void GBAConfigMakePortable(const struct GBAConfig* config) { struct VFile* portable = 0; #ifdef _WIN32 char out[MAX_PATH]; wchar_t wpath[MAX_PATH]; wchar_t wprojectName[MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, projectName, -1, wprojectName, MAX_PATH); HMODULE hModule = GetModuleHandleW(NULL); GetModuleFileNameW(hModule, wpath, MAX_PATH); PathRemoveFileSpecW(wpath); WideCharToMultiByte(CP_UTF8, 0, wpath, -1, out, MAX_PATH, 0, 0); StringCchCatA(out, MAX_PATH, "\\portable.ini"); portable = VFileOpen(out, O_WRONLY | O_CREAT); #elif defined(PSP2) || defined(_3DS) || defined(GEKKO) // Already portable #else char out[PATH_MAX]; getcwd(out, PATH_MAX); strncat(out, PATH_SEP "portable.ini", PATH_MAX - strlen(out)); portable = VFileOpen(out, O_WRONLY | O_CREAT); #endif if (portable) { portable->close(portable); GBAConfigSave(config); } }
void GBAConfigDirectory(char* out, size_t outLength) { struct VFile* portable; #ifdef _WIN32 wchar_t wpath[MAX_PATH]; wchar_t wprojectName[MAX_PATH]; MultiByteToWideChar(CP_UTF8, 0, projectName, -1, wprojectName, MAX_PATH); HMODULE hModule = GetModuleHandleW(NULL); GetModuleFileNameW(hModule, wpath, MAX_PATH); PathRemoveFileSpecW(wpath); WideCharToMultiByte(CP_UTF8, 0, wpath, -1, out, outLength, 0, 0); StringCchCatA(out, outLength, "\\portable.ini"); portable = VFileOpen(out, O_RDONLY); if (portable) { portable->close(portable); } else { wchar_t* home; SHGetKnownFolderPath(&FOLDERID_RoamingAppData, 0, NULL, &home); StringCchPrintfW(wpath, MAX_PATH, L"%ws\\%ws", home, wprojectName); CoTaskMemFree(home); CreateDirectoryW(wpath, NULL); } WideCharToMultiByte(CP_UTF8, 0, wpath, -1, out, outLength, 0, 0); #elif defined(PSP2) UNUSED(portable); snprintf(out, outLength, "cache0:/%s", projectName); sceIoMkdir(out, 0777); #elif defined(GEKKO) UNUSED(portable); snprintf(out, outLength, "/%s", projectName); mkdir(out, 0777); #elif defined(_3DS) UNUSED(portable); snprintf(out, outLength, "/%s", projectName); FSUSER_CreateDirectory(sdmcArchive, fsMakePath(PATH_ASCII, out), 0); #else getcwd(out, outLength); strncat(out, PATH_SEP "portable.ini", outLength - strlen(out)); portable = VFileOpen(out, O_RDONLY); if (portable) { getcwd(out, outLength); portable->close(portable); return; } char* home = getenv("HOME"); snprintf(out, outLength, "%s/.config", home); mkdir(out, 0755); snprintf(out, outLength, "%s/.config/%s", home, binaryName); mkdir(out, 0755); #endif }
struct VFile* VDirOptionalOpenFile(struct VDir* dir, const char* realPath, const char* prefix, const char* suffix, int mode) { char path[PATH_MAX]; path[PATH_MAX - 1] = '\0'; struct VFile* vf; if (!dir) { if (!realPath) { return 0; } char* dotPoint = strrchr(realPath, '.'); if (dotPoint - realPath + 1 >= PATH_MAX - 1) { return 0; } if (dotPoint > strrchr(realPath, '/')) { int len = dotPoint - realPath; strncpy(path, realPath, len); path[len] = 0; strncat(path + len, suffix, PATH_MAX - len - 1); } else { snprintf(path, PATH_MAX - 1, "%s%s", realPath, suffix); } vf = VFileOpen(path, mode); } else { snprintf(path, PATH_MAX - 1, "%s%s", prefix, suffix); vf = dir->openFile(dir, path, mode); } return vf; }
struct mCore* mCoreFind(const char* path) { struct VDir* archive = VDirOpenArchive(path); struct mCore* core = NULL; if (archive) { struct VDirEntry* dirent = archive->listNext(archive); while (dirent) { struct VFile* vf = archive->openFile(archive, dirent->name(dirent), O_RDONLY); if (!vf) { dirent = archive->listNext(archive); continue; } core = mCoreFindVF(vf); vf->close(vf); if (core) { break; } dirent = archive->listNext(archive); } archive->close(archive); } else { struct VFile* vf = VFileOpen(path, O_RDONLY); if (!vf) { return NULL; } core = mCoreFindVF(vf); vf->close(vf); } if (core) { return core; } return NULL; }
bool retro_load_game(const struct retro_game_info* game) { if (game->data) { data = malloc(game->size); memcpy(data, game->data, game->size); rom = VFileFromMemory(data, game->size); } else { data = 0; rom = VFileOpen(game->path, O_RDONLY); } if (!rom) { return false; } if (!GBAIsROM(rom)) { return false; } savedata = malloc(SIZE_CART_FLASH1M); save = VFileFromMemory(savedata, SIZE_CART_FLASH1M); GBALoadROM(&gba, rom, save, game->path); GBAOverrideApplyDefaults(&gba); ARMReset(&cpu); return true; }
bool ConfigurationRead(struct Configuration* configuration, const char* path) { struct VFile* vf = VFileOpen(path, O_RDONLY); if (!vf) { return false; } bool res = ConfigurationReadVFile(configuration, vf); vf->close(vf); return res; }
bool ConfigurationWrite(const struct Configuration* configuration, const char* path) { struct VFile* vf = VFileOpen(path, O_WRONLY | O_CREAT | O_TRUNC); if (!vf) { return false; } HashTableEnumerate(&configuration->root, _keyHandler, vf); HashTableEnumerate(&configuration->sections, _sectionHandler, vf); vf->close(vf); return true; }
int main(int argc, char** argv) { struct TextCodec codec; struct VFile* vf = VFileOpen(argv[1], O_RDONLY); TextCodecLoadTBL(&codec, vf, true); vf->close(vf); vf = VFileOpen(argv[2], O_RDONLY); struct TextCodecIterator iter; TextCodecStartDecode(&codec, &iter); uint8_t lineBuffer[128]; uint8_t c; while (vf->read(vf, &c, 1) > 0) { TextCodecAdvance(&iter, c, lineBuffer, sizeof(lineBuffer)); } TextCodecFinish(&iter, lineBuffer, sizeof(lineBuffer)); TextCodecDeinit(&codec); return 0; }
struct VFile* _vdsceOpenFile(struct VDir* vd, const char* path, int mode) { struct VDirSce* vdsce = (struct VDirSce*) vd; if (!path) { return 0; } const char* dir = vdsce->path; char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + strlen(PATH_SEP) + 1)); sprintf(combined, "%s%s%s", dir, PATH_SEP, path); struct VFile* file = VFileOpen(combined, mode); free(combined); return file; }
struct VFile* _vdwOpenFile(struct VDir* vd, const char* path, int mode) { struct VDirW32* vdw = (struct VDirW32*) vd; if (!path) { return 0; } const char* dir = vdw->path; char* combined = malloc(sizeof(char) * (strlen(path) + strlen(dir) + 2)); sprintf(combined, "%s\\%s", dir, path); struct VFile* file = VFileOpen(combined, mode); free(combined); return file; }
struct mCore* mCoreFind(const char* path) { struct VDir* archive = VDirOpenArchive(path); struct mCore* (*open)(void) = NULL; if (archive) { struct VDirEntry* dirent = archive->listNext(archive); while (dirent) { struct VFile* vf = archive->openFile(archive, dirent->name(dirent), O_RDONLY); if (!vf) { dirent = archive->listNext(archive); continue; } struct mCoreFilter* filter; for (filter = &_filters[0]; filter->filter; ++filter) { if (filter->filter(vf)) { break; } } vf->close(vf); if (filter->open) { open = filter->open; break; } dirent = archive->listNext(archive); } archive->close(archive); } else { struct VFile* vf = VFileOpen(path, O_RDONLY); if (!vf) { return NULL; } struct mCoreFilter* filter; for (filter = &_filters[0]; filter->filter; ++filter) { if (filter->filter(vf)) { break; } } vf->close(vf); if (filter->open) { open = filter->open; } } if (open) { return open(); } return NULL; }
static voidpf _vfmzOpen(voidpf opaque, const char* filename, int mode) { UNUSED(opaque); int flags = 0; switch (mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) { case ZLIB_FILEFUNC_MODE_READ: flags = O_RDONLY; break; case ZLIB_FILEFUNC_MODE_WRITE: flags = O_WRONLY; break; case ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE: flags = O_RDWR; break; } if (mode & ZLIB_FILEFUNC_MODE_CREATE) { flags |= O_CREAT; } return VFileOpen(filename, flags); }
bool ConfigurationWriteSection(const struct Configuration* configuration, const char* path, const char* section) { const struct Table* currentSection = &configuration->root; struct VFile* vf = VFileOpen(path, O_WRONLY | O_CREAT | O_APPEND); if (!vf) { return false; } if (section) { currentSection = HashTableLookup(&configuration->sections, section); char line[256]; size_t len = snprintf(line, sizeof(line), "[%s]\n", section); if (len >= sizeof(line)) { len = sizeof(line) - 1; } vf->write(vf, line, len); } if (currentSection) { HashTableEnumerate(currentSection, _sectionHandler, vf); } vf->close(vf); return true; }
struct VFile* mDirectorySetOpenPath(struct mDirectorySet* dirs, const char* path, bool (*filter)(struct VFile*)) { dirs->archive = VDirOpenArchive(path); struct VFile* file; if (dirs->archive) { file = VDirFindFirst(dirs->archive, filter); if (!file) { dirs->archive->close(dirs->archive); dirs->archive = 0; } } else { file = VFileOpen(path, O_RDONLY); if (file && !filter(file)) { file->close(file); file = 0; } } if (file) { char dirname[PATH_MAX]; separatePath(path, dirname, dirs->baseName, 0); mDirectorySetAttachBase(dirs, VDirOpen(dirname)); } return file; }
bool mScriptBridgeLoadScript(struct mScriptBridge* sb, const char* name) { struct VFile* vf = VFileOpen(name, O_RDONLY); if (!vf) { return false; } struct mScriptInfo info = { .name = name, .vf = vf, .success = false }; HashTableEnumerate(&sb->engines, _seTryLoad, &info); vf->close(vf); return info.success; } bool mScriptBridgeLookupSymbol(struct mScriptBridge* sb, const char* name, int32_t* out) { struct mScriptSymbol info = { .name = name, .out = out, .success = false }; HashTableEnumerate(&sb->engines, _seLookupSymbol, &info); return info.success; }
bool retro_load_game(const struct retro_game_info* game) { struct VFile* rom; if (game->data) { data = anonymousMemoryMap(game->size); dataSize = game->size; memcpy(data, game->data, game->size); rom = VFileFromMemory(data, game->size); } else { data = 0; rom = VFileOpen(game->path, O_RDONLY); } if (!rom) { return false; } core = NULL; #ifdef M_CORE_GBA if (!core && GBAIsROM(rom)) { core = GBACoreCreate(); } #endif #ifdef M_CORE_GB if (!core && GBIsROM(rom)) { core = GBCoreCreate(); } #endif if (!core) { rom->close(rom); mappedMemoryFree(data, game->size); return false; } mCoreInitConfig(core, NULL); core->init(core); core->setAVStream(core, &stream); outputBuffer = malloc(256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); core->setVideoBuffer(core, outputBuffer, 256); core->setAudioBufferSize(core, SAMPLES); blip_set_rates(core->getAudioChannel(core, 0), core->frequency(core), 32768); blip_set_rates(core->getAudioChannel(core, 1), core->frequency(core), 32768); core->setRumble(core, &rumble); #ifdef M_CORE_GBA if (core->platform(core) == PLATFORM_GBA) { struct GBA* gba = core->board; gba->luminanceSource = &lux; const char* sysDir = 0; if (environCallback(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &sysDir)) { char biosPath[PATH_MAX]; snprintf(biosPath, sizeof(biosPath), "%s%s%s", sysDir, PATH_SEP, "gba_bios.bin"); struct VFile* bios = VFileOpen(biosPath, O_RDONLY); if (bios) { core->loadBIOS(core, bios, 0); } } GBACheatDeviceCreate(&cheats); GBACheatAttachDevice(gba, &cheats); GBACheatSetInit(&cheatSet, "libretro"); GBACheatAddSet(&cheats, &cheatSet); } #endif savedata = anonymousMemoryMap(SIZE_CART_FLASH1M); struct VFile* save = VFileFromMemory(savedata, SIZE_CART_FLASH1M); _reloadSettings(); core->loadROM(core, rom); core->loadSave(core, save); core->reset(core); return true; }
int main() { hasSound = !csndInit(); rotation.d.sample = _sampleRotation; rotation.d.readTiltX = _readTiltX; rotation.d.readTiltY = _readTiltY; rotation.d.readGyroZ = _readGyroZ; stream.postVideoFrame = 0; stream.postAudioFrame = 0; stream.postAudioBuffer = _postAudioBuffer; if (!allocateRomBuffer()) { return 1; } if (hasSound) { audioLeft = linearAlloc(AUDIO_SAMPLES * sizeof(int16_t)); audioRight = linearAlloc(AUDIO_SAMPLES * sizeof(int16_t)); } sf2d_init(); sf2d_set_clear_color(0); tex = sf2d_create_texture(256, 256, TEXFMT_RGB565, SF2D_PLACE_RAM); memset(tex->data, 0, 256 * 256 * 2); sdmcArchive = (FS_archive) { ARCH_SDMC, (FS_path) { PATH_EMPTY, 1, (const u8*)"" }, 0, 0 }; FSUSER_OpenArchive(0, &sdmcArchive); logFile = VFileOpen("/mgba.log", O_WRONLY | O_CREAT | O_TRUNC); struct GUIFont* font = GUIFontCreate(); if (!font) { goto cleanup; } struct GBAGUIRunner runner = { .params = { 320, 240, font, "/", _drawStart, _drawEnd, _pollInput, 0, 0, GUI_PARAMS_TRAIL }, .setup = _setup, .teardown = 0, .gameLoaded = _gameLoaded, .gameUnloaded = _gameUnloaded, .prepareForFrame = 0, .drawFrame = _drawFrame, .pollGameInput = _pollGameInput }; GBAGUIInit(&runner, 0); GBAGUIRunloop(&runner); GBAGUIDeinit(&runner); cleanup: linearFree(renderer.outputBuffer); if (logFile) { logFile->close(logFile); } sf2d_free_texture(tex); sf2d_fini(); if (hasSound) { linearFree(audioLeft); linearFree(audioRight); } csndExit(); return 0; }
int main(int argc, char** argv) { #ifdef _3DS UNUSED(_mPerfShutdown); gfxInitDefault(); osSetSpeedupEnable(true); consoleInit(GFX_BOTTOM, NULL); if (!allocateRomBuffer()) { return 1; } #elif defined(__SWITCH__) UNUSED(_mPerfShutdown); gfxInitDefault(); consoleInit(NULL); #else signal(SIGINT, _mPerfShutdown); #endif int didFail = 0; struct mLogger logger = { .log = _log }; mLogSetDefaultLogger(&logger); struct PerfOpts perfOpts = { false, false, false, 0, 0, 0, false }; struct mSubParser subparser = { .usage = PERF_USAGE, .parse = _parsePerfOpts, .extraOptions = PERF_OPTIONS, .opts = &perfOpts }; struct mArguments args = {}; bool parsed = parseArguments(&args, argc, argv, &subparser); if (!args.fname) { parsed = false; } if (!parsed || args.showHelp) { usage(argv[0], PERF_USAGE); didFail = !parsed; goto cleanup; } if (args.showVersion) { version(argv[0]); goto cleanup; } if (perfOpts.savestate) { _savestate = VFileOpen(perfOpts.savestate, O_RDONLY); free(perfOpts.savestate); } _outputBuffer = malloc(256 * 256 * 4); if (perfOpts.csv) { puts("game_code,frames,duration,renderer"); } if (perfOpts.server) { didFail = !_mPerfRunServer(args.fname, &args, &perfOpts); } else { didFail = !_mPerfRunCore(args.fname, &args, &perfOpts); } free(_outputBuffer); if (_savestate) { _savestate->close(_savestate); } cleanup: freeArguments(&args); #ifdef _3DS gfxExit(); acExit(); #elif defined(__SWITCH__) gfxExit(); #endif return didFail; }
bool retro_load_game(const struct retro_game_info* game) { struct VFile* rom; if (game->data) { data = anonymousMemoryMap(game->size); dataSize = game->size; memcpy(data, game->data, game->size); rom = VFileFromMemory(data, game->size); } else { data = 0; rom = VFileOpen(game->path, O_RDONLY); } if (!rom) { return false; } core = mCoreFindVF(rom); if (!core) { rom->close(rom); mappedMemoryFree(data, game->size); return false; } mCoreInitConfig(core, NULL); core->init(core); core->setAVStream(core, &stream); size_t size = 256 * 224 * BYTES_PER_PIXEL; outputBuffer = malloc(size); memset(outputBuffer, 0xFF, size); core->setVideoBuffer(core, outputBuffer, 256); core->setAudioBufferSize(core, SAMPLES); blip_set_rates(core->getAudioChannel(core, 0), core->frequency(core), 32768); blip_set_rates(core->getAudioChannel(core, 1), core->frequency(core), 32768); core->setPeripheral(core, mPERIPH_RUMBLE, &rumble); savedata = anonymousMemoryMap(SIZE_CART_FLASH1M); struct VFile* save = VFileFromMemory(savedata, SIZE_CART_FLASH1M); _reloadSettings(); core->loadROM(core, rom); core->loadSave(core, save); const char* sysDir = 0; const char* biosName = 0; char biosPath[PATH_MAX]; environCallback(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &sysDir); #ifdef M_CORE_GBA if (core->platform(core) == PLATFORM_GBA) { core->setPeripheral(core, mPERIPH_GBA_LUMINANCE, &lux); biosName = "gba_bios.bin"; } #endif #ifdef M_CORE_GB if (core->platform(core) == PLATFORM_GB) { memset(&cam, 0, sizeof(cam)); cam.height = GBCAM_HEIGHT; cam.width = GBCAM_WIDTH; cam.caps = 1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER; cam.frame_raw_framebuffer = _updateCamera; core->setPeripheral(core, mPERIPH_IMAGE_SOURCE, &imageSource); environCallback(RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE, &cam); const char* modelName = mCoreConfigGetValue(&core->config, "gb.model"); struct GB* gb = core->board; if (modelName) { gb->model = GBNameToModel(modelName); } else { GBDetectModel(gb); } switch (gb->model) { case GB_MODEL_AGB: case GB_MODEL_CGB: biosName = "gbc_bios.bin"; break; case GB_MODEL_SGB: biosName = "sgb_bios.bin"; break; case GB_MODEL_DMG: default: biosName = "gb_bios.bin"; break; } } #endif if (core->opts.useBios && sysDir && biosName) { snprintf(biosPath, sizeof(biosPath), "%s%s%s", sysDir, PATH_SEP, biosName); struct VFile* bios = VFileOpen(biosPath, O_RDONLY); if (bios) { core->loadBIOS(core, bios, 0); } } core->reset(core); _setupMaps(core); return true; }
int main(int argc, char** argv) { struct mSDLRenderer renderer = {}; struct mCoreOptions opts = { .useBios = true, .rewindEnable = true, .audioBuffers = 512, .videoSync = false, .audioSync = true, .volume = 0x100, }; struct mArguments args; struct mGraphicsOpts graphicsOpts; struct mSubParser subparser; initParserForGraphics(&subparser, &graphicsOpts); bool parsed = parseArguments(&args, argc, argv, &subparser); if (!parsed || args.showHelp) { usage(argv[0], subparser.usage); freeArguments(&args); return !parsed; } if (args.showVersion) { version(argv[0]); freeArguments(&args); return 0; } renderer.core = mCoreFind(args.fname); if (!renderer.core) { printf("Could not run game. Are you sure the file exists and is a compatible game?\n"); freeArguments(&args); return 1; } renderer.core->desiredVideoDimensions(renderer.core, &renderer.width, &renderer.height); #ifdef BUILD_GL mSDLGLCreate(&renderer); #elif defined(BUILD_GLES2) || defined(USE_EPOXY) mSDLGLES2Create(&renderer); #else mSDLSWCreate(&renderer); #endif renderer.ratio = graphicsOpts.multiplier; if (renderer.ratio == 0) { renderer.ratio = 1; } opts.width = renderer.width * renderer.ratio; opts.height = renderer.height * renderer.ratio; if (!renderer.core->init(renderer.core)) { freeArguments(&args); return 1; } mInputMapInit(&renderer.core->inputMap, &GBAInputInfo); mCoreInitConfig(renderer.core, PORT); applyArguments(&args, &subparser, &renderer.core->config); mCoreConfigLoadDefaults(&renderer.core->config, &opts); mCoreLoadConfig(renderer.core); renderer.viewportWidth = renderer.core->opts.width; renderer.viewportHeight = renderer.core->opts.height; #if SDL_VERSION_ATLEAST(2, 0, 0) renderer.player.fullscreen = renderer.core->opts.fullscreen; renderer.player.windowUpdated = 0; #else renderer.fullscreen = renderer.core->opts.fullscreen; #endif renderer.lockAspectRatio = renderer.core->opts.lockAspectRatio; renderer.filter = renderer.core->opts.resampleVideo; if (!mSDLInit(&renderer)) { freeArguments(&args); renderer.core->deinit(renderer.core); return 1; } renderer.player.bindings = &renderer.core->inputMap; mSDLInitBindingsGBA(&renderer.core->inputMap); mSDLInitEvents(&renderer.events); mSDLEventsLoadConfig(&renderer.events, mCoreConfigGetInput(&renderer.core->config)); mSDLAttachPlayer(&renderer.events, &renderer.player); mSDLPlayerLoadConfig(&renderer.player, mCoreConfigGetInput(&renderer.core->config)); int ret; // TODO: Use opts and config ret = mSDLRun(&renderer, &args); mSDLDetachPlayer(&renderer.events, &renderer.player); mInputMapDeinit(&renderer.core->inputMap); mSDLDeinit(&renderer); freeArguments(&args); mCoreConfigFreeOpts(&opts); mCoreConfigDeinit(&renderer.core->config); renderer.core->deinit(renderer.core); return ret; } int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) { struct mCoreThread thread = { .core = renderer->core }; if (!mCoreLoadFile(renderer->core, args->fname)) { return 1; } mCoreAutoloadSave(renderer->core); struct mDebugger* debugger = mDebuggerCreate(args->debuggerType, renderer->core); if (debugger) { mDebuggerAttach(debugger, renderer->core); mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL); } if (args->patch) { struct VFile* patch = VFileOpen(args->patch, O_RDONLY); if (patch) { renderer->core->loadPatch(renderer->core, patch); } } else { mCoreAutoloadPatch(renderer->core); } renderer->audio.samples = renderer->core->opts.audioBuffers; renderer->audio.sampleRate = 44100; bool didFail = !mSDLInitAudio(&renderer->audio, &thread); if (!didFail) { #if SDL_VERSION_ATLEAST(2, 0, 0) mSDLSetScreensaverSuspendable(&renderer->events, renderer->core->opts.suspendScreensaver); mSDLSuspendScreensaver(&renderer->events); #endif if (mCoreThreadStart(&thread)) { renderer->runloop(renderer, &thread); mSDLPauseAudio(&renderer->audio); mCoreThreadJoin(&thread); } else { didFail = true; printf("Could not run game. Are you sure the file exists and is a compatible game?\n"); } #if SDL_VERSION_ATLEAST(2, 0, 0) mSDLResumeScreensaver(&renderer->events); mSDLSetScreensaverSuspendable(&renderer->events, false); #endif if (mCoreThreadHasCrashed(&thread)) { didFail = true; printf("The game crashed!\n"); } } renderer->core->unloadROM(renderer->core); return didFail; } static bool mSDLInit(struct mSDLRenderer* 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 mSDLDeinit(struct mSDLRenderer* renderer) { mSDLDeinitEvents(&renderer->events); mSDLDeinitAudio(&renderer->audio); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_DestroyWindow(renderer->window); #endif renderer->deinit(renderer); SDL_Quit(); }
void retro_init(void) { enum retro_pixel_format fmt; #ifdef COLOR_16_BIT #ifdef COLOR_5_6_5 fmt = RETRO_PIXEL_FORMAT_RGB565; #else #warning This pixel format is unsupported. Please use -DCOLOR_16-BIT -DCOLOR_5_6_5 fmt = RETRO_PIXEL_FORMAT_0RGB1555; #endif #else #warning This pixel format is unsupported. Please use -DCOLOR_16-BIT -DCOLOR_5_6_5 fmt = RETRO_PIXEL_FORMAT_XRGB8888; #endif environCallback(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt); struct retro_input_descriptor inputDescriptors[] = { { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Brighten Solar Sensor" }, { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "Darken Solar Sensor" } }; environCallback(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, &inputDescriptors); // TODO: RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME when BIOS booting is supported struct retro_rumble_interface rumbleInterface; if (environCallback(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumbleInterface)) { rumbleCallback = rumbleInterface.set_rumble_state; CircleBufferInit(&rumbleHistory, RUMBLE_PWM); rumble.setRumble = _setRumble; } else { rumbleCallback = 0; } luxLevel = 0; lux.readLuminance = _readLux; lux.sample = _updateLux; _updateLux(&lux); struct retro_log_callback log; if (environCallback(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log)) { logCallback = log.log; } else { logCallback = 0; } stream.postAudioFrame = 0; stream.postAudioBuffer = _postAudioBuffer; stream.postVideoFrame = _postVideoFrame; GBACreate(&gba); ARMSetComponents(&cpu, &gba.d, 0, 0); ARMInit(&cpu); gba.logLevel = 0; // TODO: Settings gba.logHandler = GBARetroLog; gba.stream = &stream; gba.idleOptimization = IDLE_LOOP_REMOVE; // TODO: Settings if (rumbleCallback) { gba.rumble = &rumble; } gba.luminanceSource = &lux; rom = 0; const char* sysDir = 0; if (environCallback(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &sysDir)) { char biosPath[PATH_MAX]; snprintf(biosPath, sizeof(biosPath), "%s%s%s", sysDir, PATH_SEP, "gba_bios.bin"); bios = VFileOpen(biosPath, O_RDONLY); if (bios) { GBALoadBIOS(&gba, bios); } } GBAVideoSoftwareRendererCreate(&renderer); renderer.outputBuffer = malloc(256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); renderer.outputBufferStride = 256; GBAVideoAssociateRenderer(&gba.video, &renderer.d); GBAAudioResizeBuffer(&gba.audio, SAMPLES); #if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF blip_set_rates(gba.audio.left, GBA_ARM7TDMI_FREQUENCY, 32768); blip_set_rates(gba.audio.right, GBA_ARM7TDMI_FREQUENCY, 32768); #endif }