int main(int argc, char** argv) { struct SDLSoftwareRenderer renderer; GBAVideoSoftwareRendererCreate(&renderer.d); struct GBAInputMap inputMap; GBAInputMapInit(&inputMap); struct GBAConfig config; GBAConfigInit(&config, PORT); GBAConfigLoad(&config); struct GBAOptions opts = { .width = VIDEO_HORIZONTAL_PIXELS, .height = VIDEO_VERTICAL_PIXELS, .useBios = true, .rewindEnable = true, .audioBuffers = 512, .videoSync = false, .audioSync = true, }; GBAConfigLoadDefaults(&config, &opts); struct GBAArguments args; struct GraphicsOpts graphicsOpts; struct SubParser subparser; initParserForGraphics(&subparser, &graphicsOpts); bool parsed = parseArguments(&args, &config, argc, argv, &subparser); if (!parsed || args.showHelp) { usage(argv[0], subparser.usage); freeArguments(&args); GBAConfigFreeOpts(&opts); GBAConfigDeinit(&config); return !parsed; } GBAConfigMap(&config, &opts); renderer.viewportWidth = opts.width; renderer.viewportHeight = opts.height; #if SDL_VERSION_ATLEAST(2, 0, 0) renderer.player.fullscreen = opts.fullscreen; renderer.player.windowUpdated = 0; #else renderer.fullscreen = opts.fullscreen; #endif renderer.ratio = graphicsOpts.multiplier; if (renderer.ratio == 0) { renderer.ratio = 1; } renderer.lockAspectRatio = opts.lockAspectRatio; renderer.filter = opts.resampleVideo; #ifdef BUILD_GL GBASDLGLCreate(&renderer); #elif defined(BUILD_GLES2) GBASDLGLES2Create(&renderer); #else GBASDLSWCreate(&renderer); #endif if (!GBASDLInit(&renderer)) { freeArguments(&args); GBAConfigFreeOpts(&opts); GBAConfigDeinit(&config); return 1; } struct GBAThread context = { .renderer = &renderer.d.d, .userData = &renderer }; context.debugger = createDebugger(&args, &context); GBAMapOptionsToContext(&opts, &context); GBAMapArgumentsToContext(&args, &context); bool didFail = false; renderer.audio.samples = context.audioBuffers; renderer.audio.sampleRate = 44100; if (opts.sampleRate) { renderer.audio.sampleRate = opts.sampleRate; } if (!GBASDLInitAudio(&renderer.audio, &context)) { didFail = true; } renderer.player.bindings = &inputMap; GBASDLInitBindings(&inputMap); GBASDLInitEvents(&renderer.events); GBASDLEventsLoadConfig(&renderer.events, GBAConfigGetInput(&config)); GBASDLAttachPlayer(&renderer.events, &renderer.player); GBASDLPlayerLoadConfig(&renderer.player, GBAConfigGetInput(&config)); context.overrides = GBAConfigGetOverrides(&config); if (!didFail) { #if SDL_VERSION_ATLEAST(2, 0, 0) GBASDLSetScreensaverSuspendable(&renderer.events, opts.suspendScreensaver); GBASDLSuspendScreensaver(&renderer.events); #endif if (GBAThreadStart(&context)) { renderer.runloop(&context, &renderer); GBAThreadJoin(&context); } else { didFail = true; printf("Could not run game. Are you sure the file exists and is a Game Boy Advance game?\n"); } #if SDL_VERSION_ATLEAST(2, 0, 0) GBASDLResumeScreensaver(&renderer.events); GBASDLSetScreensaverSuspendable(&renderer.events, false); #endif if (GBAThreadHasCrashed(&context)) { didFail = true; printf("The game crashed!\n"); } } freeArguments(&args); GBAConfigFreeOpts(&opts); GBAConfigDeinit(&config); free(context.debugger); GBASDLDetachPlayer(&renderer.events, &renderer.player); GBAInputMapDeinit(&inputMap); GBASDLDeinit(&renderer); return didFail; } static bool GBASDLInit(struct SDLSoftwareRenderer* renderer) { if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("Could not initialize video: %s\n", SDL_GetError()); return false; } return renderer->init(renderer); } static void GBASDLDeinit(struct SDLSoftwareRenderer* renderer) { GBASDLDeinitEvents(&renderer->events); GBASDLDeinitAudio(&renderer->audio); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_DestroyWindow(renderer->window); #endif renderer->deinit(renderer); SDL_Quit(); }
static void _setup(struct GBAGUIRunner* runner) { struct GBAOptions opts = { .useBios = true, .logLevel = 0, .idleOptimization = IDLE_LOOP_DETECT }; GBAConfigLoadDefaults(&runner->context.config, &opts); runner->context.gba->logHandler = GBA3DSLog; runner->context.gba->rotationSource = &rotation.d; if (hasSound) { runner->context.gba->stream = &stream; } GBAVideoSoftwareRendererCreate(&renderer); renderer.outputBuffer = linearAlloc(256 * VIDEO_VERTICAL_PIXELS * 2); renderer.outputBufferStride = 256; runner->context.renderer = &renderer.d; GBAAudioResizeBuffer(&runner->context.gba->audio, AUDIO_SAMPLES); } static void _gameLoaded(struct GBAGUIRunner* runner) { if (runner->context.gba->memory.hw.devices & HW_TILT) { HIDUSER_EnableAccelerometer(); } if (runner->context.gba->memory.hw.devices & HW_GYRO) { HIDUSER_EnableGyroscope(); } #if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF double ratio = GBAAudioCalculateRatio(1, 60, 1); blip_set_rates(runner->context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 0x8000 * ratio); blip_set_rates(runner->context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 0x8000 * ratio); #endif if (hasSound) { memset(audioLeft, 0, AUDIO_SAMPLES * sizeof(int16_t)); memset(audioRight, 0, AUDIO_SAMPLES * sizeof(int16_t)); } } static void _gameUnloaded(struct GBAGUIRunner* runner) { if (hasSound) { CSND_SetPlayState(8, 0); CSND_SetPlayState(9, 0); csndExecCmds(false); } if (runner->context.gba->memory.hw.devices & HW_TILT) { HIDUSER_DisableAccelerometer(); } if (runner->context.gba->memory.hw.devices & HW_GYRO) { HIDUSER_DisableGyroscope(); } } static void _drawFrame(struct GBAGUIRunner* runner, bool faded) { GX_SetDisplayTransfer(0, renderer.outputBuffer, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), tex->data, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), 0x000002202); GSPGPU_FlushDataCache(0, tex->data, 256 * VIDEO_VERTICAL_PIXELS * 2); #if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF if (!hasSound) { blip_clear(runner->context.gba->audio.left); blip_clear(runner->context.gba->audio.right); } #endif gspWaitForPPF(); _drawStart(); sf2d_draw_texture_scale_blend(tex, 40, 296, 1, -1, 0xFFFFFF3F | (faded ? 0 : 0xC0)); _drawEnd(); }