diff --git a/win32/CD3DCG.cpp b/win32/CD3DCG.cpp
index f15de2d1..1d51dc24 100644
--- a/win32/CD3DCG.cpp
+++ b/win32/CD3DCG.cpp
@@ -683,6 +683,8 @@ void CD3DCG::setShaderVars(int pass)
setProgramUniform(pass,"IN.texture_size",&textureSize);
setProgramUniform(pass,"IN.output_size",&outputSize);
setProgramUniform(pass,"IN.frame_count",&frameCnt);
+ float frameDirection = GUI.rewinding?-1.0f:1.0f;
+ setProgramUniform(pass,"IN.frame_direction",&frameDirection);
/* ORIG parameter
*/
diff --git a/win32/CGLCG.cpp b/win32/CGLCG.cpp
index 7f0032a8..0d75a999 100644
--- a/win32/CGLCG.cpp
+++ b/win32/CGLCG.cpp
@@ -667,6 +667,7 @@ void CGLCG::setShaderVars(int pass)
setProgram2fv(pass,"IN.texture_size",textureSize);
setProgram2fv(pass,"IN.output_size",outputSize);
setProgram1f(pass,"IN.frame_count",(float)frameCnt);
+ setProgram1f(pass,"IN.frame_direction",GUI.rewinding?-1.0f:1.0f);
/* ORIG parameter
*/
diff --git a/win32/InputCustom.cpp b/win32/InputCustom.cpp
index d86813ad..39f2cc0c 100644
--- a/win32/InputCustom.cpp
+++ b/win32/InputCustom.cpp
@@ -688,6 +688,8 @@ int GetNumHotKeysAssignedTo (WORD Key, int modifiers)
if(MATCHES_KEY(TurboDown)) count++;
if(MATCHES_KEY(ResetGame)) count++;
if(MATCHES_KEY(ToggleCheats)) count++;
+ if(MATCHES_KEY(QuitS9X)) count++;
+ if(MATCHES_KEY(Rewind)) count++;
#undef MATCHES_KEY
}
diff --git a/win32/StateManager.cpp b/win32/StateManager.cpp
new file mode 100644
index 00000000..dcef99f8
--- /dev/null
+++ b/win32/StateManager.cpp
@@ -0,0 +1,191 @@
+#include "statemanager.h"
+#include "snapshot.h"
+
+/* Snapshot Manager Class that records snapshot data for rewinding
+ mostly based on SSNES's rewind code by Themaister
+*/
+
+static inline size_t nearest_pow2_size(size_t v)
+{
+ size_t orig = v;
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+#if SIZE_MAX >= 0xffff
+ v |= v >> 8;
+#endif
+#if SIZE_MAX >= 0xffffffff
+ v |= v >> 16;
+#endif
+#if SIZE_MAX >= 0xffffffffffffffff
+ v |= v >> 32;
+#endif
+ v++;
+
+ size_t next = v;
+ size_t prev = v >> 1;
+
+ if ((next - orig) < (orig - prev))
+ return next;
+ else
+ return prev;
+}
+
+void StateManager::deallocate() {
+ if(buffer) {
+ delete [] buffer;
+ buffer = NULL;
+ }
+ if(tmp_state) {
+ delete [] tmp_state;
+ tmp_state = NULL;
+ }
+ if(in_state) {
+ delete [] in_state;
+ in_state = NULL;
+ }
+}
+
+StateManager::StateManager()
+{
+ buffer = NULL;
+ tmp_state = NULL;
+ in_state = NULL;
+ init_done = false;
+}
+
+StateManager::~StateManager() {
+ deallocate();
+}
+
+bool StateManager::init(size_t buffer_size) {
+
+ init_done = false;
+
+ deallocate();
+
+ real_state_size = S9xFreezeSize();
+ state_size = real_state_size / sizeof(uint32_t); // Works in multiple of 4.
+
+ // We need 4-byte aligned state_size to avoid having to enforce this with unneeded memcpy's!
+ if(real_state_size % sizeof(uint32_t)) state_size ++;
+
+ if (buffer_size <= real_state_size) // Need a sufficient buffer size.
+ return false;
+
+ top_ptr = 1;
+
+
+ buf_size = nearest_pow2_size(buffer_size) / sizeof(uint64_t); // Works in multiple of 8.
+ buf_size_mask = buf_size - 1;
+
+ if (!(buffer = new uint64_t[buf_size]))
+ return false;
+ if (!(tmp_state = new uint32_t[state_size]))
+ return false;
+ if (!(in_state = new uint32_t[state_size]))
+ return false;
+
+ memset(tmp_state,0,state_size * sizeof(uint32_t));
+ memset(in_state,0,state_size * sizeof(uint32_t));
+
+ init_done = true;
+
+ return true;
+}
+
+int StateManager::pop()
+{
+ if(!init_done)
+ return 0;
+
+ if (first_pop)
+ {
+ first_pop = false;
+ return S9xUnfreezeGameMem((uint8 *)tmp_state,real_state_size);
+ }
+
+ top_ptr = (top_ptr - 1) & buf_size_mask;
+
+ if (top_ptr == bottom_ptr) // Our stack is completely empty... :v
+ {
+ top_ptr = (top_ptr + 1) & buf_size_mask;
+ return 0;
+ }
+
+ while (buffer[top_ptr])
+ {
+ // Apply the xor patch.
+ uint32_t addr = buffer[top_ptr] >> 32;
+ uint32_t xor_ = buffer[top_ptr] & 0xFFFFFFFFU;
+ tmp_state[addr] ^= xor_;
+
+ top_ptr = (top_ptr - 1) & buf_size_mask;
+ }
+
+ if (top_ptr == bottom_ptr) // Our stack is completely empty... :v
+ {
+ top_ptr = (top_ptr + 1) & buf_size_mask;
+ }
+
+ return S9xUnfreezeGameMem((uint8 *)tmp_state,real_state_size);
+}
+
+void StateManager::reassign_bottom()
+{
+ bottom_ptr = (top_ptr + 1) & buf_size_mask;
+ while (buffer[bottom_ptr]) // Skip ahead until we find the first 0 (boundary for state delta).
+ bottom_ptr = (bottom_ptr + 1) & buf_size_mask;
+}
+
+void StateManager::generate_delta(const void *data)
+{
+ bool crossed = false;
+ const uint32_t *old_state = tmp_state;
+ const uint32_t *new_state = (const uint32_t*)data;
+
+ buffer[top_ptr++] = 0; // For each separate delta, we have a 0 value sentinel in between.
+ top_ptr &= buf_size_mask;
+
+ // Check if top_ptr and bottom_ptr crossed each other, which means we need to delete old cruft.
+ if (top_ptr == bottom_ptr)
+ crossed = true;
+
+ for (uint64_t i = 0; i < state_size; i++)
+ {
+ uint64_t xor_ = old_state[i] ^ new_state[i];
+
+ // If the data differs (xor != 0), we push that xor on the stack with index and xor.
+ // This can be reversed by reapplying the xor.
+ // This, if states don't really differ much, we'll save lots of space :)
+ // Hopefully this will work really well with save states.
+ if (xor_)
+ {
+ buffer[top_ptr] = (i << 32) | xor_;
+ top_ptr = (top_ptr + 1) & buf_size_mask;
+
+ if (top_ptr == bottom_ptr)
+ crossed = true;
+ }
+ }
+
+ if (crossed)
+ reassign_bottom();
+}
+
+bool StateManager::push()
+{
+ if(!init_done)
+ return false;
+ if(!S9xFreezeGameMem((uint8 *)in_state,real_state_size))
+ return false;
+ generate_delta(in_state);
+ uint32 *tmp = tmp_state;
+ tmp_state = in_state;
+ in_state = tmp;
+
+ first_pop = true;
+
+ return true;
+}
diff --git a/win32/StateManager.h b/win32/StateManager.h
new file mode 100644
index 00000000..65aabb30
--- /dev/null
+++ b/win32/StateManager.h
@@ -0,0 +1,35 @@
+#ifndef STATEMANAGER_H
+#define STATEMANAGER_H
+
+/* Snapshot Manager Class that records snapshot data for rewinding
+ mostly based on SSNES's rewind code by Themaister
+*/
+
+#include "snes9x.h"
+
+class StateManager {
+private:
+ uint64_t *buffer;
+ size_t buf_size;
+ size_t buf_size_mask;
+ uint32_t *tmp_state;
+ uint32_t *in_state;
+ size_t top_ptr;
+ size_t bottom_ptr;
+ size_t state_size;
+ size_t real_state_size;
+ bool init_done;
+ bool first_pop;
+
+ void reassign_bottom();
+ void generate_delta(const void *data);
+ void deallocate();
+public:
+ StateManager();
+ ~StateManager();
+ bool init(size_t buffer_size);
+ int pop();
+ bool push();
+};
+
+#endif // STATEMANAGER_H
diff --git a/win32/rsrc/resource.h b/win32/rsrc/resource.h
index 90d5997f..04b0b0e8 100644
--- a/win32/rsrc/resource.h
+++ b/win32/rsrc/resource.h
@@ -81,7 +81,11 @@
#define IDC_HEADER 1067
#define IDC_HIRESAVI 1067
#define IDC_ROMLIST 1068
+#define IDC_REWIND_BUFFER 1068
#define IDC_MEM_TYPE 1069
+#define IDC_REWIND_BUFFER_SPIN 1069
+#define IDC_REWIND_GRANULARITY 1070
+#define IDC_REWIND_GRANULARITY_SPIN 1071
#define IDC_HOSTNAME 1086
#define IDC_PORTNUMBER 1087
#define IDC_CLEARHISTORY 1088
@@ -226,12 +230,17 @@
#define IDC_LABEL_UP4 1183
#define IDC_PORTNUMBLOCK 1184
#define IDC_LABEL_UP5 1184
+#define IDC_LABEL_RBUFFER 1184
#define IDC_CLIENTSETTINGSBLOCK 1185
#define IDC_LABEL_UP6 1185
+#define IDC_LABEL_RBUFFER_TEXT 1185
#define IDC_SERVERSETTINGSBLOCK 1186
#define IDC_LABEL_UP7 1186
+#define IDC_LABEL_RGRANU 1186
#define IDC_LABEL_PORTNUM 1187
#define IDC_LABEL_UP8 1187
+#define IDC_LABEL_RBUFFER_TEXT2 1187
+#define IDC_LABEL_GRANU_TEXT 1187
#define IDC_LABEL_PAUSEINTERVAL 1188
#define IDC_LABEL_UP9 1188
#define IDC_LABEL_PAUSEINTERVAL_TEXT 1189
@@ -485,7 +494,7 @@
#define ID_WINDOW_SIZE_3X 40171
#define ID_WINDOW_SIZE_4X 40172
#define ID_DEBUG_APU_TRACE 40173
-#define ID_EMULATION_BACKGROUNDINPUT 40174
+#define ID_EMULATION_BACKGROUNDINPUT 40174
// Next default values for new objects
//
diff --git a/win32/rsrc/snes9x.rc b/win32/rsrc/snes9x.rc
index e5e1b992..2aa4637f 100644
--- a/win32/rsrc/snes9x.rc
+++ b/win32/rsrc/snes9x.rc
@@ -96,10 +96,10 @@ CAPTION "APP - About Dialog"
FONT 8, "MS Sans Serif", 0, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,90,160,50,14
- EDITTEXT IDC_DISCLAIMER,7,7,218,148,ES_MULTILINE | ES_NOHIDESEL | WS_VSCROLL | ES_READONLY,WS_EX_STATICEDGE
+ EDITTEXT IDC_DISCLAIMER,7,7,218,148,ES_MULTILINE | ES_NOHIDESEL | ES_READONLY | WS_VSCROLL,WS_EX_STATICEDGE
END
-IDD_EMU_SETTINGS DIALOGEX 0, 0, 319, 154
+IDD_EMU_SETTINGS DIALOGEX 0, 0, 319, 184
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
CAPTION "APP - Emulator Settings"
FONT 8, "MS Sans Serif", 0, 0, 0x0
@@ -112,9 +112,17 @@ BEGIN
CONTROL "Spin3",IDC_SPIN_MAX_SKIP,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,298,70,11,13
EDITTEXT IDC_TURBO_SKIP,91,85,49,14,ES_AUTOHSCROLL | ES_NUMBER
CONTROL "Spin4",IDC_SPIN_TURBO_SKIP,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,296,94,11,13
- CONTROL "Toggled Turbo Mode",IDC_TOGGLE_TURBO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,103,123,12
- DEFPUSHBUTTON "&OK",IDOK,215,136,46,14
- PUSHBUTTON "&Cancel",IDCANCEL,266,135,46,14
+ EDITTEXT IDC_REWIND_BUFFER,91,102,49,14,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_REWIND_BUFFER_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,294,114,11,13
+ EDITTEXT IDC_REWIND_GRANULARITY,91,120,49,14,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_REWIND_GRANULARITY_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,293,131,11,13
+ CONTROL "Toggled Turbo Mode",IDC_TOGGLE_TURBO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,136,123,12
+ CONTROL "Pause When Inactive",IDC_INACTIVE_PAUSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,147,100,12
+ CONTROL "Custom ROM Open Dialog",IDC_CUSTOMROMOPEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,158,117,12
+ CONTROL "Hi-Res AVI Recording",IDC_HIRESAVI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,169,117,12
+ DEFPUSHBUTTON "&OK",IDOK,215,168,46,14
+ PUSHBUTTON "&Cancel",IDCANCEL,266,168,46,14
+ COMBOBOX IDC_DIRCOMBO,7,29,44,30,CBS_DROPDOWNLIST | WS_TABSTOP
RTEXT "Directory",IDC_LABEL_FREEZE,53,28,32,14,SS_CENTERIMAGE
RTEXT "Auto-Save S-RAM",IDC_LABEL_ASRAM,21,47,64,14,SS_CENTERIMAGE
RTEXT "Skip at most",IDC_LABEL_SMAX,40,66,45,14,SS_CENTERIMAGE
@@ -122,13 +130,13 @@ BEGIN
LTEXT "seconds after last change (0 disables auto-save)",IDC_LABEL_ASRAM_TEXT,146,47,161,14,SS_CENTERIMAGE
LTEXT "frames in auto-frame rate mode",IDC_LABEL_SMAX_TEXT,146,66,138,14,SS_CENTERIMAGE
LTEXT "frames in Turbo mode",IDC_LABEL_STURBO_TEXT,146,85,92,14,SS_CENTERIMAGE
- CONTROL "Pause When Inactive",IDC_INACTIVE_PAUSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,114,100,12
LTEXT "Config file",IDC_STATIC,54,11,34,11
EDITTEXT IDC_CONFIG_NAME_BOX,91,9,49,14,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER
LTEXT "all of Snes9x's settings are stored in this file",IDC_STATIC,147,11,160,11
- COMBOBOX IDC_DIRCOMBO,7,29,44,30,CBS_DROPDOWNLIST | WS_TABSTOP
- CONTROL "Custom ROM Open Dialog",IDC_CUSTOMROMOPEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,125,117,12
- CONTROL "Hi-Res AVI Recording",IDC_HIRESAVI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,136,117,12
+ RTEXT "Rewind Buffer",IDC_LABEL_RBUFFER,31,102,51,14,SS_CENTERIMAGE
+ LTEXT "MB (set to 0 to disable rewind support)",IDC_LABEL_RBUFFER_TEXT,145,102,131,14,SS_CENTERIMAGE
+ RTEXT "Rewind Granularity",IDC_LABEL_RGRANU,18,120,64,14,SS_CENTERIMAGE
+ LTEXT "frames",IDC_LABEL_GRANU_TEXT,145,120,131,14,SS_CENTERIMAGE
END
IDD_OPEN_ROM DIALOGEX 0, 0, 430, 223
@@ -580,7 +588,7 @@ BEGIN
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 312
- BOTTOMMARGIN, 147
+ BOTTOMMARGIN, 177
END
IDD_OPEN_ROM, DIALOG
@@ -842,8 +850,8 @@ BEGIN
MENUITEM "&Input Configuration...\tAlt+F7", 40022
MENUITEM "&Customize Hotkeys...\tAlt+F9", ID_OPTIONS_KEYCUSTOM
MENUITEM SEPARATOR
- MENUITEM "Enable Background Input", ID_EMULATION_BACKGROUNDINPUT
- MENUITEM SEPARATOR
+ MENUITEM "Enable Background Input", ID_EMULATION_BACKGROUNDINPUT
+ MENUITEM SEPARATOR
MENUITEM "Use SNES Joypad(s)", IDM_SNES_JOYPAD
MENUITEM "Use SNES Mouse", IDM_MOUSE_TOGGLE
MENUITEM "Use Super Scope", IDM_SCOPE_TOGGLE
diff --git a/win32/snes9xw.vcproj b/win32/snes9xw.vcproj
index 27ea8e7c..3437de14 100644
--- a/win32/snes9xw.vcproj
+++ b/win32/snes9xw.vcproj
@@ -3022,6 +3022,14 @@
RelativePath=".\render.h"
>
+
+
+
+
diff --git a/win32/wconfig.cpp b/win32/wconfig.cpp
index bafa2130..896922dd 100644
--- a/win32/wconfig.cpp
+++ b/win32/wconfig.cpp
@@ -798,6 +798,7 @@ void WinPostLoad(ConfigFile& conf)
for(i=0;i<8;i++) Joypad[i+8].Enabled = Joypad[i].Enabled;
if(GUI.MaxRecentGames < 1) GUI.MaxRecentGames = 1;
if(GUI.MaxRecentGames > MAX_RECENT_GAMES_LIST_SIZE) GUI.MaxRecentGames = MAX_RECENT_GAMES_LIST_SIZE;
+ if(GUI.rewindGranularity==0) GUI.rewindGranularity = 1;
bool gap = false;
for(i=0;i
#if (((defined(_MSC_VER) && _MSC_VER >= 1300)) || defined(__MINGW32__))
@@ -563,6 +564,7 @@ struct SCustomKeys CustomKeys = {
{'R',CUSTKEY_CTRL_MASK|CUSTKEY_SHIFT_MASK}, // Reset Game
{0,0}, // Toggle Cheats
{0,0},
+ {'R',0}, // Rewind
};
@@ -610,7 +612,7 @@ struct OpenMovieParams
-
+StateManager stateMan;
std::vector dm;
/*****************************************************************************/
@@ -1231,6 +1233,13 @@ int HandleKeyMessage(WPARAM wParam, LPARAM lParam)
{
PostMessage(GUI.hWnd,WM_CLOSE,(WPARAM)NULL,(LPARAM)(NULL));
}
+ if(wParam == CustomKeys.Rewind.key
+ && modifiers == CustomKeys.Rewind.modifiers)
+ {
+ if(!GUI.rewinding)
+ S9xMessage (S9X_INFO, 0, GUI.rewindBufferSize?WINPROC_REWINDING_TEXT:WINPROC_REWINDING_DISABLED);
+ GUI.rewinding = true;
+ }
//if(wParam == CustomKeys.BGLHack.key
//&& modifiers == CustomKeys.BGLHack.modifiers)
//{
@@ -1479,6 +1488,12 @@ LRESULT CALLBACK WinProc(
{
GUI.superscope_pause = 0;
}
+ if(wParam == CustomKeys.Rewind.key
+ && modifiers == CustomKeys.Rewind.modifiers)
+ {
+ GUI.rewinding = false;
+ }
+
}
break;
@@ -3242,6 +3257,7 @@ int WINAPI WinMain(
InitRenderFilters();
GUI.ControlForced = 0xff;
+ GUI.rewinding = false;
S9xSetRecentGames ();
@@ -3426,6 +3442,19 @@ int WINAPI WinMain(
S9xClearSamples();
}
+ if(GUI.rewindBufferSize
+#ifdef NETPLAY_SUPPORT
+ &&!Settings.NetPlay
+#endif
+ ) {
+ if(GUI.rewinding) {
+ GUI.rewinding = stateMan.pop();
+ } else {
+ if(IPPU.TotalEmulatedFrames % GUI.rewindGranularity == 0)
+ stateMan.push();
+ }
+ }
+
S9xMainLoop();
GUI.FrameCount++;
}
@@ -3887,6 +3916,8 @@ static bool LoadROM(const TCHAR *filename) {
else
S9xNPServerQueueSendingLoadROMRequest (Memory.ROMName);
#endif
+ if(GUI.rewindBufferSize)
+ stateMan.init(GUI.rewindBufferSize * 1024 * 1024);
}
if(GUI.ControllerOption == SNES_SUPERSCOPE)
@@ -4909,6 +4940,10 @@ INT_PTR CALLBACK DlgEmulatorProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPar
SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP,UDM_SETPOS,0, Settings.AutoMaxSkipFrames);
SendDlgItemMessage(hDlg, IDC_SPIN_TURBO_SKIP, UDM_SETRANGE, 0, MAKELPARAM((short)600, (short)0));
SendDlgItemMessage(hDlg, IDC_SPIN_TURBO_SKIP,UDM_SETPOS,0, Settings.TurboSkipFrames);
+ SendDlgItemMessage(hDlg, IDC_REWIND_BUFFER_SPIN, UDM_SETRANGE, 0, MAKELPARAM((short)4000, (short)0));
+ SendDlgItemMessage(hDlg, IDC_REWIND_BUFFER_SPIN,UDM_SETPOS,0, GUI.rewindBufferSize);
+ SendDlgItemMessage(hDlg, IDC_REWIND_GRANULARITY_SPIN, UDM_SETRANGE, 0, MAKELPARAM((short)300, (short)1));
+ SendDlgItemMessage(hDlg, IDC_REWIND_GRANULARITY_SPIN,UDM_SETPOS,0, GUI.rewindGranularity);
CheckDlgButton(hDlg,IDC_TOGGLE_TURBO,GUI.TurboModeToggle ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hDlg,IDC_INACTIVE_PAUSE,GUI.InactivePause ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hDlg,IDC_CUSTOMROMOPEN,GUI.CustomRomOpen ? BST_CHECKED : BST_UNCHECKED);
@@ -5001,6 +5036,13 @@ INT_PTR CALLBACK DlgEmulatorProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPar
Settings.TurboSkipFrames=SendDlgItemMessage(hDlg, IDC_SPIN_TURBO_SKIP, UDM_GETPOS, 0,0);
Settings.AutoMaxSkipFrames=SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP, UDM_GETPOS, 0,0);
Settings.AutoSaveDelay=SendDlgItemMessage(hDlg, IDC_SRAM_SPIN, UDM_GETPOS, 0,0);
+ GUI.rewindGranularity = SendDlgItemMessage(hDlg, IDC_REWIND_GRANULARITY_SPIN, UDM_GETPOS, 0,0);
+ if(GUI.rewindGranularity==0) GUI.rewindGranularity = 1;
+ unsigned int newRewindBufSize = SendDlgItemMessage(hDlg, IDC_REWIND_BUFFER_SPIN, UDM_GETPOS, 0,0);
+ if(GUI.rewindBufferSize != newRewindBufSize) {
+ GUI.rewindBufferSize = newRewindBufSize;
+ stateMan.init(GUI.rewindBufferSize * 1024 * 1024);
+ }
WinSaveConfigFile();
}
@@ -7749,7 +7791,7 @@ static void set_hotkeyinfo(HWND hDlg)
SendDlgItemMessage(hDlg,IDC_HOTKEY6,WM_USER+44,CustomKeys.ClippingWindows.key,CustomKeys.ClippingWindows.modifiers);
SendDlgItemMessage(hDlg,IDC_HOTKEY7,WM_USER+44,CustomKeys.Transparency.key,CustomKeys.Transparency.modifiers);
SendDlgItemMessage(hDlg,IDC_HOTKEY8,WM_USER+44,0,0);
- SendDlgItemMessage(hDlg,IDC_HOTKEY9,WM_USER+44,0,0);
+ SendDlgItemMessage(hDlg,IDC_HOTKEY9,WM_USER+44,CustomKeys.Rewind.key,CustomKeys.Rewind.modifiers);
SendDlgItemMessage(hDlg,IDC_HOTKEY10,WM_USER+44,CustomKeys.SwitchControllers.key,CustomKeys.SwitchControllers.modifiers);
SendDlgItemMessage(hDlg,IDC_HOTKEY11,WM_USER+44,CustomKeys.JoypadSwap.key,CustomKeys.JoypadSwap.modifiers);
SendDlgItemMessage(hDlg,IDC_HOTKEY12,WM_USER+44,CustomKeys.ResetGame.key,CustomKeys.ResetGame.modifiers);
@@ -7814,7 +7856,7 @@ static void set_hotkeyinfo(HWND hDlg)
SetDlgItemText(hDlg,IDC_LABEL_HK6,HOTKEYS_LABEL_2_6);
SetDlgItemText(hDlg,IDC_LABEL_HK7,HOTKEYS_LABEL_2_7);
SetDlgItemText(hDlg,IDC_LABEL_HK8,INPUTCONFIG_LABEL_UNUSED);
- SetDlgItemText(hDlg,IDC_LABEL_HK9,INPUTCONFIG_LABEL_UNUSED);
+ SetDlgItemText(hDlg,IDC_LABEL_HK9,HOTKEYS_LABEL_2_9);
SetDlgItemText(hDlg,IDC_LABEL_HK10,HOTKEYS_LABEL_2_10);
SetDlgItemText(hDlg,IDC_LABEL_HK11,HOTKEYS_LABEL_2_11);
SetDlgItemText(hDlg,IDC_LABEL_HK12,HOTKEYS_LABEL_2_12);
@@ -7979,7 +8021,7 @@ switch(msg)
break;
case IDC_HOTKEY9:
if(index == 0) CustomKeys.ScopePause.key = wParam, CustomKeys.ScopePause.modifiers = modifiers;
- //if(index == 1) CustomKeys.GLCube.key = wParam, CustomKeys.GLCube.modifiers = modifiers;
+ if(index == 1) CustomKeys.Rewind.key = wParam, CustomKeys.Rewind.modifiers = modifiers;
if(index == 2) CustomKeys.TurboLeft.key = wParam, CustomKeys.TurboLeft.modifiers = modifiers;
if(index == 3) CustomKeys.SelectSave[8].key = wParam, CustomKeys.SelectSave[8].modifiers = modifiers;
break;
diff --git a/win32/wsnes9x.h b/win32/wsnes9x.h
index 4a49f3cd..fb7c81c6 100644
--- a/win32/wsnes9x.h
+++ b/win32/wsnes9x.h
@@ -339,7 +339,7 @@ struct sGUI {
HACCEL Accelerators;
bool NeedDepthConvert;
bool DepthConverted;
- bool BGR;
+
bool TurboModeToggle;
bool InactivePause;
bool CustomRomOpen;
@@ -395,6 +395,11 @@ struct sGUI {
long FrameCount;
long LastFrameCount;
unsigned long IdleCount;
+
+ // rewinding
+ bool rewinding;
+ unsigned int rewindBufferSize;
+ unsigned int rewindGranularity;
};
//TURBO masks
@@ -467,6 +472,7 @@ struct SCustomKeys {
SCustomKey ResetGame;
SCustomKey ToggleCheats;
SCustomKey QuitS9X;
+ SCustomKey Rewind;
};
struct SJoypad {