From 9afd7fb6207f53d5c6618e817ebd588d1855db77 Mon Sep 17 00:00:00 2001 From: John Peterson Date: Mon, 16 Feb 2009 07:17:34 +0000 Subject: [PATCH] Rerecording: Wind back the frame counter in the status bar when a save state is loaded. Issues: The frame updates do currently not occur as often as the input updates. The input updates occur more frequently, perhaps closer to 60 times per real seconds. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2274 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/Timer.cpp | 8 +++- Source/Core/Common/Src/Timer.h | 3 +- Source/Core/Core/Src/Core.h | 1 + Source/Core/Core/Src/CoreRerecording.cpp | 39 ++++++++++++++++++- Source/Core/DolphinWX/Src/Frame.cpp | 8 ++++ Source/PluginSpecs/PluginSpecs.h | 3 +- .../Plugin_PadSimple/Src/PadSimple.cpp | 13 +++++++ 7 files changed, 71 insertions(+), 4 deletions(-) diff --git a/Source/Core/Common/Src/Timer.cpp b/Source/Core/Common/Src/Timer.cpp index 28eb67c33b..7eebddced3 100644 --- a/Source/Core/Common/Src/Timer.cpp +++ b/Source/Core/Common/Src/Timer.cpp @@ -91,11 +91,17 @@ s64 Timer::GetTimeDifference(void) return(timeGetTime() - m_LastTime); } -// Add the time difference since the last Update() to the starting time +/* Add the time difference since the last Update() to the starting time. This is used to compensate + for a paused game. */ void Timer::AddTimeDifference() { m_StartTime += GetTimeDifference(); } +// Wind back the starting time to a custom time +void Timer::WindBackStartingTime(u64 WindBack) +{ + m_StartTime += WindBack; +} // Get the time elapsed since the Start() u64 Timer::GetTimeElapsed(void) diff --git a/Source/Core/Common/Src/Timer.h b/Source/Core/Common/Src/Timer.h index 946191d79d..a31ce4d7bc 100644 --- a/Source/Core/Common/Src/Timer.h +++ b/Source/Core/Common/Src/Timer.h @@ -36,6 +36,7 @@ class Timer // The time difference is always returned in milliseconds, regardless of alternative internal representation s64 GetTimeDifference(void); void AddTimeDifference(); + void WindBackStartingTime(u64 WindBack); static void IncreaseResolution(); static void RestoreResolution(); @@ -44,7 +45,7 @@ class Timer static std::string GetTimeFormatted(); std::string GetTimeElapsedFormatted(); - u64 Timer::GetTimeElapsed(); + u64 GetTimeElapsed(); public: diff --git a/Source/Core/Core/Src/Core.h b/Source/Core/Core/Src/Core.h index aedd8ffc8a..24d0e3a22c 100644 --- a/Source/Core/Core/Src/Core.h +++ b/Source/Core/Core/Src/Core.h @@ -80,6 +80,7 @@ namespace Core void WriteStatus(); void RerecordingStart(); void RerecordingStop(); + void WindBack(int Counter); extern int g_FrameCounter; extern bool g_FrameStep; #endif diff --git a/Source/Core/Core/Src/CoreRerecording.cpp b/Source/Core/Core/Src/CoreRerecording.cpp index e5d720afab..75894d8569 100644 --- a/Source/Core/Core/Src/CoreRerecording.cpp +++ b/Source/Core/Core/Src/CoreRerecording.cpp @@ -125,6 +125,40 @@ void RerecordingStop() // Update status bar WriteStatus(); } + +/* Wind back the frame counter when a save state is loaded. Currently we don't know what that means in + time so we just guess that the time is proportional the the number of frames + + Todo: There are many assumptions here: We probably want to replace the time here by the actual time + that we save together with the save state or the input recording for example. And have it adjusted + for full speed playback (whether it's 30 fps or 60 fps or some other speed that the game is natively + capped at). Also the input interrupts do not occur as often as the frame renderings, they occur more + often. So we may want to move the input recording to fram updates, or perhaps sync the input interrupts + to frame updates. + */ +void WindBack(int Counter) +{ + /* Counter should be smaller than g_FrameCounter, however it currently updates faster than the + frames so currently it may not be the same. Therefore I use the abs() function. */ + int AbsoluteFrameDifference = abs(g_FrameCounter - Counter); + float FractionalFrameDifference = (float) AbsoluteFrameDifference / (float) g_FrameCounter; + + // Update the frame counter + g_FrameCounter = Counter; + + // Approximate a time to wind back the clock to + // Get the current time + u64 CurrentTimeMs = ReRecTimer.GetTimeElapsed(); + // Save the current time in seconds in a new double + double CurrentTimeSeconds = (double) (CurrentTimeMs / 1000); + // Reduce it by the same proportion as the counter was wound back + CurrentTimeSeconds = CurrentTimeSeconds * FractionalFrameDifference; + // Update the clock + ReRecTimer.WindBackStartingTime((u64)CurrentTimeSeconds * 1000); + + // Logging + Console::Print("WindBack: %i %u\n", Counter, (u64)CurrentTimeSeconds); +} //////////////////////////////////////// @@ -134,7 +168,7 @@ void RerecordingStop() void FrameAdvance() { // Update status bar - WriteStatus(); + WriteStatus(); // If a game is not started, return if(Core::GetState() == Core::CORE_UNINITIALIZED) return; @@ -191,6 +225,9 @@ void FrameUpdate() { // Write to the status bar WriteStatus(); + /* I don't think the frequent update has any material speed inpact at all, but should it + have you can controls the update speed by changing the "% 10" in this line */ + //if (g_FrameCounter % 10 == 0) WriteStatus(); // Pause if frame stepping is on if(g_FrameStep) diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index cafe8065f7..0b55650fdb 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -193,6 +193,14 @@ int abc = 0; //Console::Print("WIIMOTE_RECONNECT\n"); Core::ReconnectWiimote(); return 0; + + #ifdef RERECORDING + case INPUT_FRAME_COUNTER: + // Wind back the frame counter after a save state has been loaded + Core::WindBack((int)lParam); + return 0; + #endif + } break; //default: diff --git a/Source/PluginSpecs/PluginSpecs.h b/Source/PluginSpecs/PluginSpecs.h index 252f3cd2ca..40e1ba8218 100644 --- a/Source/PluginSpecs/PluginSpecs.h +++ b/Source/PluginSpecs/PluginSpecs.h @@ -27,7 +27,8 @@ enum PLUGIN_COMM OPENGL_WM_USER_STOP = 10, OPENGL_WM_USER_CREATE, NJOY_RELOAD, // Reload nJoy if DirectInput has failed - WIIMOTE_RECONNECT // Reconnect the Wiimote if it has disconnected + WIIMOTE_RECONNECT, // Reconnect the Wiimote if it has disconnected + INPUT_FRAME_COUNTER // Wind back the frame counter for rerecording }; /////////////////////////////// diff --git a/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp b/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp index 934a74baa2..d70b0a550b 100644 --- a/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp +++ b/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp @@ -686,9 +686,22 @@ void Initialize(void *init) void DoState(unsigned char **ptr, int mode) { +#ifdef RERECORDING // Load or save the counter PointerWrap p(ptr, mode); p.Do(count); + + //Console::Print("count: %i\n", count); + + // Update the frame counter for the sake of the status bar + if (mode == PointerWrap::MODE_READ) + { + #ifdef _WIN32 + // This only works when rendering to the main window, I think + PostMessage(GetParent(g_PADInitialize.hWnd), WM_USER, INPUT_FRAME_COUNTER, count); + #endif + } +#endif } void Shutdown()