src/core/core.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "core.h"
7
8#include "core/log.h"
9#include "util/vfs.h"
10
11#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
12#include "util/png-io.h"
13
14#ifdef M_CORE_GB
15#include "gb/core.h"
16#include "gb/gb.h"
17#endif
18#ifdef M_CORE_GBA
19#include "gba/core.h"
20#include "gba/gba.h"
21#endif
22
23static struct mCoreFilter {
24 bool (*filter)(struct VFile*);
25 struct mCore* (*open)(void);
26} _filters[] = {
27#ifdef M_CORE_GBA
28 { GBAIsROM, GBACoreCreate },
29#endif
30#ifdef M_CORE_GB
31 { GBIsROM, GBCoreCreate },
32#endif
33 { 0, 0 }
34};
35
36struct mCore* mCoreFind(const char* path) {
37 struct VDir* archive = VDirOpenArchive(path);
38 struct mCore* (*open)(void) = NULL;
39 if (archive) {
40 struct VDirEntry* dirent = archive->listNext(archive);
41 while (dirent) {
42 struct VFile* vf = archive->openFile(archive, dirent->name(dirent), O_RDONLY);
43 if (!vf) {
44 dirent = archive->listNext(archive);
45 continue;
46 }
47 struct mCoreFilter* filter;
48 for (filter = &_filters[0]; filter->filter; ++filter) {
49 if (filter->filter(vf)) {
50 break;
51 }
52 }
53 vf->close(vf);
54 if (filter->open) {
55 open = filter->open;
56 break;
57 }
58 dirent = archive->listNext(archive);
59 }
60 archive->close(archive);
61 } else {
62 struct VFile* vf = VFileOpen(path, O_RDONLY);
63 if (!vf) {
64 return NULL;
65 }
66 struct mCoreFilter* filter;
67 for (filter = &_filters[0]; filter->filter; ++filter) {
68 if (filter->filter(vf)) {
69 break;
70 }
71 }
72 vf->close(vf);
73 if (filter->open) {
74 open = filter->open;
75 }
76 }
77 if (open) {
78 return open();
79 }
80 return NULL;
81}
82
83bool mCoreLoadFile(struct mCore* core, const char* path) {
84 struct VFile* rom = mDirectorySetOpenPath(&core->dirs, path, core->isROM);
85 if (!rom) {
86 return false;
87 }
88
89 bool ret = core->loadROM(core, rom);
90 if (!ret) {
91 rom->close(rom);
92 }
93 return ret;
94}
95
96bool mCoreAutoloadSave(struct mCore* core) {
97 return core->loadSave(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.save, ".sav", O_CREAT | O_RDWR));
98}
99
100bool mCoreAutoloadPatch(struct mCore* core) {
101 return core->loadPatch(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.patch, ".ups", O_RDONLY)) ||
102 core->loadPatch(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.patch, ".ips", O_RDONLY)) ||
103 core->loadPatch(core, mDirectorySetOpenSuffix(&core->dirs, core->dirs.patch, ".bps", O_RDONLY));
104}
105
106bool mCoreSaveState(struct mCore* core, int slot, int flags) {
107 struct VFile* vf = mCoreGetState(core, slot, true);
108 if (!vf) {
109 return false;
110 }
111 bool success = mCoreSaveStateNamed(core, vf, flags);
112 vf->close(vf);
113 if (success) {
114 mLOG(STATUS, INFO, "State %i saved", slot);
115 } else {
116 mLOG(STATUS, INFO, "State %i failed to save", slot);
117 }
118
119 return success;
120}
121
122bool mCoreLoadState(struct mCore* core, int slot, int flags) {
123 struct VFile* vf = mCoreGetState(core, slot, false);
124 if (!vf) {
125 return false;
126 }
127 bool success = mCoreLoadStateNamed(core, vf, flags);
128 vf->close(vf);
129 if (success) {
130 mLOG(STATUS, INFO, "State %i loaded", slot);
131 } else {
132 mLOG(STATUS, INFO, "State %i failed to loaded", slot);
133 }
134
135 return success;
136}
137
138struct VFile* mCoreGetState(struct mCore* core, int slot, bool write) {
139 char name[PATH_MAX];
140 snprintf(name, sizeof(name), "%s.ss%i", core->dirs.baseName, slot);
141 return core->dirs.state->openFile(core->dirs.state, name, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY);
142}
143
144void mCoreDeleteState(struct mCore* core, int slot) {
145 char name[PATH_MAX];
146 snprintf(name, sizeof(name), "%s.ss%i", core->dirs.baseName, slot);
147 core->dirs.state->deleteFile(core->dirs.state, name);
148}
149
150void mCoreTakeScreenshot(struct mCore* core) {
151#ifdef USE_PNG
152 size_t stride;
153 color_t* pixels = 0;
154 unsigned width, height;
155 core->desiredVideoDimensions(core, &width, &height);
156 struct VFile* vf = VDirFindNextAvailable(core->dirs.screenshot, core->dirs.baseName, "-", ".png", O_CREAT | O_TRUNC | O_WRONLY);
157 bool success = false;
158 if (vf) {
159 core->getVideoBuffer(core, &pixels, &stride);
160 png_structp png = PNGWriteOpen(vf);
161 png_infop info = PNGWriteHeader(png, width, height);
162 success = PNGWritePixels(png, width, height, stride, pixels);
163 PNGWriteClose(png, info);
164 vf->close(vf);
165 }
166 if (success) {
167 mLOG(STATUS, INFO, "Screenshot saved");
168 return;
169 }
170#else
171 UNUSED(core);
172#endif
173 mLOG(STATUS, WARN, "Failed to take screenshot");
174}
175#endif
176
177void mCoreInitConfig(struct mCore* core, const char* port) {
178 mCoreConfigInit(&core->config, port);
179}
180
181void mCoreLoadConfig(struct mCore* core) {
182#ifndef MINIMAL_CORE
183 mCoreConfigLoad(&core->config);
184#endif
185 mCoreLoadForeignConfig(core, &core->config);
186}
187
188void mCoreLoadForeignConfig(struct mCore* core, const struct mCoreConfig* config) {
189 mCoreConfigMap(config, &core->opts);
190#ifndef MINIMAL_CORE
191 mDirectorySetMapOptions(&core->dirs, &core->opts);
192#endif
193 if (core->opts.audioBuffers) {
194 core->setAudioBufferSize(core, core->opts.audioBuffers);
195 }
196 core->loadConfig(core, config);
197}