aboutsummaryrefslogtreecommitdiff
path: root/src/libui_sdl/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libui_sdl/main.cpp')
-rw-r--r--src/libui_sdl/main.cpp401
1 files changed, 381 insertions, 20 deletions
diff --git a/src/libui_sdl/main.cpp b/src/libui_sdl/main.cpp
index 6736fbc..4c19314 100644
--- a/src/libui_sdl/main.cpp
+++ b/src/libui_sdl/main.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2017 StapleButter
+ Copyright 2016-2019 StapleButter
This file is part of melonDS.
@@ -24,6 +24,7 @@
#include "libui/ui.h"
#include "../types.h"
+#include "../melon_fopen.h"
#include "../version.h"
#include "../Config.h"
@@ -37,6 +38,13 @@
#include "../Platform.h"
#include "../Config.h"
+#include "../Savestate.h"
+
+
+// savestate slot mapping
+// 1-8: regular slots (quick access)
+// '9': load/save arbitrary file
+const int kSavestateNum[9] = {1, 2, 3, 4, 5, 6, 7, 8, 0};
const int kScreenRot[4] = {0, 1, 2, 3};
const int kScreenGap[6] = {0, 1, 8, 64, 90, 128};
@@ -47,10 +55,19 @@ const int kScreenSizing[4] = {0, 1, 2, 3};
uiWindow* MainWindow;
uiArea* MainDrawArea;
+uiMenuItem* MenuItem_SaveState;
+uiMenuItem* MenuItem_LoadState;
+uiMenuItem* MenuItem_UndoStateLoad;
+
+uiMenuItem* MenuItem_SaveStateSlot[9];
+uiMenuItem* MenuItem_LoadStateSlot[9];
+
uiMenuItem* MenuItem_Pause;
uiMenuItem* MenuItem_Reset;
uiMenuItem* MenuItem_Stop;
+uiMenuItem* MenuItem_SavestateSRAMReloc;
+
uiMenuItem* MenuItem_ScreenRot[4];
uiMenuItem* MenuItem_ScreenGap[6];
uiMenuItem* MenuItem_ScreenLayout[3];
@@ -62,6 +79,10 @@ volatile int EmuStatus;
bool RunningSomething;
char ROMPath[1024];
+char SRAMPath[1024];
+char PrevSRAMPath[1024]; // for savestate 'undo load'
+
+bool SavestateLoaded;
bool ScreenDrawInited = false;
uiDrawBitmap* ScreenBitmap = NULL;
@@ -88,6 +109,20 @@ SDL_Joystick* Joystick;
void SetupScreenRects(int width, int height);
+void SaveState(int slot);
+void LoadState(int slot);
+void UndoStateLoad();
+void GetSavestateName(int slot, char* filename, int len);
+
+
+
+bool FileExists(char* name)
+{
+ FILE* f = melon_fopen(name, "rb");
+ if (!f) return false;
+ fclose(f);
+ return true;
+}
void UpdateWindowTitle(void* data)
@@ -301,8 +336,6 @@ int EmuThreadFunc(void* burp)
}
else
{
- EmuStatus = 2;
-
// paused
nframes = 0;
lasttick = SDL_GetTicks();
@@ -310,7 +343,13 @@ int EmuThreadFunc(void* burp)
lastmeasuretick = lasttick;
fpslimitcount = 0;
- uiAreaQueueRedrawAll(MainDrawArea);
+ if (EmuRunning == 2)
+ {
+ uiAreaQueueRedrawAll(MainDrawArea);
+ }
+
+ EmuStatus = EmuRunning;
+
SDL_Delay(100);
}
}
@@ -438,6 +477,10 @@ int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
if (evt->Modifiers == 0x2) // ALT+key
return 0;
+ // d0rp
+ if (!RunningSomething)
+ return 1;
+
if (evt->Up)
{
for (int i = 0; i < 12; i++)
@@ -446,6 +489,22 @@ int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
}
else if (!evt->Repeat)
{
+ // F keys: 3B-44, 57-58 | SHIFT: mod. 0x4
+ if (evt->Scancode >= 0x3B && evt->Scancode <= 0x42) // F1-F8, quick savestate
+ {
+ if (evt->Modifiers == 0x4) SaveState(1 + (evt->Scancode - 0x3B));
+ else if (evt->Modifiers == 0x0) LoadState(1 + (evt->Scancode - 0x3B));
+ }
+ else if (evt->Scancode == 0x43) // F9, savestate from/to file
+ {
+ if (evt->Modifiers == 0x4) SaveState(0);
+ else if (evt->Modifiers == 0x0) LoadState(0);
+ }
+ else if (evt->Scancode == 0x58) // F12, undo savestate
+ {
+ if (evt->Modifiers == 0x0) UndoStateLoad();
+ }
+
for (int i = 0; i < 12; i++)
if (evt->Scancode == Config::KeyMapping[i])
KeyInputMask &= ~(1<<i);
@@ -710,6 +769,25 @@ void Run()
EmuRunning = 1;
RunningSomething = true;
+ uiMenuItemEnable(MenuItem_SaveState);
+ uiMenuItemEnable(MenuItem_LoadState);
+
+ if (SavestateLoaded)
+ uiMenuItemEnable(MenuItem_UndoStateLoad);
+ else
+ uiMenuItemDisable(MenuItem_UndoStateLoad);
+
+ for (int i = 0; i < 8; i++)
+ {
+ char ssfile[1024];
+ GetSavestateName(i+1, ssfile, 1024);
+ if (FileExists(ssfile)) uiMenuItemEnable(MenuItem_LoadStateSlot[i]);
+ else uiMenuItemDisable(MenuItem_LoadStateSlot[i]);
+ }
+
+ for (int i = 0; i < 9; i++) uiMenuItemEnable(MenuItem_SaveStateSlot[i]);
+ uiMenuItemEnable(MenuItem_LoadStateSlot[8]);
+
uiMenuItemEnable(MenuItem_Pause);
uiMenuItemEnable(MenuItem_Reset);
uiMenuItemEnable(MenuItem_Stop);
@@ -723,6 +801,12 @@ void Stop(bool internal)
while (EmuStatus != 2);
RunningSomething = false;
+ uiWindowSetTitle(MainWindow, "melonDS " MELONDS_VERSION);
+
+ for (int i = 0; i < 9; i++) uiMenuItemDisable(MenuItem_SaveStateSlot[i]);
+ for (int i = 0; i < 9; i++) uiMenuItemDisable(MenuItem_LoadStateSlot[i]);
+ uiMenuItemDisable(MenuItem_UndoStateLoad);
+
uiMenuItemDisable(MenuItem_Pause);
uiMenuItemDisable(MenuItem_Reset);
uiMenuItemDisable(MenuItem_Stop);
@@ -732,16 +816,33 @@ void Stop(bool internal)
uiAreaQueueRedrawAll(MainDrawArea);
}
+void SetupSRAMPath()
+{
+ strncpy(SRAMPath, ROMPath, 1023);
+ SRAMPath[1023] = '\0';
+ strncpy(SRAMPath + strlen(ROMPath) - 3, "sav", 3);
+}
+
void TryLoadROM(char* file, int prevstatus)
{
char oldpath[1024];
+ char oldsram[1024];
strncpy(oldpath, ROMPath, 1024);
+ strncpy(oldsram, SRAMPath, 1024);
strncpy(ROMPath, file, 1023);
ROMPath[1023] = '\0';
- if (NDS::LoadROM(ROMPath, Config::DirectBoot))
+ SetupSRAMPath();
+
+ if (NDS::LoadROM(ROMPath, SRAMPath, Config::DirectBoot))
+ {
+ SavestateLoaded = false;
+ uiMenuItemDisable(MenuItem_UndoStateLoad);
+
+ strncpy(PrevSRAMPath, SRAMPath, 1024); // safety
Run();
+ }
else
{
uiMsgBoxError(MainWindow,
@@ -749,18 +850,194 @@ void TryLoadROM(char* file, int prevstatus)
"Make sure the file can be accessed and isn't opened in another application.");
strncpy(ROMPath, oldpath, 1024);
+ strncpy(SRAMPath, oldsram, 1024);
EmuRunning = prevstatus;
}
}
-int OnCloseWindow(uiWindow* window, void* blarg)
+// SAVESTATE TODO
+// * configurable paths. not everyone wants their ROM directory to be polluted, I guess.
+
+void GetSavestateName(int slot, char* filename, int len)
{
- if (RunningSomething)
+ int pos;
+
+ if (ROMPath[0] == '\0') // running firmware, no ROM
{
- EmuRunning = 2;
- while (EmuStatus != 2);
+ strcpy(filename, "firmware");
+ pos = 8;
+ }
+ else
+ {
+ int l = strlen(ROMPath);
+ pos = l;
+ while (ROMPath[pos] != '.' && pos > 0) pos--;
+ if (pos == 0) pos = l;
+
+ // avoid buffer overflow. shoddy
+ if (pos > len-5) pos = len-5;
+
+ strncpy(&filename[0], ROMPath, pos);
+ }
+ strcpy(&filename[pos], ".ml");
+ filename[pos+3] = '0'+slot;
+ filename[pos+4] = '\0';
+}
+
+void LoadState(int slot)
+{
+ int prevstatus = EmuRunning;
+ EmuRunning = 2;
+ while (EmuStatus != 2);
+
+ char filename[1024];
+
+ if (slot > 0)
+ {
+ GetSavestateName(slot, filename, 1024);
+ }
+ else
+ {
+ char* file = uiOpenFile(MainWindow, "melonDS savestate (any)|*.ml1;*.ml2;*.ml3;*.ml4;*.ml5;*.ml6;*.ml7;*.ml8;*.mln", NULL);
+ if (!file)
+ {
+ EmuRunning = prevstatus;
+ return;
+ }
+
+ strncpy(filename, file, 1023);
+ filename[1023] = '\0';
+ uiFreeText(file);
+ }
+
+ if (!FileExists(filename))
+ {
+ EmuRunning = prevstatus;
+ return;
+ }
+
+ // backup
+ Savestate* backup = new Savestate("timewarp.mln", true);
+ NDS::DoSavestate(backup);
+ delete backup;
+
+ Savestate* state = new Savestate(filename, false);
+ if (state->Error)
+ {
+ delete state;
+
+ uiMsgBoxError(MainWindow, "Error", "Could not load savestate file.");
+
+ // current state might be crapoed, so restore from sane backup
+ state = new Savestate("timewarp.mln", false);
+ }
+
+ NDS::DoSavestate(state);
+ delete state;
+
+ if (Config::SavestateRelocSRAM && ROMPath[0]!='\0')
+ {
+ strncpy(PrevSRAMPath, SRAMPath, 1024);
+
+ strncpy(SRAMPath, filename, 1019);
+ int len = strlen(SRAMPath);
+ strcpy(&SRAMPath[len], ".sav");
+ SRAMPath[len+4] = '\0';
+
+ NDS::RelocateSave(SRAMPath, false);
+ }
+
+ SavestateLoaded = true;
+ uiMenuItemEnable(MenuItem_UndoStateLoad);
+
+ EmuRunning = prevstatus;
+}
+
+void SaveState(int slot)
+{
+ int prevstatus = EmuRunning;
+ EmuRunning = 2;
+ while (EmuStatus != 2);
+
+ char filename[1024];
+
+ if (slot > 0)
+ {
+ GetSavestateName(slot, filename, 1024);
}
+ else
+ {
+ char* file = uiSaveFile(MainWindow, "melonDS savestate (*.mln)|*.mln", NULL);
+ if (!file)
+ {
+ EmuRunning = prevstatus;
+ return;
+ }
+
+ strncpy(filename, file, 1023);
+ filename[1023] = '\0';
+ uiFreeText(file);
+ }
+
+ Savestate* state = new Savestate(filename, true);
+ if (state->Error)
+ {
+ delete state;
+
+ uiMsgBoxError(MainWindow, "Error", "Could not save state.");
+ }
+ else
+ {
+ NDS::DoSavestate(state);
+ delete state;
+
+ if (slot > 0)
+ uiMenuItemEnable(MenuItem_LoadStateSlot[slot-1]);
+
+ if (Config::SavestateRelocSRAM && ROMPath[0]!='\0')
+ {
+ strncpy(SRAMPath, filename, 1019);
+ int len = strlen(SRAMPath);
+ strcpy(&SRAMPath[len], ".sav");
+ SRAMPath[len+4] = '\0';
+
+ NDS::RelocateSave(SRAMPath, true);
+ }
+ }
+
+ EmuRunning = prevstatus;
+}
+
+void UndoStateLoad()
+{
+ if (!SavestateLoaded) return;
+
+ int prevstatus = EmuRunning;
+ EmuRunning = 2;
+ while (EmuStatus != 2);
+
+ // pray that this works
+ // what do we do if it doesn't???
+ // but it should work.
+ Savestate* backup = new Savestate("timewarp.mln", false);
+ NDS::DoSavestate(backup);
+ delete backup;
+
+ if (ROMPath[0]!='\0')
+ {
+ strncpy(SRAMPath, PrevSRAMPath, 1024);
+ NDS::RelocateSave(SRAMPath, false);
+ }
+
+ EmuRunning = prevstatus;
+}
+
+
+int OnCloseWindow(uiWindow* window, void* blarg)
+{
+ EmuRunning = 3;
+ while (EmuStatus != 3);
uiQuit();
return 1;
@@ -795,6 +1072,9 @@ void OnLoseFocus(uiWindow* window, void* blarg)
void OnCloseByMenu(uiMenuItem* item, uiWindow* window, void* blarg)
{
+ EmuRunning = 3;
+ while (EmuStatus != 3);
+
uiControlDestroy(uiControl(window));
uiQuit();
}
@@ -816,6 +1096,23 @@ void OnOpenFile(uiMenuItem* item, uiWindow* window, void* blarg)
uiFreeText(file);
}
+void OnSaveState(uiMenuItem* item, uiWindow* window, void* param)
+{
+ int slot = *(int*)param;
+ SaveState(slot);
+}
+
+void OnLoadState(uiMenuItem* item, uiWindow* window, void* param)
+{
+ int slot = *(int*)param;
+ LoadState(slot);
+}
+
+void OnUndoStateLoad(uiMenuItem* item, uiWindow* window, void* param)
+{
+ UndoStateLoad();
+}
+
void OnRun(uiMenuItem* item, uiWindow* window, void* blarg)
{
if (!RunningSomething)
@@ -852,10 +1149,16 @@ void OnReset(uiMenuItem* item, uiWindow* window, void* blarg)
EmuRunning = 2;
while (EmuStatus != 2);
+ SavestateLoaded = false;
+ uiMenuItemDisable(MenuItem_UndoStateLoad);
+
if (ROMPath[0] == '\0')
NDS::LoadBIOS();
else
- NDS::LoadROM(ROMPath, Config::DirectBoot);
+ {
+ SetupSRAMPath();
+ NDS::LoadROM(ROMPath, SRAMPath, Config::DirectBoot);
+ }
Run();
}
@@ -878,6 +1181,12 @@ void OnOpenInputConfig(uiMenuItem* item, uiWindow* window, void* blarg)
}
+void OnSetSavestateSRAMReloc(uiMenuItem* item, uiWindow* window, void* param)
+{
+ Config::SavestateRelocSRAM = uiMenuItemChecked(item) ? 1:0;
+}
+
+
void EnsureProperMinSize()
{
bool isHori = (ScreenRotation == 1 || ScreenRotation == 3);
@@ -1005,15 +1314,6 @@ void ApplyNewSettings()
}
-bool _fileexists(char* name)
-{
- FILE* f = fopen(name, "rb");
- if (!f) return false;
- fclose(f);
- return true;
-}
-
-
int main(int argc, char** argv)
{
srand(time(NULL));
@@ -1072,6 +1372,48 @@ int main(int argc, char** argv)
menuitem = uiMenuAppendItem(menu, "Open ROM...");
uiMenuItemOnClicked(menuitem, OnOpenFile, NULL);
uiMenuAppendSeparator(menu);
+ {
+ uiMenu* submenu = uiNewMenu("Save state");
+
+ for (int i = 0; i < 9; i++)
+ {
+ char name[32];
+ if (i < 8)
+ sprintf(name, "%d\tShift+F%d", kSavestateNum[i], kSavestateNum[i]);
+ else
+ strcpy(name, "File...\tShift+F9");
+
+ uiMenuItem* ssitem = uiMenuAppendItem(submenu, name);
+ uiMenuItemOnClicked(ssitem, OnSaveState, (void*)&kSavestateNum[i]);
+
+ MenuItem_SaveStateSlot[i] = ssitem;
+ }
+
+ MenuItem_SaveState = uiMenuAppendSubmenu(menu, submenu);
+ }
+ {
+ uiMenu* submenu = uiNewMenu("Load state");
+
+ for (int i = 0; i < 9; i++)
+ {
+ char name[32];
+ if (i < 8)
+ sprintf(name, "%d\tF%d", kSavestateNum[i], kSavestateNum[i]);
+ else
+ strcpy(name, "File...\tF9");
+
+ uiMenuItem* ssitem = uiMenuAppendItem(submenu, name);
+ uiMenuItemOnClicked(ssitem, OnLoadState, (void*)&kSavestateNum[i]);
+
+ MenuItem_LoadStateSlot[i] = ssitem;
+ }
+
+ MenuItem_LoadState = uiMenuAppendSubmenu(menu, submenu);
+ }
+ menuitem = uiMenuAppendItem(menu, "Undo state load\tF12");
+ uiMenuItemOnClicked(menuitem, OnUndoStateLoad, NULL);
+ MenuItem_UndoStateLoad = menuitem;
+ uiMenuAppendSeparator(menu);
menuitem = uiMenuAppendItem(menu, "Quit");
uiMenuItemOnClicked(menuitem, OnCloseByMenu, NULL);
@@ -1096,6 +1438,15 @@ int main(int argc, char** argv)
uiMenuItemOnClicked(menuitem, OnOpenInputConfig, NULL);
uiMenuAppendSeparator(menu);
{
+ uiMenu* submenu = uiNewMenu("Savestate settings");
+
+ MenuItem_SavestateSRAMReloc = uiMenuAppendCheckItem(submenu, "Separate savefiles");
+ uiMenuItemOnClicked(MenuItem_SavestateSRAMReloc, OnSetSavestateSRAMReloc, NULL);
+
+ uiMenuAppendSubmenu(menu, submenu);
+ }
+ uiMenuAppendSeparator(menu);
+ {
uiMenu* submenu = uiNewMenu("Screen rotation");
for (int i = 0; i < 4; i++)
@@ -1167,6 +1518,12 @@ int main(int argc, char** argv)
uiWindowOnGetFocus(MainWindow, OnGetFocus, NULL);
uiWindowOnLoseFocus(MainWindow, OnLoseFocus, NULL);
+ //uiMenuItemDisable(MenuItem_SaveState);
+ //uiMenuItemDisable(MenuItem_LoadState);
+ for (int i = 0; i < 9; i++) uiMenuItemDisable(MenuItem_SaveStateSlot[i]);
+ for (int i = 0; i < 9; i++) uiMenuItemDisable(MenuItem_LoadStateSlot[i]);
+ uiMenuItemDisable(MenuItem_UndoStateLoad);
+
uiMenuItemDisable(MenuItem_Pause);
uiMenuItemDisable(MenuItem_Reset);
uiMenuItemDisable(MenuItem_Stop);
@@ -1195,6 +1552,8 @@ int main(int argc, char** argv)
SANITIZE(ScreenSizing, 0, 3);
#undef SANITIZE
+ uiMenuItemSetChecked(MenuItem_SavestateSRAMReloc, Config::SavestateRelocSRAM?1:0);
+
uiMenuItemSetChecked(MenuItem_ScreenRot[ScreenRotation], 1);
uiMenuItemSetChecked(MenuItem_ScreenLayout[ScreenLayout], 1);
uiMenuItemSetChecked(MenuItem_ScreenSizing[ScreenSizing], 1);
@@ -1221,7 +1580,9 @@ int main(int argc, char** argv)
strncpy(ROMPath, file, 1023);
ROMPath[1023] = '\0';
- if (NDS::LoadROM(ROMPath, Config::DirectBoot))
+ SetupSRAMPath();
+
+ if (NDS::LoadROM(ROMPath, SRAMPath, Config::DirectBoot))
Run();
}
}