rewind/unwind basically working

changed values, UI and settings for rewind interval and horizon
This commit is contained in:
thrust26 2017-12-12 17:07:05 +01:00
parent 517cc82baa
commit e465112c02
8 changed files with 302 additions and 157 deletions

View File

@ -172,7 +172,7 @@ class LinkedObjectPool
myPool.splice(myPool.end(), myList,
offset >= 0 ? std::next(i, offset) : std::prev(i, -offset));
}
#endif
/**
Convenience method to remove a single element from the active list by
index, offset from the beginning of the list. (ie, '0' means first
@ -181,7 +181,7 @@ class LinkedObjectPool
void remove(uInt32 index) {
myPool.splice(myPool.end(), myList, std::next(myList.begin(), index));
}
#endif
/**
Remove range of elements from the beginning of the active list to

View File

@ -30,11 +30,80 @@ RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
: myOSystem(system),
myStateManager(statemgr)
{
setup();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RewindManager::addState(const string& message)
void RewindManager::setup()
{
/*static const int NUM_INTERVALS = 6;
// TODO: check for intervals shorter than 1 frame (adjust horizon too!)
const uInt32 INTERVAL_CYCLES[NUM_INTERVALS] = { 76, 76 * 50, 76 * 262, 76 * 262 * 10,
76 * 262 * 60, 76 * 262 * 60 * 10 };
static const int NUM_HORIZONS = 7;
const uInt64 HORIZON_CYCLES[NUM_HORIZONS] = { 76 * 262, 76 * 262 * 10, 76 * 262 * 60, 76 * 262 * 60 * 10,
76 * 262 * 60 * 60, 76 * 262 * 60 * 60 * 10, uInt64(76) * 262 * 60 * 60 * 60 };*/
bool devSettings = myOSystem.settings().getBool("dev.settings");
string prefix = devSettings ? "dev." : "plr.";
mySize = MAX_SIZE; // myOSystem.settings().getInt(prefix + "rewind.size");
myUncompressed = MAX_SIZE / 4; // myOSystem.settings().getInt(prefix + "rewind.uncompressed");
myInterval = INTERVAL_CYCLES[0];
for(int i = 0; i < NUM_INTERVALS; ++i)
if(INT_SETTINGS[i] == myOSystem.settings().getString(prefix + "rewind.interval"))
myInterval = INTERVAL_CYCLES[i];
myHorizon = HORIZON_CYCLES[NUM_HORIZONS-1];
for(int i = 0; i < NUM_HORIZONS; ++i)
if(HOR_SETTINGS[i] == myOSystem.settings().getString(prefix + "rewind.horizon"))
myHorizon = HORIZON_CYCLES[i];
// calc interval growth factor
const double MAX_FACTOR = 1E8;
double minFactor = 1, maxFactor = MAX_FACTOR;
while(true)
{
double interval = myInterval;
double cycleSum = interval * myUncompressed;
// calculate next factor
myFactor = (minFactor + maxFactor) / 2;
// horizon not reachable?
if(myFactor == MAX_FACTOR)
break;
// sum up interval cycles
for(uInt32 i = myUncompressed; i < mySize; ++i)
{
interval *= myFactor;
cycleSum += interval;
}
double diff = cycleSum - myHorizon;
// exit loop if result is close enough
if(std::abs(diff) < myHorizon * 1E-5)
break;
// define new boundary
if(cycleSum < myHorizon)
minFactor = myFactor;
else
maxFactor = myFactor;
}
cerr << "factor " << myFactor << endl;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RewindManager::addState(const string& message, bool continuous)
{
// only check for continuous rewind states, ignore for debugger
if(continuous)
{
// check if the current state has the right interval from the last state
RewindState& lastState = myStateList.current();
if(myOSystem.console().tia().cycles() - lastState.cycle < myInterval)
return false;
}
// Remove all future states
myStateList.removeToLast();
@ -63,8 +132,12 @@ cerr << "add " << state.count << endl;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RewindManager::rewindState()
{
if(myStateList.currentIsValid())
if(!atFirst())
{
// Set internal current iterator to previous state (back in time),
// since we will now processed this state
myStateList.moveToPrevious();
RewindState& state = myStateList.current();
Serializer& s = state.data;
string message = getMessage(state);
@ -76,72 +149,65 @@ cerr << "rewind " << state.count << endl;
// Show message indicating the rewind state
myOSystem.frameBuffer().showMessage(message);
// Set internal current iterator to previous state (back in time),
// since we've now processed this state
myStateList.moveToPrevious();
return true;
}
else
return false;
myOSystem.frameBuffer().showMessage("Rewind not possible");
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RewindManager::unwindState()
{
#if 0
if(!atFirst()) // or last???
if(!atLast())
{
// TODO: get state next to the current state
/*RewindState& state = myStateList.???()
// Set internal current iterator to next state (forward in time),
// since we've now processed this state
myStateList.moveToNext();
RewindState& state = myStateList.current();
Serializer& s = state.data;
string message = getMessage(state);
cerr << "unwind " << state.count << endl;
s.reset(); // rewind Serializer internal buffers
s.rewind(); // rewind Serializer internal buffers
myStateManager.loadState(s);
myOSystem.console().tia().loadDisplay(s);
// Show message indicating the rewind state
myOSystem.frameBuffer().showMessage(message);*/
myOSystem.frameBuffer().showMessage(message);
return true;
}
#endif
myOSystem.frameBuffer().showMessage("Unwind not possible");
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void RewindManager::compressStates()
{
#if 0
myStateList.removeFirst(); // remove the oldest state file
#else
//bool debugMode = myOSystem.eventHandler().state() == EventHandler::S_DEBUGGER;
// TODO: let user control these:
const double DENSITY = 1.15; // exponential growth of cycle intervals
const uInt32 STEP_STATES = 6; // single step rewind length (change back to '60')
//const uInt32 SECONDS_STATES = 10; // TODO: one second rewind length
uInt64 currentCycle = myOSystem.console().tia().cycles();
uInt64 lastCycle = currentCycle;
double expectedCycles = 76 * 262.0; // == cycles of 1 frame, TODO: use actual number of scanlines
double expectedCycles = myInterval; // == cycles of 1 frame, TODO: use actual number of scanlines
double maxDelta = 0;
uInt32 removeIdx = 0;
uInt32 idx = myStateList.size() - 1;
cerr << "idx: " << idx << endl;
//cerr << "idx: " << idx << endl;
for(auto it = myStateList.last(); it != myStateList.first(); --it)
{
if(idx >= STEP_STATES)
if(idx < mySize - myUncompressed)
{
cerr << *it << endl << endl; // debug code
expectedCycles *= DENSITY;
//cerr << *it << endl << endl; // debug code
expectedCycles *= myFactor;
double expected = expectedCycles * (1 + DENSITY);
double expected = expectedCycles * (1 + myFactor);
uInt64 prev = myStateList.previous(it)->cycle;
uInt64 next = myStateList.next(it)->cycle;
double delta = expected / (prev - next);
cerr << "prev: " << prev << ", next: " << next << ", delta: " << delta << endl;
if(next != lastCycle)
lastCycle++;
double delta = expected / (next - prev);
//cerr << "prev: " << prev << ", next: " << next << ", delta: " << delta << endl;
if(delta > maxDelta)
{
@ -152,17 +218,17 @@ cerr << "prev: " << prev << ", next: " << next << ", delta: " << delta << endl;
lastCycle = it->cycle;
--idx;
}
cerr << "END\n";
if (maxDelta < 1)
{
// the horizon is getting too big
//myStateList.remove(idx - 1); // remove oldest but one
myStateList.remove(1); // remove oldest but one
cerr << "remove oldest + 1" << endl;
}
else
{
//myStateList.remove(removeIdx); // remove
myStateList.remove(removeIdx); // remove
cerr << "remove " << removeIdx << endl;
}
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -46,13 +46,69 @@ class RewindManager
RewindManager(OSystem& system, StateManager& statemgr);
public:
static const int NUM_INTERVALS = 7;
const uInt32 INTERVAL_CYCLES[NUM_INTERVALS] = {
76 * 262,
76 * 262 * 3,
76 * 262 * 10,
76 * 262 * 30,
76 * 262 * 60,
76 * 262 * 60 * 3,
76 * 262 * 60 * 10
};
/*static const int NUM_INTERVALS = 6;
const string INTERVALS[NUM_INTERVALS] = { "1 scanline", "50 scanlines", "1 frame", "10 frames",
"1 second", "10 seconds" };
const uInt32 INTERVAL_CYCLES[NUM_INTERVALS] = { 76, 76 * 50, 76 * 262, 76 * 262 * 10,
76 * 262 * 60, 76 * 262 * 60 * 10 };*/
const string INT_SETTINGS[NUM_INTERVALS] = {
"1f",
"3f",
"10f",
"30f",
"1s",
"3s",
"10s"
};
static const int NUM_HORIZONS = 8;
const uInt64 HORIZON_CYCLES[NUM_HORIZONS] = {
76 * 262 * 60 * 3,
76 * 262 * 60 * 10,
76 * 262 * 60 * 30,
76 * 262 * 60 * 60,
76 * 262 * 60 * 60 * 3,
76 * 262 * 60 * 60 * 10,
uInt64(76) * 262 * 60 * 60 * 30,
uInt64(76) * 262 * 60 * 60 * 60
};
/*static const int NUM_HORIZONS = 7;
const string HORIZONS[NUM_HORIZONS] = { "~1 frame", "~10 frames", "~1 second", "~10 seconds",
"~1 minute", "~10 minutes", "~60 minutes" };
const uInt64 HORIZON_CYCLES[NUM_HORIZONS] = { 76 * 262, 76 * 262 * 10, 76 * 262 * 60, 76 * 262 * 60 * 10,
76 * 262 * 60 * 60, 76 * 262 * 60 * 60 * 10, uInt64(76) * 262 * 60 * 60 * 60 };*/
const string HOR_SETTINGS[NUM_HORIZONS] = {
"3s",
"10s",
"30s",
"1m",
"3m",
"10m",
"30m",
"60m"
};
/**
*/
void setup();
/**
Add a new state file with the given message; this message will be
displayed when the state is replayed.
@param message Message to display when replaying this state
*/
bool addState(const string& message);
bool addState(const string& message, bool continuous = false);
/**
Rewind one level of the state list, and display the message associated
@ -77,11 +133,17 @@ class RewindManager
private:
// Maximum number of states to save
static constexpr uInt32 MAX_SIZE = 10; // TODO: use a parameter here and allow user to define size in UI
static constexpr uInt32 MAX_SIZE = 20; // TODO: use a parameter here and allow user to define size in UI
OSystem& myOSystem;
StateManager& myStateManager;
uInt32 mySize;
uInt32 myUncompressed;
uInt32 myInterval;
uInt64 myHorizon;
double myFactor;
struct RewindState {
Serializer data;
string message;

View File

@ -145,7 +145,6 @@ void StateManager::toggleRewindMode()
bool StateManager::rewindState()
{
RewindManager& r = myOSystem.state().rewindManager();
// TODO: add parameter to indicate rewinding from within emulation
return r.rewindState();
}
@ -153,7 +152,6 @@ bool StateManager::rewindState()
bool StateManager::unwindState()
{
RewindManager& r = myOSystem.state().rewindManager();
// TODO: add parameter to indicate unwinding from within emulation
return r.unwindState();
}
@ -163,7 +161,7 @@ void StateManager::update()
switch(myActiveMode)
{
case Mode::Rewind:
myRewindManager->addState("add 1 frame");
myRewindManager->addState("1 frame", true);
break;
#if 0

View File

@ -524,8 +524,8 @@ void Debugger::nextFrame(int frames)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::updateRewindbuttons(const RewindManager& r)
{
myDialog->rewindButton().setEnabled(!r.atLast());
myDialog->unwindButton().setEnabled(!r.atFirst());
myDialog->rewindButton().setEnabled(!r.atFirst());
myDialog->unwindButton().setEnabled(!r.atLast());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -158,8 +158,8 @@ Settings::Settings(OSystem& osystem)
setInternal("plr.rewind", false);
setInternal("plr.rewind.size", 100);
setInternal("plr.rewind.uncompressed", 30);
setInternal("plr.rewind.interval", 4); // = 1 second
setInternal("plr.rewind.horizon", 5); // = ~10 minutes
setInternal("plr.rewind.interval", "30f"); // = 0.5 seconds
setInternal("plr.rewind.horizon", "10m"); // = ~10 minutes
// Thumb ARM emulation options
setInternal("plr.thumb.trapfatal", "false");
@ -178,8 +178,8 @@ Settings::Settings(OSystem& osystem)
setInternal("dev.rewind", true);
setInternal("dev.rewind.size", 100);
setInternal("dev.rewind.uncompressed", 60);
setInternal("dev.rewind.interval", 2); // = 1 frame
setInternal("dev.rewind.horizon", 3); // = ~10 seconds
setInternal("dev.rewind.interval", "1f"); // = 1 frame
setInternal("dev.rewind.horizon", "10s"); // = ~10 seconds
// Thumb ARM emulation options
setInternal("dev.thumb.trapfatal", "true");
}
@ -330,10 +330,10 @@ void Settings::validate()
if(i < 0 || i > size) setInternal("dev.rewind.uncompressed", size);
i = getInt("dev.rewind.interval");
if(i < 0 || i > 5) setInternal("dev.rewind.interval", 2);
if(i < 0 || i > 5) setInternal("dev.rewind.interval", 0);
i = getInt("dev.rewind.horizon");
if(i < 0 || i > 6) setInternal("dev.rewind.horizon", 3);
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");
@ -348,11 +348,11 @@ void Settings::validate()
i = getInt("plr.rewind.uncompressed");
if(i < 0 || i > size) setInternal("plr.rewind.uncompressed", size);
i = getInt("plr.rewind.interval");
if(i < 0 || i > 5) setInternal("plr.rewind.interval", 4);
/*i = getInt("plr.rewind.interval");
if(i < 0 || i > 5) setInternal("plr.rewind.interval", 3);
i = getInt("plr.rewind.horizon");
if(i < 0 || i > 6) setInternal("plr.rewind.horizon", 5);
if(i < 0 || i > 6) setInternal("plr.rewind.horizon", 5);*/
#ifdef SOUND_SUPPORT
i = getInt("volume");

View File

@ -38,6 +38,7 @@
#include "TIA.hxx"
#include "OSystem.hxx"
#include "StateManager.hxx"
#include "RewindManager.hxx"
#include "DeveloperDialog.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -85,10 +86,12 @@ void DeveloperDialog::addEmulationTab(const GUI::Font& font)
// settings set
mySettingsGroup0 = new RadioButtonGroup();
RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, "Player settings", mySettingsGroup0, kPlrSettings);
RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1,
"Player settings", mySettingsGroup0, kPlrSettings);
wid.push_back(r);
ypos += lineHeight + VGAP;
r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, "Developer settings", mySettingsGroup0, kDevSettings);
r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1,
"Developer settings", mySettingsGroup0, kDevSettings);
wid.push_back(r);
ypos += lineHeight + VGAP * 1;
@ -177,10 +180,12 @@ void DeveloperDialog::addVideoTab(const GUI::Font& font)
// settings set
mySettingsGroup1 = new RadioButtonGroup();
RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, "Player settings", mySettingsGroup1, kPlrSettings);
RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1,
"Player settings", mySettingsGroup1, kPlrSettings);
wid.push_back(r);
ypos += lineHeight + VGAP;
r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, "Developer settings", mySettingsGroup1, kDevSettings);
r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1,
"Developer settings", mySettingsGroup1, kDevSettings);
wid.push_back(r);
ypos += lineHeight + VGAP * 1;
@ -247,7 +252,6 @@ void DeveloperDialog::addVideoTab(const GUI::Font& font)
// Add message concerning usage
const GUI::Font& infofont = instance().frameBuffer().infoFont();
ypos = myTab->getHeight() - 5 - fontHeight - infofont.getFontHeight() - 10;
//new StaticTextWidget(myTab, infofont, 10, ypos, "(*) Colors must be different for each object");
new StaticTextWidget(myTab, infofont, HBORDER, ypos, "(*) colors identical for player and developer settings");
// Add items for tab 2
@ -257,6 +261,44 @@ void DeveloperDialog::addVideoTab(const GUI::Font& font)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DeveloperDialog::addStatesTab(const GUI::Font& font)
{
const string INTERVALS[NUM_INTERVALS] = {
"1 frame",
"3 frames",
"10 frames",
"30 frames",
"1 second",
"3 seconds",
"10 seconds"
};
const string INT_SETTINGS[NUM_INTERVALS] = {
"1f",
"3f",
"10f",
"30f",
"1s",
"3s",
"10s"
};
const string HORIZONS[NUM_HORIZONS] = {
"~3 seconds",
"~10 seconds",
"~30 seconds",
"~1 minute",
"~3 minutes",
"~10 minutes",
"~30 minutes",
"~60 minutes"
};
const string HOR_SETTINGS[NUM_HORIZONS] = {
"3s",
"10s",
"30s",
"1m",
"3m",
"10m",
"30m",
"60m"
};
const int HBORDER = 10;
const int INDENT = 16+4;
const int VBORDER = 8;
@ -265,24 +307,28 @@ void DeveloperDialog::addStatesTab(const GUI::Font& font)
int lineHeight = font.getLineHeight();
int fontHeight = font.getFontHeight();
WidgetArray wid;
VariantList items;
int tabID = myTab->addTab("States");
// settings set
mySettingsGroup2 = new RadioButtonGroup();
RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, "Player settings", mySettingsGroup2, kPlrSettings);
RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1,
"Player settings", mySettingsGroup2, kPlrSettings);
wid.push_back(r);
ypos += lineHeight + VGAP;
r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, "Developer settings", mySettingsGroup2, kDevSettings);
r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1,
"Developer settings", mySettingsGroup2, kDevSettings);
wid.push_back(r);
ypos += lineHeight + VGAP * 1;
myContinuousRewindWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT, ypos + 1, "Continuous rewind", kRewind);
myContinuousRewindWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT, ypos + 1,
"Continuous rewind", kRewind);
wid.push_back(myContinuousRewindWidget);
ypos += lineHeight + VGAP;
int sWidth = font.getMaxCharWidth() * 8;
myStateSizeWidget = new SliderWidget(myTab, font, HBORDER + INDENT * 2, ypos - 1, sWidth, lineHeight,
"Buffer size (*) ", 0, kSizeChanged);
"Buffer size (*) ", 0, kSizeChanged);
myStateSizeWidget->setMinValue(100);
myStateSizeWidget->setMaxValue(1000);
myStateSizeWidget->setStepValue(20);
@ -292,32 +338,30 @@ void DeveloperDialog::addStatesTab(const GUI::Font& font)
ypos += lineHeight + VGAP;
myUncompressedWidget = new SliderWidget(myTab, font, HBORDER + INDENT * 2, ypos - 1, sWidth, lineHeight,
"Uncompressed size (*) ", 0, kUncompressedChanged);
"Uncompressed size ", 0, kUncompressedChanged);
myUncompressedWidget->setMinValue(0);
myUncompressedWidget->setMaxValue(1000);
myUncompressedWidget->setStepValue(20);
wid.push_back(myUncompressedWidget);
myUncompressedLabelWidget = new StaticTextWidget(myTab, font, myUncompressedWidget->getRight() + 4,
myUncompressedWidget->getTop() + 2, "50 ");
myUncompressedWidget->getTop() + 2, "50 ");
ypos += lineHeight + VGAP;
myStateIntervalWidget = new SliderWidget(myTab, font, HBORDER + INDENT * 2, ypos - 1, sWidth, lineHeight,
"Interval ", 0, kIntervalChanged);
myStateIntervalWidget->setMinValue(0);
myStateIntervalWidget->setMaxValue(NUM_INTERVALS - 1);
items.clear();
for(int i = 0; i < NUM_INTERVALS; ++i)
VarList::push_back(items, INTERVALS[i], INT_SETTINGS[i]);
int pwidth = font.getStringWidth("~10 seconds");
myStateIntervalWidget = new PopUpWidget(myTab, font, HBORDER + INDENT * 2, ypos, pwidth,
lineHeight, items, "Interval ", 0, kIntervalChanged);
wid.push_back(myStateIntervalWidget);
myStateIntervalLabelWidget = new StaticTextWidget(myTab, font, myStateIntervalWidget->getRight() + 4,
myStateIntervalWidget->getTop() + 2, "50 scanlines");
ypos += lineHeight + VGAP;
myStateHorizonWidget = new SliderWidget(myTab, font, HBORDER + INDENT * 2, ypos - 1, sWidth, lineHeight,
"Horizon ", 0, kHorizonChanged);
myStateHorizonWidget->setMinValue(0);
myStateHorizonWidget->setMaxValue(NUM_HORIZONS - 1);
items.clear();
for(int i = 0; i < NUM_HORIZONS; ++i)
VarList::push_back(items, HORIZONS[i], HOR_SETTINGS[i]);
myStateHorizonWidget = new PopUpWidget(myTab, font, HBORDER + INDENT * 2, ypos, pwidth,
lineHeight, items, "Horizon ", 0, kHorizonChanged);
wid.push_back(myStateHorizonWidget);
myStateHorizonLabelWidget = new StaticTextWidget(myTab, font, myStateHorizonWidget->getRight() + 4,
myStateHorizonWidget->getTop() + 2, "~60 minutes");
// Add message concerning usage
const GUI::Font& infofont = instance().frameBuffer().infoFont();
@ -477,8 +521,11 @@ void DeveloperDialog::loadSettings(SettingsSet set)
myContinuousRewind[set] = instance().settings().getBool(prefix + "rewind");
myStateSize[set] = instance().settings().getInt(prefix + "rewind.size");
myUncompressed[set] = instance().settings().getInt(prefix + "rewind.uncompressed");
myStateInterval[set] = instance().settings().getInt(prefix + "rewind.interval");
myStateHorizon[set] = instance().settings().getInt(prefix + "rewind.horizon");
/*myStateInterval[set] = instance().settings().getInt(prefix + "rewind.interval");
myStateHorizon[set] = instance().settings().getInt(prefix + "rewind.horizon");*/
myStateInterval[set] = instance().settings().getString(prefix + "rewind.interval");
myStateHorizon[set] = instance().settings().getString(prefix + "rewind.horizon");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -544,8 +591,9 @@ void DeveloperDialog::getWidgetStates(SettingsSet set)
myContinuousRewind[set] = myContinuousRewindWidget->getState();
myStateSize[set] = myStateSizeWidget->getValue();
myUncompressed[set] = myUncompressedWidget->getValue();
myStateInterval[set] = myStateIntervalWidget->getValue();
myStateHorizon[set] = myStateHorizonWidget->getValue();
myStateInterval[set] = myStateIntervalWidget->getSelected();
myStateInterval[set] = myStateIntervalWidget->getSelectedTag().toString();
myStateHorizon[set] = myStateHorizonWidget->getSelectedTag().toString();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -583,8 +631,10 @@ void DeveloperDialog::setWidgetStates(SettingsSet set)
myContinuousRewindWidget->setState(myContinuousRewind[set]);
myStateSizeWidget->setValue(myStateSize[set]);
myUncompressedWidget->setValue(myUncompressed[set]);
myStateIntervalWidget->setValue(myStateInterval[set]);
myStateHorizonWidget->setValue(myStateHorizon[set]);
//myStateIntervalWidget->setSelectedIndex(myStateInterval[set]);
myStateIntervalWidget->setSelected(myStateInterval[set]);
//myStateHorizonWidget->setSelectedIndex(myStateHorizon[set]);
myStateHorizonWidget->setSelected(myStateHorizon[set]);
handleRewind();
handleSize();
@ -671,47 +721,11 @@ void DeveloperDialog::saveConfig()
// Finally, issue a complete framebuffer re-initialization
//instance().createFrameBuffer();
// TODO: update RewindManager
// update RewindManager
instance().state().rewindManager().setup();
instance().state().setRewindMode(myContinuousRewindWidget->getState() ?
StateManager::Mode::Rewind : StateManager::Mode::Off);
// define interval growth factor
uInt32 size = myStateSizeWidget->getValue();
uInt32 uncompressed = myUncompressedWidget->getValue();
const double MAX_FACTOR = 1E8;
uInt64 horizon = HORIZON_CYCLES[myStateHorizonWidget->getValue()];
double factor, minFactor = 1, maxFactor = MAX_FACTOR;
while(true)
{
double interval = INTERVAL_CYCLES[myStateIntervalWidget->getValue()];
double cycleSum = interval * uncompressed;
// calculate next factor
factor = (minFactor + maxFactor) / 2;
// horizon not reachable?
if(factor == MAX_FACTOR)
break;
// sum up interval cycles
for(uInt32 i = uncompressed; i < size; ++i)
{
interval *= factor;
cycleSum += interval;
}
double diff = cycleSum - horizon;
//cerr << "factor " << factor << ", diff " << diff << endl;
// exit loop if result is close enough
if(std::abs(diff) < horizon * 1E-5)
break;
// define new boundary
if(cycleSum < horizon)
minFactor = factor;
else
maxFactor = factor;
}
// TODO factor calculation code above into RewindManager
//instance().settings().setValue("dev.rewind.factor", factor);
// Debugger font style
instance().settings().setValue("dbg.fontstyle",
myDebuggerFontStyle->getSelectedTag().toString());
@ -767,8 +781,8 @@ void DeveloperDialog::setDefaults()
myContinuousRewind[set] = devSettings ? true : false;
myStateSize[set] = 100;
myUncompressed[set] = devSettings ? 60 : 30;
myStateInterval[set] = devSettings ? 2 : 4;
myStateHorizon[set] = devSettings ? 3 : 5;
myStateInterval[set] = devSettings ? "1f" : "30f";
myStateHorizon[set] = devSettings ? "10s" : "10m";
setWidgetStates(set);
break;
@ -954,10 +968,8 @@ void DeveloperDialog::handleRewind()
myUncompressedLabelWidget->setEnabled(enable);
myStateIntervalWidget->setEnabled(enable);
myStateIntervalLabelWidget->setEnabled(enable);
myStateHorizonWidget->setEnabled(enable);
myStateHorizonLabelWidget->setEnabled(enable);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -965,18 +977,24 @@ void DeveloperDialog::handleSize()
{
uInt32 size = myStateSizeWidget->getValue();
uInt32 uncompressed = myUncompressedWidget->getValue();
uInt32 interval = myStateIntervalWidget->getValue();
uInt32 horizon = myStateHorizonWidget->getValue();
uInt32 interval = myStateIntervalWidget->getSelected();
uInt32 horizon = myStateHorizonWidget->getSelected();
bool found = false;
Int32 i;
if(interval == -1)
interval = 0;
if(horizon == -1)
horizon = 0;
myStateSizeLabelWidget->setValue(size);
// adapt horizon and interval
do
{
for(i = horizon; i < NUM_HORIZONS; ++i)
{
if(size * INTERVAL_CYCLES[interval] <= HORIZON_CYCLES[i])
if((uInt64)size * instance().state().rewindManager().INTERVAL_CYCLES[interval]
<= instance().state().rewindManager().HORIZON_CYCLES[i])
{
found = true;
break;
@ -988,8 +1006,8 @@ void DeveloperDialog::handleSize()
if(size < uncompressed)
myUncompressedWidget->setValue(size);
myStateIntervalWidget->setValue(interval);
myStateHorizonWidget->setValue(i);
myStateIntervalWidget->setSelectedIndex(interval);
myStateHorizonWidget->setSelectedIndex(i);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1009,18 +1027,23 @@ void DeveloperDialog::handleInterval()
{
uInt32 size = myStateSizeWidget->getValue();
uInt32 uncompressed = myUncompressedWidget->getValue();
uInt32 interval = myStateIntervalWidget->getValue();
uInt32 horizon = myStateHorizonWidget->getValue();
uInt32 interval = myStateIntervalWidget->getSelected();
uInt32 horizon = myStateHorizonWidget->getSelected();
bool found = false;
Int32 i;
myStateIntervalLabelWidget->setLabel(INTERVALS[interval]);
if(interval == -1)
interval = 0;
if(horizon == -1)
horizon = 0;
// adapt horizon and size
do
{
for(i = horizon; i < NUM_HORIZONS; ++i)
{
if(size * INTERVAL_CYCLES[interval] <= HORIZON_CYCLES[i])
if((uInt64)size * instance().state().rewindManager().INTERVAL_CYCLES[interval]
<= instance().state().rewindManager().HORIZON_CYCLES[i])
{
found = true;
break;
@ -1030,10 +1053,10 @@ void DeveloperDialog::handleInterval()
size -= myStateSizeWidget->getStepValue();
} while(!found);
myStateHorizonWidget->setSelectedIndex(i);
myStateSizeWidget->setValue(size);
if(size < uncompressed)
myUncompressedWidget->setValue(size);
myStateHorizonWidget->setValue(i);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1041,18 +1064,23 @@ void DeveloperDialog::handleHorizon()
{
uInt32 size = myStateSizeWidget->getValue();
uInt32 uncompressed = myUncompressedWidget->getValue();
uInt32 interval = myStateIntervalWidget->getValue();
uInt32 horizon = myStateHorizonWidget->getValue();
uInt32 interval = myStateIntervalWidget->getSelected();
uInt32 horizon = myStateHorizonWidget->getSelected();
bool found = false;
Int32 i;
myStateHorizonLabelWidget->setLabel(HORIZONS[horizon]);
if(interval == -1)
interval = 0;
if(horizon == -1)
horizon = 0;
// adapt interval and size
do
{
for(i = interval; i >= 0; --i)
{
if(size * INTERVAL_CYCLES[i] <= HORIZON_CYCLES[horizon])
if(size * instance().state().rewindManager().INTERVAL_CYCLES[i]
<= instance().state().rewindManager().HORIZON_CYCLES[horizon])
{
found = true;
break;
@ -1062,10 +1090,10 @@ void DeveloperDialog::handleHorizon()
size -= myStateSizeWidget->getStepValue();
} while(!found);
myStateIntervalWidget->setSelectedIndex(i);
myStateSizeWidget->setValue(size);
if(size < uncompressed)
myUncompressedWidget->setValue(size);
myStateIntervalWidget->setValue(i);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -86,17 +86,9 @@ class DeveloperDialog : public Dialog
developer
};
static const int NUM_INTERVALS = 6;
// TODO: check for intervals shorter than 1 frame (adjust horizon too!)
const string INTERVALS[NUM_INTERVALS] = { "1 scanline", "50 scanlines", "1 frame", "10 frames",
"1 second", "10 seconds" };
const uInt32 INTERVAL_CYCLES[NUM_INTERVALS] = { 76, 76 * 50, 76 * 262, 76 * 262 * 10,
76 * 262 * 60, 76 * 262 * 60 * 10 };
static const int NUM_HORIZONS = 7;
const string HORIZONS[NUM_HORIZONS] = { "~1 frame", "~10 frames", "~1 second", "~10 seconds",
"~1 minute", "~10 minutes", "~60 minutes" };
const uInt64 HORIZON_CYCLES[NUM_HORIZONS] = { 76 * 262, 76 * 262 * 10, 76 * 262 * 60, 76 * 262 * 60 * 10,
76 * 262 * 60 * 60, 76 * 262 * 60 * 60 * 10, uInt64(76) * 262 * 60 * 60 * 60 };
// MUST be aligned with RewindManager!
static const int NUM_INTERVALS = 7;
static const int NUM_HORIZONS = 8;
static const int DEBUG_COLORS = 6;
@ -130,10 +122,8 @@ class DeveloperDialog : public Dialog
StaticTextWidget* myStateSizeLabelWidget;
SliderWidget* myUncompressedWidget;
StaticTextWidget* myUncompressedLabelWidget;
SliderWidget* myStateIntervalWidget;
StaticTextWidget* myStateIntervalLabelWidget;
SliderWidget* myStateHorizonWidget;
StaticTextWidget* myStateHorizonLabelWidget;
PopUpWidget* myStateIntervalWidget;
PopUpWidget* myStateHorizonWidget;
#ifdef DEBUGGER_SUPPORT
// Debugger UI widgets
@ -162,8 +152,9 @@ class DeveloperDialog : public Dialog
bool myContinuousRewind[2];
int myStateSize[2];
int myUncompressed[2];
int myStateInterval[2];
int myStateHorizon[2];
//int myStateInterval[2];
string myStateInterval[2];
string myStateHorizon[2];
private:
void addEmulationTab(const GUI::Font& font);