Win32: add rewind support

This commit is contained in:
OV2 2012-03-28 00:18:03 +02:00
parent f7a1a99e25
commit 486cde4391
12 changed files with 329 additions and 19 deletions

View File

@ -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
*/

View File

@ -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
*/

View File

@ -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
View 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
View 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

View File

@ -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

View File

@ -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

View File

@ -3022,6 +3022,14 @@
RelativePath=".\render.h"
>
</File>
<File
RelativePath=".\StateManager.cpp"
>
</File>
<File
RelativePath=".\StateManager.h"
>
</File>
<File
RelativePath=".\wconfig.cpp"
>

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 {