mirror of https://github.com/stella-emu/stella.git
rewind/unwind basically working
changed values, UI and settings for rewind interval and horizon
This commit is contained in:
parent
517cc82baa
commit
e465112c02
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue