From f50f98416bc9e5455b71732a6727eda9bf8d6064 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Mon, 13 Jul 2015 21:56:05 -0700 Subject: [PATCH] Qt: Add savestate load undo --- CHANGES | 1 + src/platform/qt/GameController.cpp | 24 ++++++++++++++++++++++++ src/platform/qt/GameController.h | 3 +++ src/platform/qt/Window.cpp | 10 ++++++++-- 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 8c8f164c1..6c4170f45 100644 --- a/CHANGES +++ b/CHANGES @@ -24,6 +24,7 @@ Features: - Preliminary support for yanking out the game pak while a game is running - Thumb-drive mode by putting a file called portable.ini in the same folder - Configurable display driver, between software and OpenGL + - Undo-able savestate loading Bugfixes: - ARM7: Fix SWI and IRQ timings - GBA Audio: Force audio FIFOs to 32-bit diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index 24cd47ab2..d7dc24c4f 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -51,6 +51,8 @@ GameController::GameController(QObject* parent) , m_inputController(nullptr) , m_multiplayer(nullptr) , m_stateSlot(1) + , m_backupLoadState(nullptr) + , m_backupSaveState(nullptr) { m_renderer = new GBAVideoSoftwareRenderer; GBAVideoSoftwareRendererCreate(m_renderer); @@ -162,6 +164,7 @@ GameController::~GameController() { GBACheatDeviceDestroy(&m_cheatDevice); delete m_renderer; delete[] m_drawContext; + delete m_backupLoadState; } void GameController::setMultiplayerController(MultiplayerController* controller) { @@ -561,6 +564,10 @@ void GameController::loadState(int slot) { } GBARunOnThread(&m_threadContext, [](GBAThread* context) { GameController* controller = static_cast(context->userData); + if (!controller->m_backupLoadState) { + controller->m_backupLoadState = new GBASerializedState; + } + GBASerialize(context->gba, controller->m_backupLoadState); if (GBALoadState(context, context->stateDir, controller->m_stateSlot)) { controller->frameAvailable(controller->m_drawContext); controller->stateLoaded(context); @@ -578,6 +585,23 @@ void GameController::saveState(int slot) { }); } +void GameController::loadBackupState() { + if (!m_backupLoadState) { + return; + } + + GBARunOnThread(&m_threadContext, [](GBAThread* context) { + GameController* controller = static_cast(context->userData); + if (GBADeserialize(context->gba, controller->m_backupLoadState)) { + GBALog(context->gba, GBA_LOG_STATUS, "Undid state load"); + controller->frameAvailable(controller->m_drawContext); + controller->stateLoaded(context); + } + delete controller->m_backupLoadState; + controller->m_backupLoadState = nullptr; + }); +} + void GameController::setVideoSync(bool set) { m_videoSync = set; if (!m_turbo) { diff --git a/src/platform/qt/GameController.h b/src/platform/qt/GameController.h index 349a39ce6..6160a6818 100644 --- a/src/platform/qt/GameController.h +++ b/src/platform/qt/GameController.h @@ -120,6 +120,7 @@ public slots: void setFPSTarget(float fps); void loadState(int slot = 0); void saveState(int slot = 0); + void loadBackupState(); void setVideoSync(bool); void setAudioSync(bool); void setFrameskip(int); @@ -192,6 +193,8 @@ private: bool m_wasPaused; int m_stateSlot; + GBASerializedState* m_backupLoadState; + GBASerializedState* m_backupSaveState; // TODO: Use this InputController* m_inputController; MultiplayerController* m_multiplayer; diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 71f5e02d4..d49eaeace 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -697,6 +697,14 @@ void Window::setupMenu(QMenuBar* menubar) { m_gameActions.append(quickSave); addControlledAction(quickSaveMenu, quickSave, "quickSave"); + quickLoadMenu->addSeparator(); + + QAction* undoLoadState = new QAction(tr("Undo load state"), quickLoadMenu); + undoLoadState->setShortcut(tr("F11")); + connect(undoLoadState, SIGNAL(triggered()), m_controller, SLOT(loadBackupState())); + m_gameActions.append(undoLoadState); + addControlledAction(quickLoadMenu, undoLoadState, "undoLoadState"); + quickLoadMenu->addSeparator(); quickSaveMenu->addSeparator(); @@ -961,14 +969,12 @@ void Window::setupMenu(QMenuBar* menubar) { #ifdef USE_FFMPEG QAction* recordOutput = new QAction(tr("Record output..."), avMenu); - recordOutput->setShortcut(tr("F11")); connect(recordOutput, SIGNAL(triggered()), this, SLOT(openVideoWindow())); addControlledAction(avMenu, recordOutput, "recordOutput"); #endif #ifdef USE_MAGICK QAction* recordGIF = new QAction(tr("Record GIF..."), avMenu); - recordGIF->setShortcut(tr("Shift+F11")); connect(recordGIF, SIGNAL(triggered()), this, SLOT(openGIFWindow())); addControlledAction(avMenu, recordGIF, "recordGIF"); #endif