all repos — mgba @ 4e64b4fde474693d6175335efbc142c98e08c163

mGBA Game Boy Advance Emulator

src/platform/sdl/main.c (view raw)

  1/* Copyright (c) 2013-2015 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 "main.h"
  7
  8#ifdef USE_CLI_DEBUGGER
  9#include "debugger/cli-debugger.h"
 10#endif
 11
 12#ifdef USE_GDB_STUB
 13#include "debugger/gdb-stub.h"
 14#endif
 15
 16#ifdef M_CORE_GBA
 17#include "gba/gba.h"
 18#include "gba/context/config.h"
 19#include "gba/supervisor/thread.h"
 20#include "gba/video.h"
 21#endif
 22#ifdef M_CORE_GB
 23#include "gb/gb.h"
 24#include "gb/video.h"
 25#endif
 26#include "platform/commandline.h"
 27#include "util/configuration.h"
 28#include "util/vfs.h"
 29
 30#include <SDL.h>
 31
 32#include <errno.h>
 33#include <signal.h>
 34#include <sys/time.h>
 35
 36#define PORT "sdl"
 37
 38// TODO: Move somewhere
 39enum mPlatform {
 40	PLATFORM_NONE = -1,
 41	PLATFORM_GBA,
 42	PLATFORM_GB
 43};
 44
 45static bool mSDLInit(struct mSDLRenderer* renderer);
 46static void mSDLDeinit(struct mSDLRenderer* renderer);
 47
 48// TODO: Clean up signatures
 49#ifdef M_CORE_GBA
 50static int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct GBAOptions* opts, struct GBAConfig* config, struct GBAInputMap* inputMap);
 51#endif
 52#ifdef M_CORE_GB
 53static int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args);
 54#endif
 55
 56
 57int main(int argc, char** argv) {
 58	struct mSDLRenderer renderer;
 59
 60	struct GBAInputMap inputMap;
 61	GBAInputMapInit(&inputMap);
 62
 63	struct GBAConfig config;
 64	GBAConfigInit(&config, PORT);
 65	GBAConfigLoad(&config);
 66
 67	struct GBAOptions opts = {
 68		.width = 0,
 69		.height = 0,
 70		.useBios = true,
 71		.rewindEnable = true,
 72		.audioBuffers = 512,
 73		.videoSync = false,
 74		.audioSync = true,
 75	};
 76
 77	struct GBAArguments args;
 78	struct GraphicsOpts graphicsOpts;
 79
 80	struct SubParser subparser;
 81
 82	initParserForGraphics(&subparser, &graphicsOpts);
 83	bool parsed = parseArguments(&args, &config, argc, argv, &subparser);
 84	if (!parsed || args.showHelp) {
 85		usage(argv[0], subparser.usage);
 86		freeArguments(&args);
 87		GBAConfigFreeOpts(&opts);
 88		GBAConfigDeinit(&config);
 89		return !parsed;
 90	}
 91	if (args.showVersion) {
 92		version(argv[0]);
 93		freeArguments(&args);
 94		GBAConfigFreeOpts(&opts);
 95		GBAConfigDeinit(&config);
 96		return 0;
 97	}
 98
 99	enum mPlatform platform = PLATFORM_NONE;
100
101	if (args.fname) {
102		struct VFile* vf = VFileOpen(args.fname, O_RDONLY);
103		if (!vf) {
104			printf("Could not open game. Are you sure the file exists?\n");
105			freeArguments(&args);
106			GBAConfigFreeOpts(&opts);
107			GBAConfigDeinit(&config);
108			return 1;
109		}
110#ifdef M_CORE_GBA
111		else if (GBAIsROM(vf)) {
112			platform = PLATFORM_GBA;
113			if (!opts.width) {
114				opts.width = VIDEO_HORIZONTAL_PIXELS;
115			}
116			if (!opts.height) {
117				opts.height = VIDEO_VERTICAL_PIXELS;
118			}
119		}
120#endif
121#ifdef M_CORE_GB
122		else if (GBIsROM(vf)) {
123			platform = PLATFORM_GB;
124			if (!opts.width) {
125				opts.width = /*GB_*/VIDEO_HORIZONTAL_PIXELS;
126			}
127			if (!opts.height) {
128				opts.height = /*GB_*/VIDEO_VERTICAL_PIXELS;
129			}
130		}
131#endif
132		else {
133			printf("Could not run game. Are you sure the file exists and is a Game Boy Advance game?\n");
134			freeArguments(&args);
135			GBAConfigFreeOpts(&opts);
136			GBAConfigDeinit(&config);
137			return 1;
138		}
139	}
140
141	GBAConfigLoadDefaults(&config, &opts);
142	GBAConfigMap(&config, &opts);
143
144	renderer.viewportWidth = opts.width;
145	renderer.viewportHeight = opts.height;
146#if SDL_VERSION_ATLEAST(2, 0, 0)
147	renderer.player.fullscreen = opts.fullscreen;
148	renderer.player.windowUpdated = 0;
149#else
150	renderer.fullscreen = opts.fullscreen;
151#endif
152	renderer.ratio = graphicsOpts.multiplier;
153	if (renderer.ratio == 0) {
154		renderer.ratio = 1;
155	}
156
157	renderer.lockAspectRatio = opts.lockAspectRatio;
158	renderer.filter = opts.resampleVideo;
159
160	int ret;
161
162	switch (platform) {
163	case PLATFORM_GBA:
164		ret = mSDLRunGBA(&renderer, &args, &opts, &config, &inputMap);
165		break;
166	case PLATFORM_GB:
167		ret = mSDLRunGB(&renderer, &args);
168		break;
169	default:
170		ret = 1;
171		break;
172	}
173
174	freeArguments(&args);
175	GBAConfigFreeOpts(&opts);
176	GBAConfigDeinit(&config);
177
178	return ret;
179}
180
181#ifdef M_CORE_GBA
182int mSDLRunGBA(struct mSDLRenderer* renderer, struct GBAArguments* args, struct GBAOptions* opts, struct GBAConfig* config, struct GBAInputMap* inputMap) {
183	GBAVideoSoftwareRendererCreate(&renderer->d);
184#ifdef BUILD_GL
185	mSDLGLCreate(renderer);
186#elif defined(BUILD_GLES2) || defined(USE_EPOXY)
187	mSDLGLES2Create(renderer);
188#else
189	mSDLSWCreate(renderer);
190#endif
191
192	if (!mSDLInit(renderer)) {
193		return 1;
194	}
195
196	struct GBAThread context = {
197		.renderer = &renderer->d.d,
198		.userData = renderer
199	};
200
201	context.debugger = createDebugger(args, &context);
202
203	GBAMapOptionsToContext(opts, &context);
204	GBAMapArgumentsToContext(args, &context);
205
206	bool didFail = false;
207
208	renderer->audio.samples = context.audioBuffers;
209	renderer->audio.sampleRate = 44100;
210	if (opts->sampleRate) {
211		renderer->audio.sampleRate = opts->sampleRate;
212	}
213	if (!GBASDLInitAudio(&renderer->audio, &context)) {
214		didFail = true;
215	}
216
217	renderer->player.bindings = inputMap;
218	GBASDLInitBindings(inputMap);
219	GBASDLInitEvents(&renderer->events);
220	GBASDLEventsLoadConfig(&renderer->events, GBAConfigGetInput(config));
221	GBASDLAttachPlayer(&renderer->events, &renderer->player);
222	GBASDLPlayerLoadConfig(&renderer->player, GBAConfigGetInput(config));
223	context.overrides = GBAConfigGetOverrides(config);
224
225	if (!didFail) {
226#if SDL_VERSION_ATLEAST(2, 0, 0)
227		GBASDLSetScreensaverSuspendable(&renderer->events, opts->suspendScreensaver);
228		GBASDLSuspendScreensaver(&renderer->events);
229#endif
230		if (GBAThreadStart(&context)) {
231			renderer->runloop(renderer, &context);
232			GBAThreadJoin(&context);
233		} else {
234			didFail = true;
235			printf("Could not run game. Are you sure the file exists and is a Game Boy Advance game?\n");
236		}
237
238#if SDL_VERSION_ATLEAST(2, 0, 0)
239		GBASDLResumeScreensaver(&renderer->events);
240		GBASDLSetScreensaverSuspendable(&renderer->events, false);
241#endif
242
243		if (GBAThreadHasCrashed(&context)) {
244			didFail = true;
245			printf("The game crashed!\n");
246		}
247	}
248	free(context.debugger);
249	GBADirectorySetDeinit(&context.dirs);
250	GBASDLDetachPlayer(&renderer->events, &renderer->player);
251	GBAInputMapDeinit(inputMap);
252
253	mSDLDeinit(renderer);
254
255	return didFail;
256}
257#endif
258
259#ifdef M_CORE_GB
260int mSDLRunGB(struct mSDLRenderer* renderer, struct GBAArguments* args) {
261	GBVideoSoftwareRendererCreate(&renderer->gb);
262#ifdef BUILD_GL
263	mSDLGLCreateGB(renderer);
264#elif defined(BUILD_GLES2)
265	mSDLGLES2CreateGB(renderer);
266#else
267	mSDLSWCreateGB(renderer);
268#endif
269
270	if (!mSDLInit(renderer)) {
271		return 1;
272	}
273
274	struct LR35902Core cpu;
275	struct GB gb;
276
277	GBCreate(&gb);
278	LR35902SetComponents(&cpu, &gb.d, 0, 0);
279	LR35902Init(&cpu);
280
281	GBVideoAssociateRenderer(&gb.video, &renderer->gb.d);
282	struct VFile* vf = VFileOpen(args->fname, O_RDONLY);
283	GBLoadROM(&gb, vf, 0, args->fname);
284
285	LR35902Reset(&cpu);
286	renderer->runloop(renderer, &gb);
287	vf->close(vf);
288
289	mSDLDeinit(renderer);
290	return 0;
291}
292#endif
293
294static bool mSDLInit(struct mSDLRenderer* renderer) {
295	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
296		printf("Could not initialize video: %s\n", SDL_GetError());
297		return false;
298	}
299
300	return renderer->init(renderer);
301}
302
303static void mSDLDeinit(struct mSDLRenderer* renderer) {
304	GBASDLDeinitEvents(&renderer->events);
305	GBASDLDeinitAudio(&renderer->audio);
306#if SDL_VERSION_ATLEAST(2, 0, 0)
307	SDL_DestroyWindow(renderer->window);
308#endif
309
310	renderer->deinit(renderer);
311
312	SDL_Quit();
313}