diff --git a/CHANGES b/CHANGES index 3b21347f0..0d17fab74 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,7 @@ Features: - Added a setting for pausing when the emulator is not in focus - Customizable paths for save games, save states, screenshots and patches - Controller hotplugging + - Ability to store save games and active cheats within savestates Bugfixes: - Util: Fix PowerPC PNG read/write pixel order - VFS: Fix VFileReadline and remove _vfdReadline @@ -67,6 +68,7 @@ Misc: - Qt: Added button for breaking into the GDB debugger - GBA BIOS: Finish implementing RegisterRamReset - GBA: Allow jumping to OAM and palette RAM + - Qt: Add box for showing duration of rewind 0.3.2: (2015-12-16) Bugfixes: diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index d2d900d0d..7722b7715 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -907,6 +907,14 @@ void GameController::reloadAudioDriver() { } } +void GameController::setSaveStateExtdata(int flags) { + m_saveStateFlags = flags; +} + +void GameController::setLoadStateExtdata(int flags) { + m_loadStateFlags = flags; +} + void GameController::setLuminanceValue(uint8_t value) { m_luxValue = value; value = std::max(value - 0x16, 0); diff --git a/src/platform/qt/GameController.h b/src/platform/qt/GameController.h index 0d757bce1..a7a3d89ae 100644 --- a/src/platform/qt/GameController.h +++ b/src/platform/qt/GameController.h @@ -138,6 +138,8 @@ public slots: void setAVStream(GBAAVStream*); void clearAVStream(); void reloadAudioDriver(); + void setSaveStateExtdata(int flags); + void setLoadStateExtdata(int flags); #ifdef USE_PNG void screenshot(); diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index 810079459..48ed5e4e8 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -13,6 +13,10 @@ #include "InputController.h" #include "ShortcutView.h" +extern "C" { +#include "gba/serialize.h" +} + using namespace QGBA; SettingsView::SettingsView(ConfigController* controller, InputController* inputController, ShortcutController* shortcutController, QWidget* parent) @@ -21,29 +25,7 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC { m_ui.setupUi(this); - loadSetting("bios", m_ui.bios); - loadSetting("useBios", m_ui.useBios); - loadSetting("skipBios", m_ui.skipBios); - loadSetting("audioBuffers", m_ui.audioBufferSize); - loadSetting("sampleRate", m_ui.sampleRate); - loadSetting("videoSync", m_ui.videoSync); - loadSetting("audioSync", m_ui.audioSync); - loadSetting("frameskip", m_ui.frameskip); - loadSetting("fpsTarget", m_ui.fpsTarget); - loadSetting("lockAspectRatio", m_ui.lockAspectRatio); - loadSetting("volume", m_ui.volume); - loadSetting("mute", m_ui.mute); - loadSetting("rewindEnable", m_ui.rewind); - loadSetting("rewindBufferInterval", m_ui.rewindInterval); - loadSetting("rewindBufferCapacity", m_ui.rewindCapacity); - loadSetting("resampleVideo", m_ui.resampleVideo); - loadSetting("allowOpposingDirections", m_ui.allowOpposingDirections); - loadSetting("suspendScreensaver", m_ui.suspendScreensaver); - loadSetting("pauseOnFocusLost", m_ui.pauseOnFocusLost); - loadSetting("savegamePath", m_ui.savegamePath); - loadSetting("savestatePath", m_ui.savestatePath); - loadSetting("screenshotPath", m_ui.screenshotPath); - loadSetting("patchPath", m_ui.patchPath); + reloadConfig(); if (m_ui.savegamePath->text().isEmpty()) { m_ui.savegameSameDir->setChecked(true); @@ -109,28 +91,7 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC } }); - double fastForwardRatio = loadSetting("fastForwardRatio").toDouble(); - if (fastForwardRatio <= 0) { - m_ui.fastForwardUnbounded->setChecked(true); - m_ui.fastForwardRatio->setEnabled(false); - } else { - m_ui.fastForwardUnbounded->setChecked(false); - m_ui.fastForwardRatio->setEnabled(true); - m_ui.fastForwardRatio->setValue(fastForwardRatio); - } - connect(m_ui.fastForwardUnbounded, &QAbstractButton::toggled, [this](bool checked) { - m_ui.fastForwardRatio->setEnabled(!checked); - }); - - QString idleOptimization = loadSetting("idleOptimization"); - if (idleOptimization == "ignore") { - m_ui.idleOptimization->setCurrentIndex(0); - } else if (idleOptimization == "remove") { - m_ui.idleOptimization->setCurrentIndex(1); - } else if (idleOptimization == "detect") { - m_ui.idleOptimization->setCurrentIndex(2); - } - + // TODO: Move to reloadConfig() QVariant audioDriver = m_controller->getQtOption("audioDriver"); #ifdef BUILD_QT_MULTIMEDIA m_ui.audioDriver->addItem(tr("Qt Multimedia"), static_cast(AudioProcessor::Driver::QT_MULTIMEDIA)); @@ -146,6 +107,7 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC } #endif + // TODO: Move to reloadConfig() QVariant displayDriver = m_controller->getQtOption("displayDriver"); m_ui.displayDriver->addItem(tr("Software (Qt)"), static_cast(Display::Driver::QT)); if (!displayDriver.isNull() && displayDriver.toInt() == static_cast(Display::Driver::QT)) { @@ -195,6 +157,14 @@ void SettingsView::selectBios() { } } +void SettingsView::recalculateRewind() { + int interval = m_ui.rewindInterval->value(); + int capacity = m_ui.rewindCapacity->value(); + double duration = m_ui.fpsTarget->value(); + m_ui.rewindDuration->setValue(interval * capacity / duration); + +} + void SettingsView::updateConfig() { saveSetting("bios", m_ui.bios); saveSetting("useBios", m_ui.useBios); @@ -238,6 +208,18 @@ void SettingsView::updateConfig() { break; } + int loadState = 0; + loadState |= m_ui.loadStateScreenshot->isChecked() ? SAVESTATE_SCREENSHOT : 0; + loadState |= m_ui.loadStateSave->isChecked() ? SAVESTATE_SAVEDATA : 0; + loadState |= m_ui.loadStateCheats->isChecked() ? SAVESTATE_CHEATS : 0; + saveSetting("loadStateExtdata", loadState); + + int saveState = 0; + saveState |= m_ui.saveStateScreenshot->isChecked() ? SAVESTATE_SCREENSHOT : 0; + saveState |= m_ui.saveStateSave->isChecked() ? SAVESTATE_SAVEDATA : 0; + saveState |= m_ui.saveStateCheats->isChecked() ? SAVESTATE_CHEATS : 0; + saveSetting("saveStateExtdata", saveState); + QVariant audioDriver = m_ui.audioDriver->itemData(m_ui.audioDriver->currentIndex()); if (audioDriver != m_controller->getQtOption("audioDriver")) { m_controller->setQtOption("audioDriver", audioDriver); @@ -258,6 +240,72 @@ void SettingsView::updateConfig() { emit biosLoaded(m_ui.bios->text()); } +void SettingsView::reloadConfig() { + loadSetting("bios", m_ui.bios); + loadSetting("useBios", m_ui.useBios); + loadSetting("skipBios", m_ui.skipBios); + loadSetting("audioBuffers", m_ui.audioBufferSize); + loadSetting("sampleRate", m_ui.sampleRate); + loadSetting("videoSync", m_ui.videoSync); + loadSetting("audioSync", m_ui.audioSync); + loadSetting("frameskip", m_ui.frameskip); + loadSetting("fpsTarget", m_ui.fpsTarget); + loadSetting("lockAspectRatio", m_ui.lockAspectRatio); + loadSetting("volume", m_ui.volume); + loadSetting("mute", m_ui.mute); + loadSetting("rewindEnable", m_ui.rewind); + loadSetting("rewindBufferInterval", m_ui.rewindInterval); + loadSetting("rewindBufferCapacity", m_ui.rewindCapacity); + loadSetting("resampleVideo", m_ui.resampleVideo); + loadSetting("allowOpposingDirections", m_ui.allowOpposingDirections); + loadSetting("suspendScreensaver", m_ui.suspendScreensaver); + loadSetting("pauseOnFocusLost", m_ui.pauseOnFocusLost); + loadSetting("savegamePath", m_ui.savegamePath); + loadSetting("savestatePath", m_ui.savestatePath); + loadSetting("screenshotPath", m_ui.screenshotPath); + loadSetting("patchPath", m_ui.patchPath); + + double fastForwardRatio = loadSetting("fastForwardRatio").toDouble(); + if (fastForwardRatio <= 0) { + m_ui.fastForwardUnbounded->setChecked(true); + m_ui.fastForwardRatio->setEnabled(false); + } else { + m_ui.fastForwardUnbounded->setChecked(false); + m_ui.fastForwardRatio->setEnabled(true); + m_ui.fastForwardRatio->setValue(fastForwardRatio); + } + + connect(m_ui.rewindInterval, SIGNAL(valueChanged(int)), this, SLOT(recalculateRewind())); + connect(m_ui.rewindCapacity, SIGNAL(valueChanged(int)), this, SLOT(recalculateRewind())); + connect(m_ui.fpsTarget, SIGNAL(valueChanged(double)), this, SLOT(recalculateRewind())); + + QString idleOptimization = loadSetting("idleOptimization"); + if (idleOptimization == "ignore") { + m_ui.idleOptimization->setCurrentIndex(0); + } else if (idleOptimization == "remove") { + m_ui.idleOptimization->setCurrentIndex(1); + } else if (idleOptimization == "detect") { + m_ui.idleOptimization->setCurrentIndex(2); + } + + bool ok; + int loadState = loadSetting("loadStateExtdata").toInt(&ok); + if (!ok) { + loadState = SAVESTATE_SCREENSHOT; + } + m_ui.loadStateScreenshot->setChecked(loadState & SAVESTATE_SCREENSHOT); + m_ui.loadStateSave->setChecked(loadState & SAVESTATE_SAVEDATA); + m_ui.loadStateCheats->setChecked(loadState & SAVESTATE_CHEATS); + + int saveState = loadSetting("saveStateExtdata").toInt(&ok); + if (!ok) { + saveState = SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS; + } + m_ui.saveStateScreenshot->setChecked(saveState & SAVESTATE_SCREENSHOT); + m_ui.saveStateSave->setChecked(saveState & SAVESTATE_SAVEDATA); + m_ui.saveStateCheats->setChecked(saveState & SAVESTATE_CHEATS); +} + void SettingsView::saveSetting(const char* key, const QAbstractButton* field) { m_controller->setOption(key, field->isChecked()); m_controller->updateOption(key); diff --git a/src/platform/qt/SettingsView.h b/src/platform/qt/SettingsView.h index 4ccdabf0e..77d672bdf 100644 --- a/src/platform/qt/SettingsView.h +++ b/src/platform/qt/SettingsView.h @@ -30,7 +30,9 @@ signals: private slots: void selectBios(); + void recalculateRewind(); void updateConfig(); + void reloadConfig(); private: Ui::SettingsView m_ui; diff --git a/src/platform/qt/SettingsView.ui b/src/platform/qt/SettingsView.ui index 6a2cca0bb..22a94947f 100644 --- a/src/platform/qt/SettingsView.ui +++ b/src/platform/qt/SettingsView.ui @@ -6,8 +6,8 @@ 0 0 - 568 - 451 + 544 + 425 @@ -23,10 +23,56 @@ QLayout::SetFixedSize + + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + 0 + 0 + + + + + 140 + 16777215 + + + + 0 + + + + Audio/Video + + + + + Emulation + + + + + Savestates + + + + + Paths + + + + - 0 + 2 @@ -374,77 +420,35 @@ - Use BIOS file + Use BIOS file if found true + + + + Skip BIOS intro + + + + + + + Qt::Horizontal + + + - - - Create rewind state: - - - - - - - Enable rewind - - - - - - - - - Every - - - - - - - - - - frames - - - - - - - - - Rewind history: - - - - - - - - - - - - states - - - - - - Fast forward speed - + false @@ -466,7 +470,7 @@ - + Unbounded @@ -476,14 +480,21 @@ - + + + + Qt::Horizontal + + + + Allow opposing input directions - + Suspend screensaver @@ -493,14 +504,21 @@ - + + + + Pause when inactive + + + + Idle loops - + @@ -519,41 +537,172 @@ - - + + + + + + QFormLayout::FieldsStayAtSizeHint + + + - Skip BIOS intro + Save extra data - - + + + + Screenshot + + + true + + + + + + + Save data + + + true + + + + + + + Cheat codes + + + true + + + + + Qt::Horizontal - + + + + Load extra data + + + + + + + Screenshot + + + true + + + + + + + Save data + + + + + + + Cheat codes + + + + Qt::Horizontal - - - - Qt::Horizontal + + + + Enable rewind - - + + - Pause when inactive + Create rewind state: + + + + + + Every + + + + + + + + + + frames + + + + + + + + + Rewind history: + + + + + + + + + + + + states + + + + + + + + + + + false + + + 999.990000000000009 + + + + + + + seconds + + + + + @@ -750,44 +899,6 @@ - - - - - 0 - 0 - - - - - 140 - 16777215 - - - - - Audio/Video - - - - - Emulation - - - - - Paths - - - - - - - - QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - @@ -904,5 +1015,21 @@ + + fastForwardUnbounded + toggled(bool) + fastForwardRatio + setDisabled(bool) + + + 338 + 163 + + + 327 + 135 + + + diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index d5d8f30dd..2e6b70da6 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -241,6 +241,19 @@ void Window::reloadConfig() { m_log.setLevels(opts->logLevel); + QString saveStateExtdata = m_config->getOption("saveStateExtdata"); + bool ok; + int flags = saveStateExtdata.toInt(&ok); + if (ok) { + m_controller->setSaveStateExtdata(flags); + } + + QString loadStateExtdata = m_config->getOption("loadStateExtdata"); + flags = loadStateExtdata.toInt(&ok); + if (ok) { + m_controller->setLoadStateExtdata(flags); + } + m_controller->setOptions(opts); m_display->lockAspectRatio(opts->lockAspectRatio); m_display->filter(opts->resampleVideo); @@ -1239,6 +1252,16 @@ void Window::setupMenu(QMenuBar* menubar) { m_inputController.setAllowOpposing(value.toBool()); }, this); + ConfigOption* saveStateExtdata = m_config->addOption("saveStateExtdata"); + saveStateExtdata->connect([this](const QVariant& value) { + m_controller->setSaveStateExtdata(value.toInt()); + }, this); + + ConfigOption* loadStateExtdata = m_config->addOption("loadStateExtdata"); + loadStateExtdata->connect([this](const QVariant& value) { + m_controller->setLoadStateExtdata(value.toInt()); + }, this); + QAction* exitFullScreen = new QAction(tr("Exit fullscreen"), frameMenu); connect(exitFullScreen, SIGNAL(triggered()), this, SLOT(exitFullScreen())); exitFullScreen->setShortcut(QKeySequence("Esc"));