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
This commit is contained in:
John Peterson 2009-02-16 07:17:34 +00:00
parent 718aa585e2
commit 9afd7fb620
7 changed files with 71 additions and 4 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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