diff --git a/src/gba/context/context.c b/src/gba/context/context.c index 2304a0f5a..e771b0cfd 100644 --- a/src/gba/context/context.c +++ b/src/gba/context/context.c @@ -14,6 +14,7 @@ bool GBAContextInit(struct GBAContext* context, const char* port) { context->gba = anonymousMemoryMap(sizeof(struct GBA)); context->cpu = anonymousMemoryMap(sizeof(struct ARMCore)); context->rom = 0; + context->fname = 0; context->save = 0; context->renderer = 0; memset(context->components, 0, sizeof(context->components)); @@ -61,6 +62,7 @@ bool GBAContextLoadROM(struct GBAContext* context, const char* path, bool autolo return false; } + context->fname = path; if (autoloadSave) { context->save = VDirOptionalOpenFile(0, path, 0, ".sav", O_RDWR | O_CREAT); } @@ -123,7 +125,7 @@ bool GBAContextStart(struct GBAContext* context) { GBAVideoAssociateRenderer(&context->gba->video, context->renderer); } - if (!GBALoadROM(context->gba, context->rom, context->save, 0)) { + if (!GBALoadROM(context->gba, context->rom, context->save, context->fname)) { return false; } diff --git a/src/gba/context/context.h b/src/gba/context/context.h index 811f80c47..fd86dca7c 100644 --- a/src/gba/context/context.h +++ b/src/gba/context/context.h @@ -16,6 +16,7 @@ struct GBAContext { struct ARMCore* cpu; struct GBAVideoRenderer* renderer; struct VFile* rom; + const char* fname; struct VFile* save; struct VFile* bios; struct ARMComponent* components[GBA_COMPONENT_MAX]; diff --git a/src/gba/context/gui-runner.c b/src/gba/context/gui-runner.c index bc49ad9d3..5db38d9f2 100644 --- a/src/gba/context/gui-runner.c +++ b/src/gba/context/gui-runner.c @@ -5,13 +5,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gui-runner.h" +#include "gba/serialize.h" #include "util/gui/file-select.h" #include "util/gui/font.h" #include "util/gui/menu.h" +#include "util/vfs.h" enum { RUNNER_CONTINUE, - RUNNER_EXIT + RUNNER_EXIT, + RUNNER_SAVE_STATE, + RUNNER_LOAD_STATE, }; void GBAGUIInit(struct GBAGUIRunner* runner, const char* port) { @@ -36,6 +40,11 @@ void GBAGUIRunloop(struct GBAGUIRunner* runner) { }; GUIMenuItemListInit(&pauseMenu.items, 0); *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Unpause", .data = (void*) RUNNER_CONTINUE }; +#if !(defined(__POWERPC__) || defined(__PPC__)) + // PPC doesn't have working savestates yet + *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Save state", .data = (void*) RUNNER_SAVE_STATE }; + *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Load state", .data = (void*) RUNNER_LOAD_STATE }; +#endif *GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Exit game", .data = (void*) RUNNER_EXIT }; while (true) { @@ -95,29 +104,37 @@ void GBAGUIRunloop(struct GBAGUIRunner* runner) { runner->params.guiPrepare(); } GUIInvalidateKeys(&runner->params); - while (true) { - struct GUIMenuItem item; - enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &pauseMenu, &item); - if (reason == GUI_MENU_EXIT_ACCEPT) { - if (item.data == (void*) RUNNER_EXIT) { - running = false; - break; - } - if (item.data == (void*) RUNNER_CONTINUE) { - int keys = -1; - while (keys) { - GUIPollInput(&runner->params, 0, &keys); - } - break; - } - } else { - int keys = -1; - while (keys) { - GUIPollInput(&runner->params, 0, &keys); + int keys = -1; // Huge hack to avoid an extra variable! + struct GUIMenuItem item; + enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &pauseMenu, &item); + if (reason == GUI_MENU_EXIT_ACCEPT) { + struct VFile* vf; + switch ((int) item.data) { + case RUNNER_EXIT: + running = false; + keys = 0; + break; + case RUNNER_SAVE_STATE: + vf = GBAGetState(runner->context.gba, 0, 1, true); + if (vf) { + GBASaveStateNamed(runner->context.gba, vf, true); + vf->close(vf); } break; + case RUNNER_LOAD_STATE: + vf = GBAGetState(runner->context.gba, 0, 1, false); + if (vf) { + GBALoadStateNamed(runner->context.gba, vf); + vf->close(vf); + } + break; + case RUNNER_CONTINUE: + break; } } + while (keys) { + GUIPollInput(&runner->params, 0, &keys); + } if (runner->params.guiFinish) { runner->params.guiFinish(); } diff --git a/src/gba/serialize.c b/src/gba/serialize.c index 48765cbfa..8acf95f97 100644 --- a/src/gba/serialize.c +++ b/src/gba/serialize.c @@ -187,13 +187,11 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { return true; } -#ifndef _3DS struct VFile* GBAGetState(struct GBA* gba, struct VDir* dir, int slot, bool write) { char suffix[5] = { '\0' }; snprintf(suffix, sizeof(suffix), ".ss%d", slot); return VDirOptionalOpenFile(dir, gba->activeFile, "savestate", suffix, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY); } -#endif #ifdef USE_PNG static bool _savePNGState(struct GBA* gba, struct VFile* vf) { diff --git a/src/platform/3ds/ctru-heap.c b/src/platform/3ds/ctru-heap.c index 8e357faaa..3df454b1a 100644 --- a/src/platform/3ds/ctru-heap.c +++ b/src/platform/3ds/ctru-heap.c @@ -26,8 +26,8 @@ extern char* fake_heap_start; extern char* fake_heap_end; u32 __linear_heap; u32 __heapBase; -static u32 __heap_size = 0x03000000; -static u32 __linear_heap_size = 0x00800000; +static u32 __heap_size = 0x02800000; +static u32 __linear_heap_size = 0x01000000; extern void (*__system_retAddr)(void);