diff --git a/docs/index.html b/docs/index.html
index d7d340e30..8bb086b80 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -3107,9 +3107,12 @@
Defines the horizon of the rewind buffer. A large horizon allows
going back further in time. To reach the horizon, save states
- will be compressed. This means that more and more intermediate
+ will be compressed (*). This means that more and more intermediate
states will be removed and the interval between save states
- becomes larger the further they are back in time.
+ becomes larger the further they are back in time. The very first
+ save state will not be removed.
+ (*) Compresion only works if 'Uncompressed size' is smaller than
+ 'Buffer size'.
|
-plr.rewind.horizon -dev.rewind.horizon |
diff --git a/src/common/RewindManager.cxx b/src/common/RewindManager.cxx
index 4a2d85ab9..f2314645c 100644
--- a/src/common/RewindManager.cxx
+++ b/src/common/RewindManager.cxx
@@ -36,6 +36,8 @@ RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RewindManager::setup()
{
+ myLastContinuousAdd = false;
+
string prefix = myOSystem.settings().getBool("dev.settings") ? "dev." : "plr.";
mySize = myOSystem.settings().getInt(prefix + "rewind.size");
@@ -55,20 +57,22 @@ void RewindManager::setup()
myHorizon = HORIZON_CYCLES[i];
// calc interval growth factor
+ // this factor defines the backward horizon
const double MAX_FACTOR = 1E8;
double minFactor = 0, maxFactor = MAX_FACTOR;
+ myFactor = 1;
- while(true)
+ while(myUncompressed < mySize)
{
double interval = myInterval;
- double cycleSum = interval * myUncompressed;
+ double cycleSum = interval * (myUncompressed + 1);
// calculate nextCycles factor
myFactor = (minFactor + maxFactor) / 2;
// horizon not reachable?
if(myFactor == MAX_FACTOR)
break;
- // sum up interval cycles
- for(uInt32 i = myUncompressed; i < mySize; ++i)
+ // sum up interval cycles (first and last state are not compressed)
+ for(uInt32 i = myUncompressed + 1; i < mySize - 1; ++i)
{
interval *= myFactor;
cycleSum += interval;
@@ -119,6 +123,7 @@ bool RewindManager::addState(const string& message, bool continuous)
state.cycles = myOSystem.console().tia().cycles();
//state.count = count++;
//cerr << "add " << state.count << endl;
+ myLastContinuousAdd = continuous;
return true;
}
return false;
@@ -129,15 +134,17 @@ bool RewindManager::rewindState()
{
if(!atFirst())
{
- RewindState& lastState = myStateList.current();
-
+ if (!myLastContinuousAdd)
// Set internal current iterator to previous state (back in time),
// since we will now processed this state
- myStateList.moveToPrevious();
+ myStateList.moveToPrevious();
+ myLastContinuousAdd = false;
+
+ //RewindState& lastState = myStateList.current();
RewindState& state = myStateList.current();
Serializer& s = state.data;
- string message = getMessage(state, lastState);
+ string message = getMessage(state);
//cerr << "rewind " << state.count << endl;
s.rewind(); // rewind Serializer internal buffers
@@ -163,7 +170,7 @@ bool RewindManager::unwindState()
RewindState& state = myStateList.current();
Serializer& s = state.data;
- string message = getMessage(state, state);
+ string message = getMessage(state);
//cerr << "unwind " << state.count << endl;
s.rewind(); // rewind Serializer internal buffers
@@ -182,8 +189,8 @@ bool RewindManager::unwindState()
void RewindManager::compressStates()
{
uInt64 currentCycles = myOSystem.console().tia().cycles();
- double expectedCycles = myInterval * (1*0 + myFactor);
- double maxError = 0;
+ double expectedCycles = myInterval * myFactor * (1 + myFactor);
+ double maxError = 1;
uInt32 removeIdx = 0;
uInt32 idx = myStateList.size() - 2;
@@ -223,17 +230,18 @@ void RewindManager::compressStates()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-string RewindManager::getMessage(RewindState& state, RewindState& lastState)
+string RewindManager::getMessage(RewindState& state)
{
Int64 diff = myOSystem.console().tia().cycles() - state.cycles;
stringstream message;
message << (diff >= 0 ? "Rewind" : "Unwind") << " " << getUnitString(diff);
- // add optional message (TODO: when smart removal works, we have to do something smart with this part too)
- if(!lastState.message.empty())
- message << " (" << lastState.message << ")";
message << " [" << myStateList.currentIdx() << "/" << myStateList.size() << "]";
+ // add optional message
+ if(!state.message.empty())
+ message << " (" << state.message << ")";
+
return message.str();
}
diff --git a/src/common/RewindManager.hxx b/src/common/RewindManager.hxx
index 53fef1b7d..f4e67debb 100644
--- a/src/common/RewindManager.hxx
+++ b/src/common/RewindManager.hxx
@@ -144,6 +144,7 @@ class RewindManager
uInt32 myInterval;
uInt64 myHorizon;
double myFactor;
+ bool myLastContinuousAdd;
struct RewindState {
Serializer data;
@@ -168,7 +169,7 @@ class RewindManager
void compressStates();
- string getMessage(RewindState& state, RewindState& lastState);
+ string getMessage(RewindState& state);
private:
// Following constructors and assignment operators not supported
diff --git a/src/common/StateManager.cxx b/src/common/StateManager.cxx
index a279e23f6..d31c56aaf 100644
--- a/src/common/StateManager.cxx
+++ b/src/common/StateManager.cxx
@@ -161,7 +161,7 @@ void StateManager::update()
switch(myActiveMode)
{
case Mode::Rewind:
- myRewindManager->addState("1 frame", true);
+ myRewindManager->addState("continuous rewind", true);
break;
#if 0
diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx
index 943b3f883..ac3957a8d 100644
--- a/src/emucore/EventHandler.cxx
+++ b/src/emucore/EventHandler.cxx
@@ -299,13 +299,15 @@ void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state)
switch(key)
{
case KBDK_LEFT: // Alt-left rewinds states
- if(myOSystem.state().rewindState() && myState != S_PAUSE)
- setEventState(S_PAUSE);
+ myOSystem.frameBuffer().resetPauseDelay();
+ setEventState(S_PAUSE);
+ myOSystem.state().rewindState();
break;
case KBDK_RIGHT: // Alt-right unwinds states
- if(myOSystem.state().unwindState() && myState != S_PAUSE)
- setEventState(S_PAUSE);
+ myOSystem.frameBuffer().resetPauseDelay();
+ setEventState(S_PAUSE);
+ myOSystem.state().unwindState();
break;
default:
diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx
index 5b635c52a..ed1da3185 100644
--- a/src/emucore/FrameBuffer.cxx
+++ b/src/emucore/FrameBuffer.cxx
@@ -301,7 +301,7 @@ void FrameBuffer::update()
// Show a pause message immediately and then every 7 seconds
if (myPausedCount-- <= 0)
{
- myPausedCount = uInt32(7 * myOSystem.frameRate());
+ resetPauseDelay();
showMessage("Paused", kMiddleCenter);
}
break; // S_PAUSE
@@ -471,6 +471,12 @@ inline void FrameBuffer::drawMessage()
myMsg.enabled = false;
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void FrameBuffer::resetPauseDelay()
+{
+ myPausedCount = uInt32(7 * myOSystem.frameRate());
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
shared_ptr FrameBuffer::allocateSurface(int w, int h, const uInt32* data)
{
diff --git a/src/emucore/FrameBuffer.hxx b/src/emucore/FrameBuffer.hxx
index 12f0e038d..7114ca4b0 100644
--- a/src/emucore/FrameBuffer.hxx
+++ b/src/emucore/FrameBuffer.hxx
@@ -144,6 +144,11 @@ class FrameBuffer
*/
void enableMessages(bool enable);
+ /**
+ Reset 'Paused' display delay counter
+ */
+ void resetPauseDelay();
+
/**
Allocate a new surface. The FrameBuffer class takes all responsibility
for freeing this surface (ie, other classes must not delete it directly).
diff --git a/src/emucore/Settings.cxx b/src/emucore/Settings.cxx
index 6a312e01a..4943d5003 100644
--- a/src/emucore/Settings.cxx
+++ b/src/emucore/Settings.cxx
@@ -329,11 +329,11 @@ void Settings::validate()
i = getInt("dev.rewind.uncompressed");
if(i < 0 || i > size) setInternal("dev.rewind.uncompressed", size);
- i = getInt("dev.rewind.interval");
+ /*i = getInt("dev.rewind.interval");
if(i < 0 || i > 5) setInternal("dev.rewind.interval", 0);
i = getInt("dev.rewind.horizon");
- if(i < 0 || i > 6) setInternal("dev.rewind.horizon", 1);
+ if(i < 0 || i > 6) setInternal("dev.rewind.horizon", 1);*/
i = getInt("plr.tv.jitter_recovery");
if(i < 1 || i > 20) setInternal("plr.tv.jitter_recovery", "10");
diff --git a/src/gui/DeveloperDialog.cxx b/src/gui/DeveloperDialog.cxx
index 88b6ca927..fc48e4f39 100644
--- a/src/gui/DeveloperDialog.cxx
+++ b/src/gui/DeveloperDialog.cxx
@@ -999,6 +999,7 @@ void DeveloperDialog::handleSize()
myUncompressedWidget->setValue(size);
myStateIntervalWidget->setSelectedIndex(interval);
myStateHorizonWidget->setSelectedIndex(i);
+ myStateHorizonWidget->setEnabled(size > uncompressed);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -1011,6 +1012,7 @@ void DeveloperDialog::handleUncompressed()
if(size < uncompressed)
myStateSizeWidget->setValue(uncompressed);
+ myStateHorizonWidget->setEnabled(size > uncompressed);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -