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:
parent
718aa585e2
commit
9afd7fb620
|
@ -91,11 +91,17 @@ s64 Timer::GetTimeDifference(void)
|
||||||
return(timeGetTime() - m_LastTime);
|
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()
|
void Timer::AddTimeDifference()
|
||||||
{
|
{
|
||||||
m_StartTime += GetTimeDifference();
|
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()
|
// Get the time elapsed since the Start()
|
||||||
u64 Timer::GetTimeElapsed(void)
|
u64 Timer::GetTimeElapsed(void)
|
||||||
|
|
|
@ -36,6 +36,7 @@ class Timer
|
||||||
// The time difference is always returned in milliseconds, regardless of alternative internal representation
|
// The time difference is always returned in milliseconds, regardless of alternative internal representation
|
||||||
s64 GetTimeDifference(void);
|
s64 GetTimeDifference(void);
|
||||||
void AddTimeDifference();
|
void AddTimeDifference();
|
||||||
|
void WindBackStartingTime(u64 WindBack);
|
||||||
|
|
||||||
static void IncreaseResolution();
|
static void IncreaseResolution();
|
||||||
static void RestoreResolution();
|
static void RestoreResolution();
|
||||||
|
@ -44,7 +45,7 @@ class Timer
|
||||||
|
|
||||||
static std::string GetTimeFormatted();
|
static std::string GetTimeFormatted();
|
||||||
std::string GetTimeElapsedFormatted();
|
std::string GetTimeElapsedFormatted();
|
||||||
u64 Timer::GetTimeElapsed();
|
u64 GetTimeElapsed();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,7 @@ namespace Core
|
||||||
void WriteStatus();
|
void WriteStatus();
|
||||||
void RerecordingStart();
|
void RerecordingStart();
|
||||||
void RerecordingStop();
|
void RerecordingStop();
|
||||||
|
void WindBack(int Counter);
|
||||||
extern int g_FrameCounter;
|
extern int g_FrameCounter;
|
||||||
extern bool g_FrameStep;
|
extern bool g_FrameStep;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -125,6 +125,40 @@ void RerecordingStop()
|
||||||
// Update status bar
|
// Update status bar
|
||||||
WriteStatus();
|
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()
|
void FrameAdvance()
|
||||||
{
|
{
|
||||||
// Update status bar
|
// Update status bar
|
||||||
WriteStatus();
|
WriteStatus();
|
||||||
|
|
||||||
// If a game is not started, return
|
// If a game is not started, return
|
||||||
if(Core::GetState() == Core::CORE_UNINITIALIZED) return;
|
if(Core::GetState() == Core::CORE_UNINITIALIZED) return;
|
||||||
|
@ -191,6 +225,9 @@ void FrameUpdate()
|
||||||
{
|
{
|
||||||
// Write to the status bar
|
// Write to the status bar
|
||||||
WriteStatus();
|
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
|
// Pause if frame stepping is on
|
||||||
if(g_FrameStep)
|
if(g_FrameStep)
|
||||||
|
|
|
@ -193,6 +193,14 @@ int abc = 0;
|
||||||
//Console::Print("WIIMOTE_RECONNECT\n");
|
//Console::Print("WIIMOTE_RECONNECT\n");
|
||||||
Core::ReconnectWiimote();
|
Core::ReconnectWiimote();
|
||||||
return 0;
|
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;
|
break;
|
||||||
//default:
|
//default:
|
||||||
|
|
|
@ -27,7 +27,8 @@ enum PLUGIN_COMM
|
||||||
OPENGL_WM_USER_STOP = 10,
|
OPENGL_WM_USER_STOP = 10,
|
||||||
OPENGL_WM_USER_CREATE,
|
OPENGL_WM_USER_CREATE,
|
||||||
NJOY_RELOAD, // Reload nJoy if DirectInput has failed
|
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
|
||||||
};
|
};
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -686,9 +686,22 @@ void Initialize(void *init)
|
||||||
|
|
||||||
void DoState(unsigned char **ptr, int mode)
|
void DoState(unsigned char **ptr, int mode)
|
||||||
{
|
{
|
||||||
|
#ifdef RERECORDING
|
||||||
// Load or save the counter
|
// Load or save the counter
|
||||||
PointerWrap p(ptr, mode);
|
PointerWrap p(ptr, mode);
|
||||||
p.Do(count);
|
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()
|
void Shutdown()
|
||||||
|
|
Loading…
Reference in New Issue