all repos — mgba @ 25b4faef1262e37154e955d21d0fe1befa07e23b

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#include <mgba/internal/debugger/cli-debugger.h>
  9
 10#ifdef USE_GDB_STUB
 11#include <mgba/internal/debugger/gdb-stub.h>
 12#endif
 13#ifdef USE_EDITLINE
 14#include "feature/editline/cli-el-backend.h"
 15#endif
 16#ifdef ENABLE_SCRIPTING
 17#include <mgba/core/scripting.h>
 18
 19#ifdef ENABLE_PYTHON
 20#include "platform/python/engine.h"
 21#endif
 22#endif
 23
 24#include <mgba/core/core.h>
 25#include <mgba/core/config.h>
 26#include <mgba/core/input.h>
 27#include <mgba/core/thread.h>
 28#include <mgba/internal/gba/input.h>
 29
 30#include <mgba/feature/commandline.h>
 31#include <mgba-util/vfs.h>
 32
 33#include <SDL.h>
 34
 35#include <errno.h>
 36#include <signal.h>
 37
 38#define PORT "sdl"
 39
 40static bool mSDLInit(struct mSDLRenderer* renderer);
 41static void mSDLDeinit(struct mSDLRenderer* renderer);
 42
 43static int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args);
 44
 45int main(int argc, char** argv) {
 46	struct mSDLRenderer renderer = {0};
 47
 48	struct mCoreOptions opts = {
 49		.useBios = true,
 50		.rewindEnable = true,
 51		.rewindBufferCapacity = 600,
 52		.rewindSave = true,
 53		.audioBuffers = 1024,
 54		.videoSync = false,
 55		.audioSync = true,
 56		.volume = 0x100,
 57	};
 58
 59	struct mArguments args;
 60	struct mGraphicsOpts graphicsOpts;
 61
 62	struct mSubParser subparser;
 63
 64	initParserForGraphics(&subparser, &graphicsOpts);
 65	bool parsed = parseArguments(&args, argc, argv, &subparser);
 66	if (!args.fname && !args.showVersion) {
 67		parsed = false;
 68	}
 69	if (!parsed || args.showHelp) {
 70		usage(argv[0], subparser.usage);
 71		freeArguments(&args);
 72		return !parsed;
 73	}
 74	if (args.showVersion) {
 75		version(argv[0]);
 76		freeArguments(&args);
 77		return 0;
 78	}
 79
 80	renderer.core = mCoreFind(args.fname);
 81	if (!renderer.core) {
 82		printf("Could not run game. Are you sure the file exists and is a compatible game?\n");
 83		freeArguments(&args);
 84		return 1;
 85	}
 86	renderer.core->desiredVideoDimensions(renderer.core, &renderer.width, &renderer.height);
 87#ifdef BUILD_GL
 88	mSDLGLCreate(&renderer);
 89#elif defined(BUILD_GLES2) || defined(USE_EPOXY)
 90	mSDLGLES2Create(&renderer);
 91#else
 92	mSDLSWCreate(&renderer);
 93#endif
 94
 95	renderer.ratio = graphicsOpts.multiplier;
 96	if (renderer.ratio == 0) {
 97		renderer.ratio = 1;
 98	}
 99	opts.width = renderer.width * renderer.ratio;
100	opts.height = renderer.height * renderer.ratio;
101
102	if (!renderer.core->init(renderer.core)) {
103		freeArguments(&args);
104		return 1;
105	}
106
107	mInputMapInit(&renderer.core->inputMap, &GBAInputInfo);
108	mCoreInitConfig(renderer.core, PORT);
109	applyArguments(&args, &subparser, &renderer.core->config);
110
111	mCoreConfigLoadDefaults(&renderer.core->config, &opts);
112	mCoreLoadConfig(renderer.core);
113
114	renderer.viewportWidth = renderer.core->opts.width;
115	renderer.viewportHeight = renderer.core->opts.height;
116#if SDL_VERSION_ATLEAST(2, 0, 0)
117	renderer.player.fullscreen = renderer.core->opts.fullscreen;
118	renderer.player.windowUpdated = 0;
119#else
120	renderer.fullscreen = renderer.core->opts.fullscreen;
121#endif
122
123	renderer.lockAspectRatio = renderer.core->opts.lockAspectRatio;
124	renderer.lockIntegerScaling = renderer.core->opts.lockIntegerScaling;
125	renderer.filter = renderer.core->opts.resampleVideo;
126
127	if (!mSDLInit(&renderer)) {
128		freeArguments(&args);
129		renderer.core->deinit(renderer.core);
130		return 1;
131	}
132
133	renderer.player.bindings = &renderer.core->inputMap;
134	mSDLInitBindingsGBA(&renderer.core->inputMap);
135	mSDLInitEvents(&renderer.events);
136	mSDLEventsLoadConfig(&renderer.events, mCoreConfigGetInput(&renderer.core->config));
137	mSDLAttachPlayer(&renderer.events, &renderer.player);
138	mSDLPlayerLoadConfig(&renderer.player, mCoreConfigGetInput(&renderer.core->config));
139
140#if SDL_VERSION_ATLEAST(2, 0, 0)
141	renderer.core->setPeripheral(renderer.core, mPERIPH_RUMBLE, &renderer.player.rumble.d);
142#endif
143
144	int ret;
145
146	// TODO: Use opts and config
147	ret = mSDLRun(&renderer, &args);
148	mSDLDetachPlayer(&renderer.events, &renderer.player);
149	mInputMapDeinit(&renderer.core->inputMap);
150
151	mSDLDeinit(&renderer);
152
153	freeArguments(&args);
154	mCoreConfigFreeOpts(&opts);
155	mCoreConfigDeinit(&renderer.core->config);
156	renderer.core->deinit(renderer.core);
157
158	return ret;
159}
160
161int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
162	struct mCoreThread thread = {
163		.core = renderer->core
164	};
165	if (!mCoreLoadFile(renderer->core, args->fname)) {
166		return 1;
167	}
168	mCoreAutoloadSave(renderer->core);
169#ifdef ENABLE_SCRIPTING
170	struct mScriptBridge* bridge = mScriptBridgeCreate();
171#ifdef ENABLE_PYTHON
172	mPythonSetup(bridge);
173#endif
174#endif
175
176#ifdef USE_DEBUGGERS
177	struct mDebugger* debugger = mDebuggerCreate(args->debuggerType, renderer->core);
178	if (debugger) {
179#ifdef USE_EDITLINE
180		if (args->debuggerType == DEBUGGER_CLI) {
181			struct CLIDebugger* cliDebugger = (struct CLIDebugger*) debugger;
182			CLIDebuggerAttachBackend(cliDebugger, CLIDebuggerEditLineBackendCreate());
183		}
184#endif
185		mDebuggerAttach(debugger, renderer->core);
186		mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL);
187	}
188#ifdef ENABLE_SCRIPTING
189	mScriptBridgeSetDebugger(bridge, debugger);
190#endif
191#endif
192
193	if (args->patch) {
194		struct VFile* patch = VFileOpen(args->patch, O_RDONLY);
195		if (patch) {
196			renderer->core->loadPatch(renderer->core, patch);
197		}
198	} else {
199		mCoreAutoloadPatch(renderer->core);
200	}
201
202	renderer->audio.samples = renderer->core->opts.audioBuffers;
203	renderer->audio.sampleRate = 44100;
204
205	bool didFail = !mCoreThreadStart(&thread);
206	if (!didFail) {
207#if SDL_VERSION_ATLEAST(2, 0, 0)
208		mSDLSetScreensaverSuspendable(&renderer->events, renderer->core->opts.suspendScreensaver);
209		mSDLSuspendScreensaver(&renderer->events);
210#endif
211		if (mSDLInitAudio(&renderer->audio, &thread)) {
212			renderer->runloop(renderer, &thread);
213			mSDLPauseAudio(&renderer->audio);
214			if (mCoreThreadHasCrashed(&thread)) {
215				didFail = true;
216				printf("The game crashed!\n");
217			}
218		} else {
219			didFail = true;
220			printf("Could not initialize audio.\n");
221		}
222#if SDL_VERSION_ATLEAST(2, 0, 0)
223		mSDLResumeScreensaver(&renderer->events);
224		mSDLSetScreensaverSuspendable(&renderer->events, false);
225#endif
226
227		mCoreThreadJoin(&thread);
228	} else {
229		printf("Could not run game. Are you sure the file exists and is a compatible game?\n");
230	}
231	renderer->core->unloadROM(renderer->core);
232
233#ifdef ENABLE_SCRIPTING
234	mScriptBridgeDestroy(bridge);
235#endif
236
237	return didFail;
238}
239
240static bool mSDLInit(struct mSDLRenderer* renderer) {
241	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
242		printf("Could not initialize video: %s\n", SDL_GetError());
243		return false;
244	}
245
246	return renderer->init(renderer);
247}
248
249static void mSDLDeinit(struct mSDLRenderer* renderer) {
250	mSDLDeinitEvents(&renderer->events);
251	mSDLDeinitAudio(&renderer->audio);
252#if SDL_VERSION_ATLEAST(2, 0, 0)
253	SDL_DestroyWindow(renderer->window);
254#endif
255
256	renderer->deinit(renderer);
257
258	SDL_Quit();
259}