mirror of
https://github.com/libretro/snes9x.git
synced 2024-11-24 00:39:46 +00:00
Win32: add rewind support
This commit is contained in:
parent
f7a1a99e25
commit
486cde4391
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
}
|
||||
|
191
win32/StateManager.cpp
Normal file
191
win32/StateManager.cpp
Normal file
@ -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;
|
||||
}
|
35
win32/StateManager.h
Normal file
35
win32/StateManager.h
Normal file
@ -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
|
@ -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
|
||||
//
|
||||
|
@ -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
|
||||
|
@ -3022,6 +3022,14 @@
|
||||
RelativePath=".\render.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\StateManager.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\StateManager.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\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<MAX_RECENT_GAMES_LIST_SIZE;i++) // remove gaps in recent games list
|
||||
{
|
||||
@ -905,6 +906,8 @@ void WinRegisterConfigItems()
|
||||
AddUIntC("MessageDisplayTime", Settings.InitialInfoStringTimeout, 120, "display length of messages, in frames. set to 0 to disable all message text");
|
||||
#undef CATEGORY
|
||||
#define CATEGORY "Settings\\Win"
|
||||
AddUIntC("RewindBufferSize", GUI.rewindBufferSize, 0, "rewind buffer size in MB - 0 disables rewind support");
|
||||
AddUIntC("RewindGranularity", GUI.rewindGranularity, 1, "rewind granularity - rewind takes a snapshot each x frames");
|
||||
AddBoolC("PauseWhenInactive", GUI.InactivePause, TRUE, "true to pause Snes9x when it is not the active window");
|
||||
AddBoolC("CustomRomOpenDialog", GUI.CustomRomOpen, false, "false to use standard Windows open dialog for the ROM open dialog");
|
||||
AddBoolC("AVIHiRes", GUI.AVIHiRes, false, "true to record AVI in Hi-Res scale");
|
||||
@ -1015,7 +1018,7 @@ void WinRegisterConfigItems()
|
||||
ADD(ClippingWindows); /*ADD(BGLHack);*/ ADD(Transparency); /*ADD(HDMA)*/; /*ADD(GLCube);*/
|
||||
/*ADD(InterpMode7);*/ ADD(JoypadSwap); ADD(SwitchControllers); ADD(ResetGame); ADD(ToggleCheats);
|
||||
ADD(TurboA); ADD(TurboB); ADD(TurboY); ADD(TurboX); ADD(TurboL); ADD(TurboR); ADD(TurboStart); ADD(TurboSelect); ADD(TurboUp); ADD(TurboDown); ADD(TurboLeft); ADD(TurboRight);
|
||||
ADD(QuitS9X);
|
||||
ADD(QuitS9X);ADD(Rewind);
|
||||
#undef ADD
|
||||
#undef ADDN
|
||||
#undef CATEGORY
|
||||
|
@ -272,6 +272,7 @@ Nintendo is a trade mark.")
|
||||
#define HOTKEYS_LABEL_2_5 TEXT("Sprites Layer")
|
||||
#define HOTKEYS_LABEL_2_6 TEXT("Clipping Windows")
|
||||
#define HOTKEYS_LABEL_2_7 TEXT("Transparency")
|
||||
#define HOTKEYS_LABEL_2_9 TEXT("Rewind")
|
||||
#define HOTKEYS_LABEL_2_10 TEXT("Switch Controllers")
|
||||
#define HOTKEYS_LABEL_2_11 TEXT("Joypad Swap")
|
||||
#define HOTKEYS_LABEL_2_12 TEXT("Reset Game")
|
||||
@ -444,6 +445,8 @@ Nintendo is a trade mark.")
|
||||
#define WINPROC_DISCONNECT "Disconnect from the NetPlay server first."
|
||||
#define WINPROC_NET_RESTART "Your game will be reset after the ROM has been sent due to\nyour 'Sync Using Reset Game' setting.\n\n"
|
||||
#define WINPROC_SYNC_SND "Sync sound"
|
||||
#define WINPROC_REWINDING_TEXT "Rewinding"
|
||||
#define WINPROC_REWINDING_DISABLED "Rewind is disabled"
|
||||
|
||||
//Emulator Settings
|
||||
|
||||
|
@ -213,6 +213,7 @@
|
||||
#include "../conffile.h"
|
||||
#include "AVIOutput.h"
|
||||
#include "InputCustom.h"
|
||||
#include "StateManager.h"
|
||||
#include <vector>
|
||||
|
||||
#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<dMode> 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;
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user