all repos — mgba @ 3d53f23e8d3bab561ab8a7ad3d896160e26b304c

mGBA Game Boy Advance Emulator

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, ".sav", O_CREAT | O_RDWR));
 98}
 99
100bool mCoreAutoloadPatch(struct mCore* core) {
101	return core->loadPatch(core, mDirectorySetOpenSuffix(&core->dirs, ".ups", O_RDONLY)) ||
102	       core->loadPatch(core, mDirectorySetOpenSuffix(&core->dirs, ".ips", O_RDONLY)) ||
103	       core->loadPatch(core, mDirectorySetOpenSuffix(&core->dirs, ".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 = core->saveState(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 = core->loadState(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}