View
@@ -47,10 +47,18 @@ AudioProcessor::AudioProcessor(QObject* parent)
{
}
-void AudioProcessor::setInput(mCoreThread* input) {
+AudioProcessor::~AudioProcessor() {
+ stop();
+}
+
+void AudioProcessor::setInput(std::shared_ptr<CoreController> input) {
m_context = input;
}
+void AudioProcessor::stop() {
+ m_context.reset();
+}
+
void AudioProcessor::setBufferSamples(int samples) {
m_samples = samples;
}
View
@@ -7,6 +7,10 @@
#define QGBA_AUDIO_PROCESSOR
#include <QObject>
+#include <memory>
+
+#include "CoreController.h"
+
struct mCoreThread;
namespace QGBA {
@@ -28,12 +32,14 @@ Q_OBJECT
static void setDriver(Driver driver) { s_driver = driver; }
AudioProcessor(QObject* parent = nullptr);
+ ~AudioProcessor();
int getBufferSamples() const { return m_samples; }
virtual unsigned sampleRate() const = 0;
public slots:
- virtual void setInput(mCoreThread* input);
+ virtual void setInput(std::shared_ptr<CoreController>);
+ virtual void stop();
virtual bool start() = 0;
virtual void pause() = 0;
@@ -44,10 +50,10 @@ public slots:
virtual void requestSampleRate(unsigned) = 0;
protected:
- mCoreThread* input() { return m_context; }
+ mCoreThread* input() { return m_context->thread(); }
private:
- mCoreThread* m_context = nullptr;
+ std::shared_ptr<CoreController> m_context;
int m_samples = 2048;
static Driver s_driver;
};
View
@@ -20,24 +20,32 @@ AudioProcessorQt::AudioProcessorQt(QObject* parent)
{
}
-void AudioProcessorQt::setInput(mCoreThread* input) {
- AudioProcessor::setInput(input);
+void AudioProcessorQt::setInput(std::shared_ptr<CoreController> controller) {
+ AudioProcessor::setInput(controller);
if (m_device) {
- m_device->setInput(input);
+ m_device->setInput(input());
if (m_audioOutput) {
m_device->setFormat(m_audioOutput->format());
}
}
}
+void AudioProcessorQt::stop() {
+ if (m_device) {
+ m_device.reset();
+ }
+ pause();
+ AudioProcessor::stop();
+}
+
bool AudioProcessorQt::start() {
if (!input()) {
LOG(QT, WARN) << tr("Can't start an audio processor without input");
return false;
}
if (!m_device) {
- m_device = new AudioDevice(this);
+ m_device = std::make_unique<AudioDevice>(this);
}
if (!m_audioOutput) {
@@ -56,7 +64,7 @@ bool AudioProcessorQt::start() {
m_device->setInput(input());
m_device->setFormat(m_audioOutput->format());
- m_audioOutput->start(m_device);
+ m_audioOutput->start(m_device.get());
return m_audioOutput->state() == QAudio::ActiveState;
}
View
@@ -22,7 +22,8 @@ Q_OBJECT
virtual unsigned sampleRate() const override;
public slots:
- virtual void setInput(mCoreThread* input) override;
+ virtual void setInput(std::shared_ptr<CoreController> input) override;
+ virtual void stop() override;
virtual bool start() override;
virtual void pause() override;
@@ -33,7 +34,7 @@ public slots:
private:
QAudioOutput* m_audioOutput = nullptr;
- AudioDevice* m_device = nullptr;
+ std::unique_ptr<AudioDevice> m_device;
unsigned m_sampleRate = 44100;
};
View
@@ -16,18 +16,19 @@ AudioProcessorSDL::AudioProcessorSDL(QObject* parent)
{
}
-AudioProcessorSDL::~AudioProcessorSDL() {
- mSDLDeinitAudio(&m_audio);
-}
-
-void AudioProcessorSDL::setInput(mCoreThread* input) {
- AudioProcessor::setInput(input);
- if (m_audio.core && input->core != m_audio.core) {
+void AudioProcessorSDL::setInput(std::shared_ptr<CoreController> controller) {
+ AudioProcessor::setInput(controller);
+ if (m_audio.core && input()->core != m_audio.core) {
mSDLDeinitAudio(&m_audio);
- mSDLInitAudio(&m_audio, input);
+ mSDLInitAudio(&m_audio, input());
}
}
+void AudioProcessorSDL::stop() {
+ mSDLDeinitAudio(&m_audio);
+ AudioProcessor::stop();
+}
+
bool AudioProcessorSDL::start() {
if (!input()) {
LOG(QT, WARN) << tr("Can't start an audio processor without input");
@@ -51,21 +52,25 @@ void AudioProcessorSDL::pause() {
void AudioProcessorSDL::setBufferSamples(int samples) {
AudioProcessor::setBufferSamples(samples);
- m_audio.samples = samples;
- if (m_audio.core) {
- mSDLDeinitAudio(&m_audio);
- mSDLInitAudio(&m_audio, input());
+ if (m_audio.samples != samples) {
+ m_audio.samples = samples;
+ if (m_audio.core) {
+ mSDLDeinitAudio(&m_audio);
+ mSDLInitAudio(&m_audio, input());
+ }
}
}
void AudioProcessorSDL::inputParametersChanged() {
}
void AudioProcessorSDL::requestSampleRate(unsigned rate) {
- m_audio.sampleRate = rate;
- if (m_audio.core) {
- mSDLDeinitAudio(&m_audio);
- mSDLInitAudio(&m_audio, input());
+ if (m_audio.sampleRate != rate) {
+ m_audio.sampleRate = rate;
+ if (m_audio.core) {
+ mSDLDeinitAudio(&m_audio);
+ mSDLInitAudio(&m_audio, input());
+ }
}
}
View
@@ -18,12 +18,12 @@ Q_OBJECT
public:
AudioProcessorSDL(QObject* parent = nullptr);
- ~AudioProcessorSDL();
virtual unsigned sampleRate() const override;
public slots:
- virtual void setInput(mCoreThread* input) override;
+ virtual void setInput(std::shared_ptr<CoreController> input) override;
+ virtual void stop() override;
virtual bool start() override;
virtual void pause() override;
View
@@ -1,6 +1,6 @@
-if(NOT MSVC)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
-endif()
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7")
@@ -67,12 +67,13 @@ set(SOURCE_FILES
CheatsModel.cpp
CheatsView.cpp
ConfigController.cpp
+ CoreManager.cpp
+ CoreController.cpp
Display.cpp
DisplayGL.cpp
DisplayQt.cpp
GBAApp.cpp
GIFView.cpp
- GameController.cpp
GamepadAxisEvent.cpp
GamepadButtonEvent.cpp
GamepadHatEvent.cpp
@@ -282,7 +283,7 @@ if(APPLE)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
get_target_property(QTCOCOA Qt5::QCocoaIntegrationPlugin LOCATION)
get_target_property(COREAUDIO Qt5::CoreAudioPlugin LOCATION)
- get_target_property(BUNDLE_PATH ${BINARY_NAME}-qt LOCATION)
+ set(BUNDLE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.app)
target_sources(${BINARY_NAME}-qt PRIVATE "${PLUGINS}")
set_source_files_properties("${QTCOCOA}" PROPERTIES MACOSX_PACKAGE_LOCATION Contents/PlugIns)
set_source_files_properties("${COREAUDIO}" PROPERTIES MACOSX_PACKAGE_LOCATION Contents/PlugIns)
View
@@ -6,7 +6,7 @@
#include "CheatsView.h"
#include "GBAApp.h"
-#include "GameController.h"
+#include "CoreController.h"
#include <QClipboard>
#include <QPushButton>
@@ -21,7 +21,7 @@
using namespace QGBA;
-CheatsView::CheatsView(GameController* controller, QWidget* parent)
+CheatsView::CheatsView(std::shared_ptr<CoreController> controller, QWidget* parent)
: QWidget(parent)
, m_controller(controller)
, m_model(controller->cheatDevice())
@@ -35,8 +35,8 @@ CheatsView::CheatsView(GameController* controller, QWidget* parent)
connect(m_ui.save, &QPushButton::clicked, this, &CheatsView::save);
connect(m_ui.addSet, &QPushButton::clicked, this, &CheatsView::addSet);
connect(m_ui.remove, &QPushButton::clicked, this, &CheatsView::removeSet);
- connect(controller, &GameController::gameStopped, this, &CheatsView::close);
- connect(controller, &GameController::stateLoaded, &m_model, &CheatsModel::invalidated);
+ connect(controller.get(), &CoreController::stopping, this, &CheatsView::close);
+ connect(controller.get(), &CoreController::stateLoaded, &m_model, &CheatsModel::invalidated);
QPushButton* add;
switch (controller->platform()) {
@@ -123,7 +123,7 @@ void CheatsView::save() {
}
void CheatsView::addSet() {
- GameController::Interrupter interrupter(m_controller);
+ CoreController::Interrupter interrupter(m_controller);
mCheatSet* set = m_controller->cheatDevice()->createSet(m_controller->cheatDevice(), nullptr);
m_model.addSet(set);
}
@@ -134,7 +134,7 @@ void CheatsView::removeSet() {
if (selection.count() < 1) {
return;
}
- GameController::Interrupter interrupter(m_controller);
+ CoreController::Interrupter interrupter(m_controller);
for (const QModelIndex& index : selection) {
m_model.removeAt(selection[0]);
}
@@ -154,7 +154,7 @@ void CheatsView::enterCheat(int codeType) {
if (!set) {
return;
}
- m_controller->threadInterrupt();
+ CoreController::Interrupter interrupter(m_controller);
if (selection.count() == 0) {
m_model.addSet(set);
index = m_model.index(m_model.rowCount() - 1, 0, QModelIndex());
@@ -167,6 +167,5 @@ void CheatsView::enterCheat(int codeType) {
m_model.endAppendRow();
}
set->refresh(set, m_controller->cheatDevice());
- m_controller->threadContinue();
m_ui.codeEntry->clear();
}
View
@@ -9,6 +9,7 @@
#include <QWidget>
#include <functional>
+#include <memory>
#include "CheatsModel.h"
@@ -18,13 +19,13 @@ struct mCheatDevice;
namespace QGBA {
-class GameController;
+class CoreController;
class CheatsView : public QWidget {
Q_OBJECT
public:
- CheatsView(GameController* controller, QWidget* parent = nullptr);
+ CheatsView(std::shared_ptr<CoreController> controller, QWidget* parent = nullptr);
virtual bool eventFilter(QObject*, QEvent*) override;
@@ -38,7 +39,7 @@ private slots:
void enterCheat(int codeType);
Ui::CheatsView m_ui;
- GameController* m_controller;
+ std::shared_ptr<CoreController> m_controller;
CheatsModel m_model;
};
View
@@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ConfigController.h"
-#include "GameController.h"
+#include "CoreController.h"
#include <QAction>
#include <QDir>
@@ -98,8 +98,8 @@ ConfigController::ConfigController(QObject* parent)
mCoreConfigInit(&m_config, PORT);
- m_opts.audioSync = GameController::AUDIO_SYNC;
- m_opts.videoSync = GameController::VIDEO_SYNC;
+ m_opts.audioSync = CoreController::AUDIO_SYNC;
+ m_opts.videoSync = CoreController::VIDEO_SYNC;
m_opts.fpsTarget = 60;
m_opts.audioBuffers = 1536;
m_opts.sampleRate = 44100;
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -0,0 +1,194 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef QGBA_CORE_CONTROLLER
+#define QGBA_CORE_CONTROLLER
+
+#include <QByteArray>
+#include <QList>
+#include <QMutex>
+#include <QObject>
+#include <QSize>
+
+#include "VFileDevice.h"
+
+#include <functional>
+#include <memory>
+
+#include <mgba/core/core.h>
+#include <mgba/core/interface.h>
+#include <mgba/core/thread.h>
+#include <mgba/core/tile-cache.h>
+
+struct mCore;
+
+namespace QGBA {
+
+class ConfigController;
+class InputController;
+class LogController;
+class MultiplayerController;
+class Override;
+
+class CoreController : public QObject {
+Q_OBJECT
+
+public:
+ static const bool VIDEO_SYNC = false;
+ static const bool AUDIO_SYNC = true;
+
+ class Interrupter {
+ public:
+ Interrupter(CoreController*, bool fromThread = false);
+ Interrupter(std::shared_ptr<CoreController>, bool fromThread = false);
+ Interrupter(const Interrupter&);
+ ~Interrupter();
+
+ private:
+ CoreController* m_parent;
+ };
+
+ CoreController(mCore* core, QObject* parent = nullptr);
+ ~CoreController();
+
+ mCoreThread* thread() { return &m_threadContext; }
+
+ color_t* drawContext();
+
+ bool isPaused();
+
+ mPlatform platform() const;
+ QSize screenDimensions() const;
+ QPair<unsigned, unsigned> frameRate() const;
+
+ void loadConfig(ConfigController*);
+
+ mCheatDevice* cheatDevice() { return m_threadContext.core->cheatDevice(m_threadContext.core); }
+
+#ifdef USE_DEBUGGERS
+ mDebugger* debugger() { return m_threadContext.core->debugger; }
+ void setDebugger(mDebugger*);
+#endif
+
+ void setMultiplayerController(MultiplayerController*);
+ void clearMultiplayerController();
+ MultiplayerController* multiplayerController() { return m_multiplayer; }
+
+ mTileCache* tileCache();
+ int stateSlot() const { return m_stateSlot; }
+
+ void setOverride(std::unique_ptr<Override> override);
+ Override* override() { return m_override.get(); }
+
+ void setInputController(InputController*);
+ void setLogger(LogController*);
+
+public slots:
+ void start();
+ void stop();
+ void reset();
+ void setPaused(bool paused);
+ void frameAdvance();
+ void setSync(bool enable);
+
+ void setRewinding(bool);
+ void rewind(int count = 0);
+
+ void setFastForward(bool);
+ void forceFastForward(bool);
+
+ void loadState(int slot = 0);
+ void saveState(int slot = 0);
+ void loadBackupState();
+ void saveBackupState();
+
+ void loadSave(const QString&, bool temporary);
+ void loadPatch(const QString&);
+ void replaceGame(const QString&);
+ void yankPak();
+
+#ifdef USE_PNG
+ void screenshot();
+#endif
+
+ void setRealTime();
+ void setFixedTime(const QDateTime& time);
+ void setFakeEpoch(const QDateTime& time);
+
+ void importSharkport(const QString& path);
+ void exportSharkport(const QString& path);
+
+ void setAVStream(mAVStream*);
+ void clearAVStream();
+
+ void clearOverride();
+
+ void startVideoLog(const QString& path);
+ void endVideoLog();
+
+signals:
+ void started();
+ void paused();
+ void unpaused();
+ void stopping();
+ void crashed(const QString& errorMessage);
+ void failed();
+ void frameAvailable();
+ void stateLoaded();
+ void rewound();
+
+ void rewindChanged(bool);
+ void fastForwardChanged(bool);
+
+ void unimplementedBiosCall(int);
+ void statusPosted(const QString& message);
+ void logPosted(int level, int category, const QString& log);
+
+private:
+ void updateKeys();
+ void finishFrame();
+
+ void updateFastForward();
+
+ mCoreThread m_threadContext{};
+
+ bool m_patched = false;
+
+ QByteArray m_buffers[2];
+ QByteArray* m_activeBuffer;
+ QByteArray* m_completeBuffer = nullptr;
+
+ std::unique_ptr<mTileCache> m_tileCache;
+ std::unique_ptr<Override> m_override;
+
+ QList<std::function<void()>> m_resetActions;
+ QList<std::function<void()>> m_frameActions;
+ QMutex m_mutex;
+
+ VFileDevice m_backupLoadState;
+ QByteArray m_backupSaveState{nullptr};
+ int m_stateSlot = 1;
+ int m_loadStateFlags;
+ int m_saveStateFlags;
+
+ bool m_audioSync = AUDIO_SYNC;
+ bool m_videoSync = VIDEO_SYNC;
+
+ int m_fastForward = false;
+ int m_fastForwardForced = false;
+ float m_fastForwardRatio = -1.f;
+ float m_fpsTarget;
+
+ InputController* m_inputController = nullptr;
+ LogController* m_log = nullptr;
+ MultiplayerController* m_multiplayer = nullptr;
+
+ mVideoLogContext* m_vl = nullptr;
+ VFile* m_vlVf = nullptr;
+};
+
+}
+
+#endif
View
@@ -0,0 +1,165 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "CoreManager.h"
+
+#include "CoreController.h"
+#include "LogController.h"
+
+#include <QDir>
+
+#ifdef M_CORE_GBA
+#include <mgba/gba/core.h>
+#endif
+
+#include <mgba/core/core.h>
+#include <mgba-util/vfs.h>
+
+using namespace QGBA;
+
+void CoreManager::setConfig(const mCoreConfig* config) {
+ m_config = config;
+}
+
+void CoreManager::setMultiplayerController(MultiplayerController* multiplayer) {
+ m_multiplayer = multiplayer;
+}
+
+CoreController* CoreManager::loadGame(const QString& path) {
+ QFileInfo info(path);
+ if (!info.isReadable()) {
+ QString fname = info.fileName();
+ QString base = info.path();
+ if (base.endsWith("/") || base.endsWith(QDir::separator())) {
+ base.chop(1);
+ }
+ VDir* dir = VDirOpenArchive(base.toUtf8().constData());
+ if (dir) {
+ VFile* vf = dir->openFile(dir, fname.toUtf8().constData(), O_RDONLY);
+ if (vf) {
+ struct VFile* vfclone = VFileMemChunk(NULL, vf->size(vf));
+ uint8_t buffer[2048];
+ ssize_t read;
+ while ((read = vf->read(vf, buffer, sizeof(buffer))) > 0) {
+ vfclone->write(vfclone, buffer, read);
+ }
+ vf->close(vf);
+ vf = vfclone;
+ }
+ dir->close(dir);
+ loadGame(vf, fname, base);
+ } else {
+ LOG(QT, ERROR) << tr("Failed to open game file: %1").arg(path);
+ }
+ return nullptr;
+ }
+ VFile* vf = nullptr;
+ VDir* archive = VDirOpenArchive(path.toUtf8().constData());
+ if (archive) {
+ VFile* vfOriginal = VDirFindFirst(archive, [](VFile* vf) {
+ return mCoreIsCompatible(vf) != PLATFORM_NONE;
+ });
+ ssize_t size;
+ if (vfOriginal && (size = vfOriginal->size(vfOriginal)) > 0) {
+ void* mem = vfOriginal->map(vfOriginal, size, MAP_READ);
+ vf = VFileMemChunk(mem, size);
+ vfOriginal->unmap(vfOriginal, mem, (size_t) read);
+ vfOriginal->close(vfOriginal);
+ }
+ }
+ QDir dir(info.dir());
+ if (!vf) {
+ vf = VFileOpen(info.canonicalFilePath().toUtf8().constData(), O_RDONLY);
+ }
+ return loadGame(vf, info.fileName(), dir.canonicalPath());
+}
+
+CoreController* CoreManager::loadGame(VFile* vf, const QString& path, const QString& base) {
+ if (!vf) {
+ return nullptr;
+ }
+
+ mCore* core = mCoreFindVF(vf);
+ if (!core) {
+ return nullptr;
+ }
+
+ core->init(core);
+ mCoreInitConfig(core, nullptr);
+
+ if (m_config) {
+ mCoreLoadForeignConfig(core, m_config);
+ }
+
+ if (m_preload) {
+ mCorePreloadVF(core, vf);
+ } else {
+ core->loadROM(core, vf);
+ }
+
+ QFileInfo info(base + "/" + path);
+ QByteArray bytes(info.baseName().toUtf8());
+ strncpy(core->dirs.baseName, bytes.constData(), sizeof(core->dirs.baseName));
+
+ bytes = info.dir().canonicalPath().toUtf8();
+ mDirectorySetAttachBase(&core->dirs, VDirOpen(bytes.constData()));
+ mCoreAutoloadSave(core);
+
+ CoreController* cc = new CoreController(core);
+ if (m_multiplayer) {
+ cc->setMultiplayerController(m_multiplayer);
+ }
+ emit coreLoaded(cc);
+ return cc;
+}
+
+CoreController* CoreManager::loadBIOS(int platform, const QString& path) {
+ QFileInfo info(path);
+ VFile* vf = VFileOpen(info.canonicalFilePath().toUtf8().constData(), O_RDONLY);
+ if (!vf) {
+ return nullptr;
+ }
+
+ mCore* core = nullptr;
+ switch (platform) {
+#ifdef M_CORE_GBA
+ case PLATFORM_GBA:
+ core = GBACoreCreate();
+ break;
+#endif
+ default:
+ vf->close(vf);
+ return nullptr;
+ }
+ if (!core) {
+ vf->close(vf);
+ return nullptr;
+ }
+
+ core->init(core);
+ mCoreInitConfig(core, nullptr);
+
+ if (m_config) {
+ mCoreLoadForeignConfig(core, m_config);
+ }
+
+ core->loadBIOS(core, vf, 0);
+
+ mCoreConfigSetOverrideIntValue(&core->config, "useBios", 1);
+ mCoreConfigSetOverrideIntValue(&core->config, "skipBios", 0);
+
+ QByteArray bytes(info.baseName().toUtf8());
+ strncpy(core->dirs.baseName, bytes.constData(), sizeof(core->dirs.baseName));
+
+ bytes = info.dir().canonicalPath().toUtf8();
+ mDirectorySetAttachBase(&core->dirs, VDirOpen(bytes.constData()));
+
+ CoreController* cc = new CoreController(core);
+ if (m_multiplayer) {
+ cc->setMultiplayerController(m_multiplayer);
+ }
+ emit coreLoaded(cc);
+ return cc;
+}
View
@@ -0,0 +1,45 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef QGBA_CORE_MANAGER
+#define QGBA_CORE_MANAGER
+
+#include <QFileInfo>
+#include <QObject>
+#include <QString>
+
+struct mCoreConfig;
+struct VFile;
+
+namespace QGBA {
+
+class CoreController;
+class MultiplayerController;
+
+class CoreManager : public QObject {
+Q_OBJECT
+
+public:
+ void setConfig(const mCoreConfig*);
+ void setMultiplayerController(MultiplayerController*);
+ void setPreload(bool preload) { m_preload = preload; }
+
+public slots:
+ CoreController* loadGame(const QString& path);
+ CoreController* loadGame(VFile* vf, const QString& path, const QString& base);
+ CoreController* loadBIOS(int platform, const QString& path);
+
+signals:
+ void coreLoaded(CoreController*);
+
+private:
+ const mCoreConfig* m_config = nullptr;
+ MultiplayerController* m_multiplayer = nullptr;
+ bool m_preload = false;
+};
+
+}
+
+#endif
View
@@ -5,16 +5,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DebuggerConsoleController.h"
-#include "GameController.h"
+#include "CoreController.h"
#include <QMutexLocker>
#include <mgba/internal/debugger/cli-debugger.h>
using namespace QGBA;
-DebuggerConsoleController::DebuggerConsoleController(GameController* controller, QObject* parent)
- : DebuggerController(controller, &m_cliDebugger.d, parent)
+DebuggerConsoleController::DebuggerConsoleController(QObject* parent)
+ : DebuggerController(&m_cliDebugger.d, parent)
{
m_backend.d.printf = printf;
m_backend.d.init = init;
@@ -39,8 +39,10 @@ void DebuggerConsoleController::enterLine(const QString& line) {
}
void DebuggerConsoleController::detach() {
- m_lines.append(QString());
- m_cond.wakeOne();
+ if (m_cliDebugger.d.state != DEBUGGER_SHUTDOWN) {
+ m_lines.append(QString());
+ m_cond.wakeOne();
+ }
DebuggerController::detach();
}
@@ -68,14 +70,16 @@ void DebuggerConsoleController::init(struct CLIDebuggerBackend* be) {
void DebuggerConsoleController::deinit(struct CLIDebuggerBackend* be) {
Backend* consoleBe = reinterpret_cast<Backend*>(be);
DebuggerConsoleController* self = consoleBe->self;
- self->m_lines.append(QString());
- self->m_cond.wakeOne();
+ if (be->p->d.state != DEBUGGER_SHUTDOWN) {
+ self->m_lines.append(QString());
+ self->m_cond.wakeOne();
+ }
}
const char* DebuggerConsoleController::readLine(struct CLIDebuggerBackend* be, size_t* len) {
Backend* consoleBe = reinterpret_cast<Backend*>(be);
DebuggerConsoleController* self = consoleBe->self;
- GameController::Interrupter interrupter(self->m_gameController, true);
+ CoreController::Interrupter interrupter(self->m_gameController, true);
QMutexLocker lock(&self->m_mutex);
while (self->m_lines.isEmpty()) {
self->m_cond.wait(&self->m_mutex);
@@ -99,7 +103,7 @@ void DebuggerConsoleController::lineAppend(struct CLIDebuggerBackend* be, const
const char* DebuggerConsoleController::historyLast(struct CLIDebuggerBackend* be, size_t* len) {
Backend* consoleBe = reinterpret_cast<Backend*>(be);
DebuggerConsoleController* self = consoleBe->self;
- GameController::Interrupter interrupter(self->m_gameController, true);
+ CoreController::Interrupter interrupter(self->m_gameController, true);
QMutexLocker lock(&self->m_mutex);
if (self->m_history.isEmpty()) {
return "i";
@@ -111,7 +115,7 @@ const char* DebuggerConsoleController::historyLast(struct CLIDebuggerBackend* be
void DebuggerConsoleController::historyAppend(struct CLIDebuggerBackend* be, const char* line) {
Backend* consoleBe = reinterpret_cast<Backend*>(be);
DebuggerConsoleController* self = consoleBe->self;
- GameController::Interrupter interrupter(self->m_gameController, true);
+ CoreController::Interrupter interrupter(self->m_gameController, true);
QMutexLocker lock(&self->m_mutex);
self->m_history.append(QString::fromUtf8(line));
}
View
@@ -16,13 +16,13 @@
namespace QGBA {
-class GameController;
+class CoreController;
class DebuggerConsoleController : public DebuggerController {
Q_OBJECT
public:
- DebuggerConsoleController(GameController* controller, QObject* parent = nullptr);
+ DebuggerConsoleController(QObject* parent = nullptr);
signals:
void log(const QString&);
@@ -44,7 +44,7 @@ public slots:
static const char* historyLast(struct CLIDebuggerBackend* be, size_t* len);
static void historyAppend(struct CLIDebuggerBackend* be, const char* line);
- CLIDebugger m_cliDebugger;
+ CLIDebugger m_cliDebugger{};
QMutex m_mutex;
QWaitCondition m_cond;
View
@@ -5,32 +5,44 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GDBController.h"
-#include "GameController.h"
+#include "CoreController.h"
using namespace QGBA;
-DebuggerController::DebuggerController(GameController* controller, mDebugger* debugger, QObject* parent)
+DebuggerController::DebuggerController(mDebugger* debugger, QObject* parent)
: QObject(parent)
, m_debugger(debugger)
- , m_gameController(controller)
{
}
bool DebuggerController::isAttached() {
+ if (!m_gameController) {
+ return false;
+ }
return m_gameController->debugger() == m_debugger;
}
+void DebuggerController::setController(std::shared_ptr<CoreController> controller) {
+ if (m_gameController && controller != m_gameController) {
+ m_gameController->disconnect(this);
+ detach();
+ }
+ m_gameController = controller;
+ if (controller) {
+ connect(m_gameController.get(), &CoreController::stopping, [this]() {
+ setController(nullptr);
+ });
+ }
+}
+
void DebuggerController::attach() {
if (isAttached()) {
return;
}
- if (m_gameController->isLoaded()) {
+ if (m_gameController) {
attachInternal();
m_gameController->setDebugger(m_debugger);
mDebuggerEnter(m_debugger, DEBUGGER_ENTER_ATTACHED, 0);
- } else {
- QObject::disconnect(m_autoattach);
- m_autoattach = connect(m_gameController, &GameController::gameStarted, this, &DebuggerController::attach);
}
}
@@ -39,16 +51,18 @@ void DebuggerController::detach() {
if (!isAttached()) {
return;
}
- GameController::Interrupter interrupter(m_gameController);
- shutdownInternal();
- m_gameController->setDebugger(nullptr);
+ if (m_gameController) {
+ CoreController::Interrupter interrupter(m_gameController);
+ shutdownInternal();
+ m_gameController->setDebugger(nullptr);
+ }
}
void DebuggerController::breakInto() {
if (!isAttached()) {
return;
}
- GameController::Interrupter interrupter(m_gameController);
+ CoreController::Interrupter interrupter(m_gameController);
mDebuggerEnter(m_debugger, DEBUGGER_ENTER_MANUAL, 0);
}
@@ -57,7 +71,7 @@ void DebuggerController::shutdown() {
if (!isAttached()) {
return;
}
- GameController::Interrupter interrupter(m_gameController);
+ CoreController::Interrupter interrupter(m_gameController);
shutdownInternal();
}
View
@@ -8,20 +8,23 @@
#include <QObject>
+#include <memory>
+
struct mDebugger;
namespace QGBA {
-class GameController;
+class CoreController;
class DebuggerController : public QObject {
Q_OBJECT
public:
- DebuggerController(GameController* controller, mDebugger* debugger, QObject* parent = nullptr);
+ DebuggerController(mDebugger* debugger, QObject* parent = nullptr);
public:
bool isAttached();
+ void setController(std::shared_ptr<CoreController>);
public slots:
virtual void attach();
@@ -34,7 +37,7 @@ public slots:
virtual void shutdownInternal();
mDebugger* const m_debugger;
- GameController* const m_gameController;
+ std::shared_ptr<CoreController> m_gameController;
private:
QMetaObject::Connection m_autoattach;
View
@@ -8,16 +8,19 @@
#include <mgba-util/common.h>
+#include <memory>
+
#include <QWidget>
#include "MessagePainter.h"
-struct mCoreThread;
struct VDir;
struct VideoShader;
namespace QGBA {
+class CoreController;
+
class Display : public QWidget {
Q_OBJECT
@@ -41,6 +44,7 @@ Q_OBJECT
bool isIntegerScalingLocked() const { return m_lockIntegerScaling; }
bool isFiltered() const { return m_filter; }
+ virtual void startDrawing(std::shared_ptr<CoreController>) = 0;
virtual bool isDrawing() const = 0;
virtual bool supportsShaders() const = 0;
virtual VideoShader* shaders() = 0;
@@ -52,15 +56,14 @@ Q_OBJECT
void hideCursor();
public slots:
- virtual void startDrawing(mCoreThread* context) = 0;
virtual void stopDrawing() = 0;
virtual void pauseDrawing() = 0;
virtual void unpauseDrawing() = 0;
virtual void forceDraw() = 0;
virtual void lockAspectRatio(bool lock);
virtual void lockIntegerScaling(bool lock);
virtual void filter(bool filter);
- virtual void framePosted(const uint32_t*) = 0;
+ virtual void framePosted() = 0;
virtual void setShaders(struct VDir*) = 0;
virtual void clearShaders() = 0;
View
@@ -7,12 +7,13 @@
#if defined(BUILD_GL) || defined(BUILD_GLES)
+#include "CoreController.h"
+
#include <QApplication>
#include <QResizeEvent>
#include <QTimer>
#include <mgba/core/core.h>
-#include <mgba/core/thread.h>
#ifdef BUILD_GL
#include "platform/opengl/gl.h"
#endif
@@ -52,14 +53,17 @@ VideoShader* DisplayGL::shaders() {
return shaders;
}
-void DisplayGL::startDrawing(mCoreThread* thread) {
+void DisplayGL::startDrawing(std::shared_ptr<CoreController> controller) {
if (m_drawThread) {
return;
}
+ QSize dims = controller->screenDimensions();
+ setSystemDimensions(dims.width(), dims.height());
+
m_isDrawing = true;
- m_painter->setContext(thread);
+ m_painter->setContext(controller);
m_painter->setMessagePainter(messagePainter());
- m_context = thread;
+ m_context = controller;
m_painter->resize(size());
m_gl->move(0, 0);
m_drawThread = new QThread(this);
@@ -69,15 +73,10 @@ void DisplayGL::startDrawing(mCoreThread* thread) {
m_painter->moveToThread(m_drawThread);
connect(m_drawThread, &QThread::started, m_painter, &PainterGL::start);
m_drawThread->start();
- mCoreSyncSetVideoSync(&m_context->impl->sync, false);
lockAspectRatio(isAspectRatioLocked());
lockIntegerScaling(isIntegerScalingLocked());
- unsigned width, height;
- thread->core->desiredVideoDimensions(thread->core, &width, &height);
- setSystemDimensions(width, height);
-
filter(isFiltered());
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
messagePainter()->resize(size(), isAspectRatioLocked(), devicePixelRatioF());
@@ -90,41 +89,27 @@ void DisplayGL::startDrawing(mCoreThread* thread) {
void DisplayGL::stopDrawing() {
if (m_drawThread) {
m_isDrawing = false;
- if (mCoreThreadIsActive(m_context)) {
- mCoreThreadInterrupt(m_context);
- }
+ CoreController::Interrupter interrupter(m_context);
QMetaObject::invokeMethod(m_painter, "stop", Qt::BlockingQueuedConnection);
m_drawThread->exit();
m_drawThread = nullptr;
- if (mCoreThreadIsActive(m_context)) {
- mCoreThreadContinue(m_context);
- }
}
+ m_context.reset();
}
void DisplayGL::pauseDrawing() {
if (m_drawThread) {
m_isDrawing = false;
- if (mCoreThreadIsActive(m_context)) {
- mCoreThreadInterrupt(m_context);
- }
+ CoreController::Interrupter interrupter(m_context);
QMetaObject::invokeMethod(m_painter, "pause", Qt::BlockingQueuedConnection);
- if (mCoreThreadIsActive(m_context)) {
- mCoreThreadContinue(m_context);
- }
}
}
void DisplayGL::unpauseDrawing() {
if (m_drawThread) {
m_isDrawing = true;
- if (mCoreThreadIsActive(m_context)) {
- mCoreThreadInterrupt(m_context);
- }
+ CoreController::Interrupter interrupter(m_context);
QMetaObject::invokeMethod(m_painter, "unpause", Qt::BlockingQueuedConnection);
- if (mCoreThreadIsActive(m_context)) {
- mCoreThreadContinue(m_context);
- }
}
}
@@ -155,9 +140,9 @@ void DisplayGL::filter(bool filter) {
}
}
-void DisplayGL::framePosted(const uint32_t* buffer) {
- if (m_drawThread && buffer) {
- m_painter->enqueue(buffer);
+void DisplayGL::framePosted() {
+ if (m_drawThread) {
+ m_painter->enqueue(m_context->drawContext());
QMetaObject::invokeMethod(m_painter, "draw");
}
}
@@ -188,12 +173,6 @@ void DisplayGL::resizePainter() {
PainterGL::PainterGL(int majorVersion, QGLWidget* parent)
: m_gl(parent)
- , m_active(false)
- , m_started(false)
- , m_context(nullptr)
- , m_shader{}
- , m_backend(nullptr)
- , m_messagePainter(nullptr)
{
#ifdef BUILD_GL
mGLContext* glBackend;
@@ -267,7 +246,7 @@ PainterGL::~PainterGL() {
m_backend = nullptr;
}
-void PainterGL::setContext(mCoreThread* context) {
+void PainterGL::setContext(std::shared_ptr<CoreController> context) {
m_context = context;
if (!context) {
@@ -278,9 +257,8 @@ void PainterGL::setContext(mCoreThread* context) {
#if defined(_WIN32) && defined(USE_EPOXY)
epoxy_handle_external_wglMakeCurrent();
#endif
- unsigned width, height;
- context->core->desiredVideoDimensions(context->core, &width, &height);
- m_backend->setDimensions(m_backend, width, height);
+ QSize size = m_context->screenDimensions();
+ m_backend->setDimensions(m_backend, size.width(), size.height());
m_gl->doneCurrent();
}
@@ -334,13 +312,13 @@ void PainterGL::start() {
}
void PainterGL::draw() {
- if (m_queue.isEmpty() || !mCoreThreadIsActive(m_context)) {
+ if (m_queue.isEmpty()) {
return;
}
- if (mCoreSyncWaitFrameStart(&m_context->impl->sync) || !m_queue.isEmpty()) {
+ if (mCoreSyncWaitFrameStart(&m_context->thread()->impl->sync) || !m_queue.isEmpty()) {
dequeue();
- mCoreSyncWaitFrameEnd(&m_context->impl->sync);
+ mCoreSyncWaitFrameEnd(&m_context->thread()->impl->sync);
m_painter.begin(m_gl->context()->device());
performDraw();
m_painter.end();
@@ -354,7 +332,7 @@ void PainterGL::draw() {
m_delayTimer.restart();
}
} else {
- mCoreSyncWaitFrameEnd(&m_context->impl->sync);
+ mCoreSyncWaitFrameEnd(&m_context->thread()->impl->sync);
}
if (!m_queue.isEmpty()) {
QMetaObject::invokeMethod(this, "draw", Qt::QueuedConnection);
@@ -380,6 +358,7 @@ void PainterGL::stop() {
m_backend->swap(m_backend);
m_gl->doneCurrent();
m_gl->context()->moveToThread(m_gl->thread());
+ m_context.reset();
moveToThread(m_gl->thread());
}
@@ -414,9 +393,8 @@ void PainterGL::enqueue(const uint32_t* backing) {
} else {
buffer = m_free.takeLast();
}
- unsigned width, height;
- m_context->core->desiredVideoDimensions(m_context->core, &width, &height);
- memcpy(buffer, backing, width * height * BYTES_PER_PIXEL);
+ QSize size = m_context->screenDimensions();
+ memcpy(buffer, backing, size.width() * size.height() * BYTES_PER_PIXEL);
m_queue.enqueue(buffer);
m_mutex.unlock();
}
View
@@ -46,20 +46,20 @@ Q_OBJECT
DisplayGL(const QGLFormat& format, QWidget* parent = nullptr);
~DisplayGL();
+ void startDrawing(std::shared_ptr<CoreController>) override;
bool isDrawing() const override { return m_isDrawing; }
bool supportsShaders() const override;
VideoShader* shaders() override;
public slots:
- void startDrawing(mCoreThread* context) override;
void stopDrawing() override;
void pauseDrawing() override;
void unpauseDrawing() override;
void forceDraw() override;
void lockAspectRatio(bool lock) override;
void lockIntegerScaling(bool lock) override;
void filter(bool filter) override;
- void framePosted(const uint32_t*) override;
+ void framePosted() override;
void setShaders(struct VDir*) override;
void clearShaders() override;
@@ -74,7 +74,7 @@ public slots:
QGLWidget* m_gl;
PainterGL* m_painter;
QThread* m_drawThread = nullptr;
- mCoreThread* m_context = nullptr;
+ std::shared_ptr<CoreController> m_context;
};
class PainterGL : public QObject {
@@ -84,7 +84,7 @@ Q_OBJECT
PainterGL(int majorVersion, QGLWidget* parent);
~PainterGL();
- void setContext(mCoreThread*);
+ void setContext(std::shared_ptr<CoreController>);
void setMessagePainter(MessagePainter*);
void enqueue(const uint32_t* backing);
@@ -116,14 +116,14 @@ public slots:
QPainter m_painter;
QMutex m_mutex;
QGLWidget* m_gl;
- bool m_active;
- bool m_started;
- mCoreThread* m_context;
+ bool m_active = false;
+ bool m_started = false;
+ std::shared_ptr<CoreController> m_context = nullptr;
bool m_supportsShaders;
- VideoShader m_shader;
- VideoBackend* m_backend;
+ VideoShader m_shader{};
+ VideoBackend* m_backend = nullptr;
QSize m_size;
- MessagePainter* m_messagePainter;
+ MessagePainter* m_messagePainter = nullptr;
QElapsedTimer m_delayTimer;
};
View
@@ -5,6 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DisplayQt.h"
+#include "CoreController.h"
+
#include <QPainter>
#include <mgba/core/core.h>
@@ -17,11 +19,19 @@ DisplayQt::DisplayQt(QWidget* parent)
{
}
-void DisplayQt::startDrawing(mCoreThread* context) {
- context->core->desiredVideoDimensions(context->core, &m_width, &m_height);
+void DisplayQt::startDrawing(std::shared_ptr<CoreController> controller) {
+ QSize size = controller->screenDimensions();
+ m_width = size.width();
+ m_height = size.height();
setSystemDimensions(m_width, m_height);
m_backing = std::move(QImage());
m_isDrawing = true;
+ m_context = controller;
+}
+
+void DisplayQt::stopDrawing() {
+ m_isDrawing = false;
+ m_context.reset();
}
void DisplayQt::lockAspectRatio(bool lock) {
@@ -39,8 +49,9 @@ void DisplayQt::filter(bool filter) {
update();
}
-void DisplayQt::framePosted(const uint32_t* buffer) {
+void DisplayQt::framePosted() {
update();
+ color_t* buffer = m_context->drawContext();
if (const_cast<const QImage&>(m_backing).bits() == reinterpret_cast<const uchar*>(buffer)) {
return;
}
View
@@ -19,20 +19,20 @@ Q_OBJECT
public:
DisplayQt(QWidget* parent = nullptr);
+ void startDrawing(std::shared_ptr<CoreController>) override;
bool isDrawing() const override { return m_isDrawing; }
bool supportsShaders() const override { return false; }
VideoShader* shaders() override { return nullptr; }
public slots:
- void startDrawing(mCoreThread* context) override;
- void stopDrawing() override { m_isDrawing = false; }
+ void stopDrawing() override;
void pauseDrawing() override { m_isDrawing = false; }
void unpauseDrawing() override { m_isDrawing = true; }
void forceDraw() override { update(); }
void lockAspectRatio(bool lock) override;
void lockIntegerScaling(bool lock) override;
void filter(bool filter) override;
- void framePosted(const uint32_t*) override;
+ void framePosted() override;
void setShaders(struct VDir*) override {}
void clearShaders() override {}
@@ -44,6 +44,7 @@ public slots:
unsigned m_width;
unsigned m_height;
QImage m_backing{nullptr};
+ std::shared_ptr<CoreController> m_context = nullptr;
};
}
View
@@ -6,9 +6,10 @@
#include "GBAApp.h"
#include "AudioProcessor.h"
+#include "CoreController.h"
+#include "CoreManager.h"
#include "ConfigController.h"
#include "Display.h"
-#include "GameController.h"
#include "Window.h"
#include "VFileDevice.h"
@@ -57,6 +58,9 @@ GBAApp::GBAApp(int& argc, char* argv[], ConfigController* config)
reloadGameDB();
+ m_manager.setConfig(m_configController->config());
+ m_manager.setMultiplayerController(&m_multiplayer);
+
if (!m_configController->getQtOption("audioDriver").isNull()) {
AudioProcessor::setDriver(static_cast<AudioProcessor::Driver>(m_configController->getQtOption("audioDriver").toInt()));
}
@@ -71,7 +75,8 @@ GBAApp::~GBAApp() {
bool GBAApp::event(QEvent* event) {
if (event->type() == QEvent::FileOpen) {
- m_windows[0]->controller()->loadGame(static_cast<QFileOpenEvent*>(event)->file());
+ CoreController* core = m_manager.loadGame(static_cast<QFileOpenEvent*>(event)->file());
+ m_windows[0]->setController(core, static_cast<QFileOpenEvent*>(event)->file());
return true;
}
return QApplication::event(event);
@@ -81,7 +86,7 @@ Window* GBAApp::newWindow() {
if (m_windows.count() >= MAX_GBAS) {
return nullptr;
}
- Window* w = new Window(m_configController, m_multiplayer.attached());
+ Window* w = new Window(&m_manager, m_configController, m_multiplayer.attached());
int windowId = m_multiplayer.attached();
connect(w, &Window::destroyed, [this, w]() {
m_windows.removeAll(w);
@@ -93,7 +98,6 @@ Window* GBAApp::newWindow() {
w->setAttribute(Qt::WA_DeleteOnClose);
w->loadConfig();
w->show();
- w->controller()->setMultiplayerController(&m_multiplayer);
w->multiplayerChanged();
for (Window* w : m_windows) {
w->updateMultiplayerStatus(m_windows.count() < MAX_GBAS);
@@ -107,7 +111,7 @@ GBAApp* GBAApp::app() {
void GBAApp::pauseAll(QList<Window*>* paused) {
for (auto& window : m_windows) {
- if (!window->controller()->isLoaded() || window->controller()->isPaused()) {
+ if (!window->controller() || window->controller()->isPaused()) {
continue;
}
window->controller()->setPaused(true);
@@ -117,7 +121,9 @@ void GBAApp::pauseAll(QList<Window*>* paused) {
void GBAApp::continueAll(const QList<Window*>& paused) {
for (auto& window : paused) {
- window->controller()->setPaused(false);
+ if (window->controller()) {
+ window->controller()->setPaused(false);
+ }
}
}
View
@@ -8,8 +8,12 @@
#include <QApplication>
#include <QFileDialog>
+#include <QList>
+#include <QObject>
+#include <QString>
#include <QThread>
+#include "CoreManager.h"
#include "MultiplayerController.h"
struct NoIntroDB;
@@ -70,6 +74,7 @@ Q_OBJECT
ConfigController* m_configController;
QList<Window*> m_windows;
MultiplayerController m_multiplayer;
+ CoreManager m_manager;
NoIntroDB* m_db = nullptr;
#ifdef USE_SQLITE3
View
@@ -5,12 +5,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GDBController.h"
-#include "GameController.h"
+#include "CoreController.h"
using namespace QGBA;
-GDBController::GDBController(GameController* controller, QObject* parent)
- : DebuggerController(controller, &m_gdbStub.d, parent)
+GDBController::GDBController(QObject* parent)
+ : DebuggerController(&m_gdbStub.d, parent)
, m_bindAddress({ IPV4, 0 })
{
GDBStubCreate(&m_gdbStub);
@@ -21,7 +21,7 @@ ushort GDBController::port() {
}
bool GDBController::isAttached() {
- return m_gameController->debugger() == &m_gdbStub.d;
+ return m_gameController && m_gameController->debugger() == &m_gdbStub.d;
}
void GDBController::setPort(ushort port) {
@@ -34,7 +34,7 @@ void GDBController::setBindAddress(uint32_t bindAddress) {
}
void GDBController::listen() {
- GameController::Interrupter interrupter(m_gameController);
+ CoreController::Interrupter interrupter(m_gameController);
if (!isAttached()) {
attach();
}
View
@@ -14,13 +14,13 @@
namespace QGBA {
-class GameController;
+class CoreController;
class GDBController : public DebuggerController {
Q_OBJECT
public:
- GDBController(GameController* controller, QObject* parent = nullptr);
+ GDBController(QObject* parent = nullptr);
public:
ushort port();
@@ -38,7 +38,7 @@ public slots:
private:
virtual void shutdownInternal() override;
- GDBStub m_gdbStub;
+ GDBStub m_gdbStub{};
ushort m_port = 2345;
Address m_bindAddress;
View
@@ -7,6 +7,7 @@
#ifdef USE_MAGICK
+#include "CoreController.h"
#include "GBAApp.h"
#include "LogController.h"
@@ -39,6 +40,12 @@ GIFView::~GIFView() {
stopRecording();
}
+void GIFView::setController(std::shared_ptr<CoreController> controller) {
+ connect(controller.get(), &CoreController::stopping, this, &GIFView::stopRecording);
+ connect(this, &GIFView::recordingStarted, controller.get(), &CoreController::setAVStream);
+ connect(this, &GIFView::recordingStopped, controller.get(), &CoreController::clearAVStream, Qt::DirectConnection);
+}
+
void GIFView::startRecording() {
int delayMs = m_ui.delayAuto->isChecked() ? -1 : m_ui.delayMs->value();
ImageMagickGIFEncoderSetParams(&m_encoder, m_ui.frameskip->value(), delayMs);
View
@@ -10,12 +10,16 @@
#include <QWidget>
+#include <memory>
+
#include "ui_GIFView.h"
#include "feature/imagemagick/imagemagick-gif-encoder.h"
namespace QGBA {
+class CoreController;
+
class GIFView : public QWidget {
Q_OBJECT
@@ -26,6 +30,8 @@ Q_OBJECT
mAVStream* getStream() { return &m_encoder.d; }
public slots:
+ void setController(std::shared_ptr<CoreController>);
+
void startRecording();
void stopRecording();
View
@@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "IOViewer.h"
-#include "GameController.h"
+#include "CoreController.h"
#include <QComboBox>
#include <QFontDatabase>
@@ -1023,7 +1023,7 @@ const QList<IOViewer::RegisterDescription>& IOViewer::registerDescriptions() {
return s_registers;
}
-IOViewer::IOViewer(GameController* controller, QWidget* parent)
+IOViewer::IOViewer(std::shared_ptr<CoreController> controller, QWidget* parent)
: QDialog(parent)
, m_controller(controller)
{
@@ -1067,16 +1067,17 @@ IOViewer::IOViewer(GameController* controller, QWidget* parent)
}
selectRegister(0);
+
+ connect(controller.get(), &CoreController::stopping, this, &QWidget::close);
}
void IOViewer::updateRegister() {
m_value = 0;
uint16_t value = 0;
- m_controller->threadInterrupt();
- if (m_controller->isLoaded()) {
+ {
+ CoreController::Interrupter interrupter(m_controller);
value = GBAView16(static_cast<ARMCore*>(m_controller->thread()->core->cpu), BASE_IO | m_register);
}
- m_controller->threadContinue();
for (int i = 0; i < 16; ++i) {
m_b[i]->setChecked(value & (1 << i) ? Qt::Checked : Qt::Unchecked);
@@ -1095,11 +1096,10 @@ void IOViewer::bitFlipped() {
}
void IOViewer::writeback() {
- m_controller->threadInterrupt();
- if (m_controller->isLoaded()) {
+ {
+ CoreController::Interrupter interrupter(m_controller);
GBAIOWrite(static_cast<GBA*>(m_controller->thread()->core->board), m_register, m_value);
}
- m_controller->threadContinue();
updateRegister();
}
View
@@ -9,11 +9,13 @@
#include <QDialog>
#include <QList>
+#include <memory>
+
#include "ui_IOViewer.h"
namespace QGBA {
-class GameController;
+class CoreController;
class IOViewer : public QDialog {
Q_OBJECT
@@ -39,7 +41,7 @@ Q_OBJECT
};
typedef QList<RegisterItem> RegisterDescription;
- IOViewer(GameController* controller, QWidget* parent = nullptr);
+ IOViewer(std::shared_ptr<CoreController> controller, QWidget* parent = nullptr);
static const QList<RegisterDescription>& registerDescriptions();
@@ -65,7 +67,7 @@ private slots:
QCheckBox* m_b[16];
- GameController* m_controller;
+ std::shared_ptr<CoreController> m_controller;
};
}
View
@@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "LoadSaveState.h"
-#include "GameController.h"
+#include "CoreController.h"
#include "GamepadAxisEvent.h"
#include "GamepadButtonEvent.h"
#include "VFileDevice.h"
@@ -20,7 +20,7 @@
using namespace QGBA;
-LoadSaveState::LoadSaveState(GameController* controller, QWidget* parent)
+LoadSaveState::LoadSaveState(std::shared_ptr<CoreController> controller, QWidget* parent)
: QWidget(parent)
, m_controller(controller)
, m_mode(LoadSave::LOAD)
@@ -61,6 +61,8 @@ LoadSaveState::LoadSaveState(GameController* controller, QWidget* parent)
escape->setShortcut(QKeySequence("Esc"));
escape->setShortcutContext(Qt::WidgetWithChildrenShortcut);
addAction(escape);
+
+ connect(m_controller.get(), &CoreController::stopping, this, &QWidget::close);
}
void LoadSaveState::setMode(LoadSave mode) {
View
@@ -8,11 +8,13 @@
#include <QWidget>
+#include <memory>
+
#include "ui_LoadSaveState.h"
namespace QGBA {
-class GameController;
+class CoreController;
class InputController;
class SavestateButton;
@@ -27,7 +29,7 @@ Q_OBJECT
public:
const static int NUM_SLOTS = 9;
- LoadSaveState(GameController* controller, QWidget* parent = nullptr);
+ LoadSaveState(std::shared_ptr<CoreController> controller, QWidget* parent = nullptr);
void setInputController(InputController* controller);
void setMode(LoadSave mode);
@@ -46,7 +48,7 @@ Q_OBJECT
void triggerState(int slot);
Ui::LoadSaveState m_ui;
- GameController* m_controller;
+ std::shared_ptr<CoreController> m_controller;
SavestateButton* m_slots[NUM_SLOTS];
LoadSave m_mode;
View
@@ -11,8 +11,11 @@ LogController LogController::s_global(mLOG_ALL);
LogController::LogController(int levels, QObject* parent)
: QObject(parent)
- , m_logLevel(levels)
{
+ mLogFilterInit(&m_filter);
+ mLogFilterSet(&m_filter, "gba.bios", mLOG_STUB);
+ m_filter.defaultLevels = levels;
+
if (this != &s_global) {
connect(&s_global, &LogController::logPosted, this, &LogController::postLog);
connect(this, &LogController::levelsSet, &s_global, &LogController::setLevels);
@@ -26,24 +29,24 @@ LogController::Stream LogController::operator()(int category, int level) {
}
void LogController::postLog(int level, int category, const QString& string) {
- if (!(m_logLevel & level)) {
+ if (!mLogFilterTest(&m_filter, category, static_cast<mLogLevel>(level))) {
return;
}
emit logPosted(level, category, string);
}
void LogController::setLevels(int levels) {
- m_logLevel = levels;
+ m_filter.defaultLevels = levels;
emit levelsSet(levels);
}
void LogController::enableLevels(int levels) {
- m_logLevel |= levels;
+ m_filter.defaultLevels |= levels;
emit levelsEnabled(levels);
}
void LogController::disableLevels(int levels) {
- m_logLevel &= ~levels;
+ m_filter.defaultLevels &= ~levels;
emit levelsDisabled(levels);
}
View
@@ -8,6 +8,8 @@
#include "GBAApp.h"
+#include <mgba/core/log.h>
+
#include <QObject>
#include <QStringList>
@@ -35,7 +37,8 @@ Q_OBJECT
public:
LogController(int levels, QObject* parent = nullptr);
- int levels() const { return m_logLevel; }
+ int levels() const { return m_filter.defaultLevels; }
+ mLogFilter* filter() { return &m_filter; }
Stream operator()(int category, int level);
@@ -55,7 +58,7 @@ public slots:
void disableLevels(int levels);
private:
- int m_logLevel;
+ mLogFilter m_filter;
static LogController s_global;
};
View
@@ -6,7 +6,7 @@
#include "MemoryModel.h"
#include "GBAApp.h"
-#include "GameController.h"
+#include "CoreController.h"
#include "LogController.h"
#include "VFileDevice.h"
@@ -91,7 +91,7 @@ MemoryModel::MemoryModel(QWidget* parent)
setRegion(0, 0x10000000, tr("All"));
}
-void MemoryModel::setController(GameController* controller) {
+void MemoryModel::setController(std::shared_ptr<CoreController> controller) {
m_core = controller->thread()->core;
}
View
@@ -11,6 +11,7 @@
#include <QSize>
#include <QStaticText>
#include <QVector>
+
#include <memory>
#include <mgba-util/text-codec.h>
@@ -19,15 +20,15 @@ struct mCore;
namespace QGBA {
-class GameController;
+class CoreController;
class MemoryModel : public QAbstractScrollArea {
Q_OBJECT
public:
MemoryModel(QWidget* parent = nullptr);
- void setController(GameController* controller);
+ void setController(std::shared_ptr<CoreController> controller);
void setRegion(uint32_t base, uint32_t size, const QString& name = QString(), int segment = -1);
void setSegment(int segment);
View
@@ -8,12 +8,12 @@
#include <mgba/core/core.h>
-#include "GameController.h"
+#include "CoreController.h"
#include "MemoryView.h"
using namespace QGBA;
-MemorySearch::MemorySearch(GameController* controller, QWidget* parent)
+MemorySearch::MemorySearch(std::shared_ptr<CoreController> controller, QWidget* parent)
: QWidget(parent)
, m_controller(controller)
{
@@ -26,6 +26,8 @@ MemorySearch::MemorySearch(GameController* controller, QWidget* parent)
connect(m_ui.numHex, &QPushButton::clicked, this, &MemorySearch::refresh);
connect(m_ui.numDec, &QPushButton::clicked, this, &MemorySearch::refresh);
connect(m_ui.viewMem, &QPushButton::clicked, this, &MemorySearch::openMemory);
+
+ connect(controller.get(), &CoreController::stopping, this, &QWidget::close);
}
MemorySearch::~MemorySearch() {
@@ -109,10 +111,7 @@ void MemorySearch::search() {
mCoreMemorySearchParams params;
- GameController::Interrupter interrupter(m_controller);
- if (!m_controller->isLoaded()) {
- return;
- }
+ CoreController::Interrupter interrupter(m_controller);
mCore* core = m_controller->thread()->core;
if (createParams(&params)) {
@@ -125,10 +124,7 @@ void MemorySearch::search() {
void MemorySearch::searchWithin() {
mCoreMemorySearchParams params;
- GameController::Interrupter interrupter(m_controller);
- if (!m_controller->isLoaded()) {
- return;
- }
+ CoreController::Interrupter interrupter(m_controller);
mCore* core = m_controller->thread()->core;
if (createParams(&params)) {
@@ -139,10 +135,7 @@ void MemorySearch::searchWithin() {
}
void MemorySearch::refresh() {
- GameController::Interrupter interrupter(m_controller);
- if (!m_controller->isLoaded()) {
- return;
- }
+ CoreController::Interrupter interrupter(m_controller);
mCore* core = m_controller->thread()->core;
m_ui.results->clearContents();
@@ -220,7 +213,6 @@ void MemorySearch::openMemory() {
MemoryView* memView = new MemoryView(m_controller);
memView->jumpToAddress(address);
- connect(m_controller, &GameController::gameStopped, memView, &QWidget::close);
memView->setAttribute(Qt::WA_DeleteOnClose);
memView->show();
}
View
@@ -6,21 +6,23 @@
#ifndef QGBA_MEMORY_SEARCH
#define QGBA_MEMORY_SEARCH
+#include <memory>
+
#include "ui_MemorySearch.h"
#include <mgba/core/mem-search.h>
namespace QGBA {
-class GameController;
+class CoreController;
class MemorySearch : public QWidget {
Q_OBJECT
public:
static constexpr size_t LIMIT = 10000;
- MemorySearch(GameController* controller, QWidget* parent = nullptr);
+ MemorySearch(std::shared_ptr<CoreController> controller, QWidget* parent = nullptr);
~MemorySearch();
public slots:
@@ -36,7 +38,7 @@ private slots:
Ui::MemorySearch m_ui;
- GameController* m_controller;
+ std::shared_ptr<CoreController> m_controller;
mCoreMemorySearchResults m_results;
QByteArray m_string;
View
@@ -6,13 +6,13 @@
#include "MemoryView.h"
-#include "GameController.h"
+#include "CoreController.h"
#include <mgba/core/core.h>
using namespace QGBA;
-MemoryView::MemoryView(GameController* controller, QWidget* parent)
+MemoryView::MemoryView(std::shared_ptr<CoreController> controller, QWidget* parent)
: QWidget(parent)
, m_controller(controller)
{
@@ -45,12 +45,12 @@ MemoryView::MemoryView(GameController* controller, QWidget* parent)
m_ui.hexfield, static_cast<void (MemoryModel::*)(uint32_t)>(&MemoryModel::jumpToAddress));
connect(m_ui.hexfield, &MemoryModel::selectionChanged, this, &MemoryView::updateSelection);
- connect(controller, &GameController::gameStopped, this, &QWidget::close);
+ connect(controller.get(), &CoreController::stopping, this, &QWidget::close);
- connect(controller, &GameController::frameAvailable, this, &MemoryView::update);
- connect(controller, &GameController::gamePaused, this, &MemoryView::update);
- connect(controller, &GameController::stateLoaded, this, &MemoryView::update);
- connect(controller, &GameController::rewound, this, &MemoryView::update);
+ connect(controller.get(), &CoreController::frameAvailable, this, &MemoryView::update);
+ connect(controller.get(), &CoreController::paused, this, &MemoryView::update);
+ connect(controller.get(), &CoreController::stateLoaded, this, &MemoryView::update);
+ connect(controller.get(), &CoreController::rewound, this, &MemoryView::update);
connect(m_ui.copy, &QAbstractButton::clicked, m_ui.hexfield, &MemoryModel::copy);
connect(m_ui.save, &QAbstractButton::clicked, m_ui.hexfield, &MemoryModel::save);
@@ -94,9 +94,6 @@ void MemoryView::updateSelection(uint32_t start, uint32_t end) {
void MemoryView::updateStatus() {
int align = m_ui.hexfield->alignment();
- if (!m_controller->isLoaded()) {
- return;
- }
mCore* core = m_controller->thread()->core;
QByteArray selection(m_ui.hexfield->serialize());
QString text(m_ui.hexfield->decodeText(selection));
View
@@ -12,13 +12,13 @@
namespace QGBA {
-class GameController;
+class CoreController;
class MemoryView : public QWidget {
Q_OBJECT
public:
- MemoryView(GameController* controller, QWidget* parent = nullptr);
+ MemoryView(std::shared_ptr<CoreController> controller, QWidget* parent = nullptr);
public slots:
void update();
@@ -33,7 +33,7 @@ private slots:
private:
Ui::MemoryView m_ui;
- GameController* m_controller;
+ std::shared_ptr<CoreController> m_controller;
QPair<uint32_t, uint32_t> m_selection;
};
View
@@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MultiplayerController.h"
-#include "GameController.h"
+#include "CoreController.h"
#ifdef M_CORE_GBA
#include <mgba/internal/gba/gba.h>
@@ -153,7 +153,7 @@ MultiplayerController::MultiplayerController() {
};
}
-bool MultiplayerController::attachGame(GameController* controller) {
+bool MultiplayerController::attachGame(CoreController* controller) {
if (m_lockstep.attached == MAX_GBAS) {
return false;
}
@@ -232,13 +232,15 @@ bool MultiplayerController::attachGame(GameController* controller) {
return false;
}
-void MultiplayerController::detachGame(GameController* controller) {
+void MultiplayerController::detachGame(CoreController* controller) {
mCoreThread* thread = controller->thread();
if (!thread) {
return;
}
+ QList<CoreController::Interrupter> interrupters;
+
for (int i = 0; i < m_players.count(); ++i) {
- m_players[i].controller->threadInterrupt();
+ interrupters.append(m_players[i].controller);
}
switch (controller->platform()) {
#ifdef M_CORE_GBA
@@ -269,20 +271,16 @@ void MultiplayerController::detachGame(GameController* controller) {
break;
}
- controller->threadContinue();
for (int i = 0; i < m_players.count(); ++i) {
if (m_players[i].controller == controller) {
m_players.removeAt(i);
break;
}
}
- for (int i = 0; i < m_players.count(); ++i) {
- m_players[i].controller->threadContinue();
- }
emit gameDetached();
}
-int MultiplayerController::playerId(GameController* controller) {
+int MultiplayerController::playerId(CoreController* controller) {
for (int i = 0; i < m_players.count(); ++i) {
if (m_players[i].controller == controller) {
return i;
View
@@ -23,27 +23,27 @@ struct GBASIOLockstepNode;
namespace QGBA {
-class GameController;
+class CoreController;
class MultiplayerController : public QObject {
Q_OBJECT
public:
MultiplayerController();
- bool attachGame(GameController*);
- void detachGame(GameController*);
+ bool attachGame(CoreController*);
+ void detachGame(CoreController*);
int attached();
- int playerId(GameController*);
+ int playerId(CoreController*);
signals:
void gameAttached();
void gameDetached();
private:
struct Player {
- GameController* controller;
+ CoreController* controller;
GBSIOLockstepNode* gbNode;
GBASIOLockstepNode* gbaNode;
int awake;
View
@@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ObjView.h"
+#include "CoreController.h"
#include "GBAApp.h"
#include <QFontDatabase>
@@ -24,7 +25,7 @@
using namespace QGBA;
-ObjView::ObjView(GameController* controller, QWidget* parent)
+ObjView::ObjView(std::shared_ptr<CoreController> controller, QWidget* parent)
: AssetView(controller, parent)
, m_controller(controller)
{
@@ -119,16 +120,16 @@ void ObjView::updateTilesGBA(bool force) {
};
m_objInfo = newInfo;
m_tileOffset = tile;
- mTileCacheSetPalette(m_tileCache.get(), paletteSet);
+ mTileCacheSetPalette(m_tileCache, paletteSet);
int i = 0;
for (int y = 0; y < height / 8; ++y) {
for (int x = 0; x < width / 8; ++x, ++i, ++tile, ++tileBase) {
- const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * tileBase], tile, palette);
+ const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache, &m_tileStatus[32 * tileBase], tile, palette);
if (data) {
m_ui.tiles->setTile(i, data);
} else if (force) {
- m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), tile, palette));
+ m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache, tile, palette));
}
}
tile += newInfo.stride - width / 8;
@@ -215,16 +216,16 @@ void ObjView::updateTilesGB(bool force) {
m_tileOffset = tile;
int i = 0;
- mTileCacheSetPalette(m_tileCache.get(), 0);
+ mTileCacheSetPalette(m_tileCache, 0);
m_ui.tile->setPalette(palette);
m_ui.tile->setPaletteSet(0, 512, 1024);
for (int y = 0; y < height / 8; ++y, ++i) {
unsigned t = tile + i;
- const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[16 * t], t, palette);
+ const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache, &m_tileStatus[16 * t], t, palette);
if (data) {
m_ui.tiles->setTile(i, data);
} else if (force) {
- m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), t, palette));
+ m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache, t, palette));
}
}
@@ -247,7 +248,7 @@ void ObjView::updateTilesGB(bool force) {
#ifdef USE_PNG
void ObjView::exportObj() {
- GameController::Interrupter interrupter(m_controller);
+ CoreController::Interrupter interrupter(m_controller);
QString filename = GBAApp::app()->getSaveFileName(this, tr("Export sprite"),
tr("Portable Network Graphics (*.png)"));
VFile* vf = VFileDevice::open(filename, O_WRONLY | O_CREAT | O_TRUNC);
@@ -256,11 +257,11 @@ void ObjView::exportObj() {
return;
}
- mTileCacheSetPalette(m_tileCache.get(), m_objInfo.paletteSet);
+ mTileCacheSetPalette(m_tileCache, m_objInfo.paletteSet);
png_structp png = PNGWriteOpen(vf);
png_infop info = PNGWriteHeader8(png, m_objInfo.width * 8, m_objInfo.height * 8);
- const uint16_t* rawPalette = mTileCacheGetPalette(m_tileCache.get(), m_objInfo.paletteId);
+ const uint16_t* rawPalette = mTileCacheGetPalette(m_tileCache, m_objInfo.paletteId);
unsigned colors = 1 << m_objInfo.bits;
uint32_t palette[256];
for (unsigned c = 0; c < colors && c < 256; ++c) {
View
@@ -7,19 +7,20 @@
#define QGBA_OBJ_VIEW
#include "AssetView.h"
-#include "GameController.h"
#include "ui_ObjView.h"
#include <mgba/core/tile-cache.h>
namespace QGBA {
+class CoreController;
+
class ObjView : public AssetView {
Q_OBJECT
public:
- ObjView(GameController* controller, QWidget* parent = nullptr);
+ ObjView(std::shared_ptr<CoreController> controller, QWidget* parent = nullptr);
#ifdef USE_PNG
public slots:
@@ -40,7 +41,7 @@ private slots:
Ui::ObjView m_ui;
- GameController* m_controller;
+ std::shared_ptr<CoreController> m_controller;
mTileCacheEntry m_tileStatus[1024 * 32] = {}; // TODO: Correct size
int m_objId = 0;
struct ObjInfo {
View
@@ -9,7 +9,7 @@
#include <QPushButton>
#include "ConfigController.h"
-#include "GameController.h"
+#include "CoreController.h"
#ifdef M_CORE_GBA
#include "GBAOverride.h"
@@ -28,9 +28,8 @@ QList<enum GBModel> OverrideView::s_gbModelList;
QList<enum GBMemoryBankControllerType> OverrideView::s_mbcList;
#endif
-OverrideView::OverrideView(GameController* controller, ConfigController* config, QWidget* parent)
+OverrideView::OverrideView(ConfigController* config, QWidget* parent)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
- , m_controller(controller)
, m_config(config)
{
#ifdef M_CORE_GB
@@ -57,9 +56,6 @@ OverrideView::OverrideView(GameController* controller, ConfigController* config,
#endif
m_ui.setupUi(this);
- connect(controller, &GameController::gameStarted, this, &OverrideView::gameStarted);
- connect(controller, &GameController::gameStopped, this, &OverrideView::gameStopped);
-
connect(m_ui.hwAutodetect, &QAbstractButton::toggled, [this] (bool enabled) {
m_ui.hwRTC->setEnabled(!enabled);
m_ui.hwGyro->setEnabled(!enabled);
@@ -106,9 +102,16 @@ OverrideView::OverrideView(GameController* controller, ConfigController* config,
connect(m_ui.buttonBox, &QDialogButtonBox::accepted, this, &OverrideView::saveOverride);
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &QWidget::close);
m_ui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(false);
+}
- if (controller->isLoaded()) {
- gameStarted(controller->thread());
+void OverrideView::setController(std::shared_ptr<CoreController> controller) {
+ m_controller = controller;
+ gameStarted();
+ connect(controller.get(), &CoreController::stopping, this, &OverrideView::gameStopped);
+ if (m_override) {
+ m_controller->setOverride(std::move(m_override));
+ } else {
+ m_controller->clearOverride();
}
}
@@ -149,7 +152,7 @@ bool OverrideView::eventFilter(QObject* obj, QEvent* event) {
}
void OverrideView::saveOverride() {
- if (!m_config) {
+ if (!m_config || !m_controller) {
return;
}
m_config->saveOverride(*m_controller->override());
@@ -158,7 +161,7 @@ void OverrideView::saveOverride() {
void OverrideView::updateOverrides() {
#ifdef M_CORE_GBA
if (m_ui.tabWidget->currentWidget() == m_ui.tabGBA) {
- GBAOverride* gba = new GBAOverride;
+ std::unique_ptr<GBAOverride> gba(new GBAOverride);
memset(gba->override.id, 0, 4);
gba->override.savetype = static_cast<SavedataType>(m_ui.savetype->currentIndex() - 1);
gba->override.hardware = HW_NO_OVERRIDE;
@@ -193,18 +196,18 @@ void OverrideView::updateOverrides() {
gba->override.idleLoop = parsedIdleLoop;
}
+
if (gba->override.savetype != SAVEDATA_AUTODETECT || gba->override.hardware != HW_NO_OVERRIDE ||
gba->override.idleLoop != IDLE_LOOP_NONE) {
- m_controller->setOverride(gba);
+ m_override = std::move(gba);
} else {
- m_controller->clearOverride();
- delete gba;
+ m_override.reset();
}
}
#endif
#ifdef M_CORE_GB
if (m_ui.tabWidget->currentWidget() == m_ui.tabGB) {
- GBOverride* gb = new GBOverride;
+ std::unique_ptr<GBOverride> gb(new GBOverride);
gb->override.mbc = s_mbcList[m_ui.mbc->currentIndex()];
gb->override.model = s_gbModelList[m_ui.gbModel->currentIndex()];
gb->override.gbColors[0] = m_gbColors[0];
@@ -214,20 +217,17 @@ void OverrideView::updateOverrides() {
bool hasOverride = gb->override.mbc != GB_MBC_AUTODETECT || gb->override.model != GB_MODEL_AUTODETECT;
hasOverride = hasOverride || (m_gbColors[0] | m_gbColors[1] | m_gbColors[2] | m_gbColors[3]);
if (hasOverride) {
- m_controller->setOverride(gb);
+ m_override = std::move(gb);
} else {
- m_controller->clearOverride();
- delete gb;
+ m_override.reset();
}
}
#endif
}
-void OverrideView::gameStarted(mCoreThread* thread) {
- if (!thread->core) {
- gameStopped();
- return;
- }
+void OverrideView::gameStarted() {
+ CoreController::Interrupter interrupter(m_controller);
+ mCoreThread* thread = m_controller->thread();
m_ui.tabWidget->setEnabled(false);
m_ui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(true);
@@ -278,6 +278,7 @@ void OverrideView::gameStarted(mCoreThread* thread) {
}
void OverrideView::gameStopped() {
+ m_controller.reset();
m_ui.tabWidget->setEnabled(true);
m_ui.savetype->setCurrentIndex(0);
m_ui.idleLoop->clear();
View
@@ -8,32 +8,38 @@
#include <QDialog>
+#include <memory>
+
#ifdef M_CORE_GB
#include <mgba/gb/interface.h>
#endif
+#include "Override.h"
+
#include "ui_OverrideView.h"
struct mCoreThread;
namespace QGBA {
class ConfigController;
-class GameController;
+class CoreController;
class Override;
class OverrideView : public QDialog {
Q_OBJECT
public:
- OverrideView(GameController* controller, ConfigController* config, QWidget* parent = nullptr);
+ OverrideView(ConfigController* config, QWidget* parent = nullptr);
+
+ void setController(std::shared_ptr<CoreController> controller);
public slots:
void saveOverride();
private slots:
void updateOverrides();
- void gameStarted(mCoreThread*);
+ void gameStarted();
void gameStopped();
protected:
@@ -42,7 +48,8 @@ private slots:
private:
Ui::OverrideView m_ui;
- GameController* m_controller;
+ std::shared_ptr<CoreController> m_controller;
+ std::unique_ptr<Override> m_override;
ConfigController* m_config;
#ifdef M_CORE_GB
View
@@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "PaletteView.h"
+#include "CoreController.h"
#include "GBAApp.h"
#include "LogController.h"
#include "VFileDevice.h"
@@ -24,13 +25,13 @@
using namespace QGBA;
-PaletteView::PaletteView(GameController* controller, QWidget* parent)
+PaletteView::PaletteView(std::shared_ptr<CoreController> controller, QWidget* parent)
: QWidget(parent)
, m_controller(controller)
{
m_ui.setupUi(this);
- connect(m_controller, &GameController::frameAvailable, this, &PaletteView::updatePalette);
+ connect(controller.get(), &CoreController::frameAvailable, this, &PaletteView::updatePalette);
m_ui.bgGrid->setDimensions(QSize(16, 16));
m_ui.objGrid->setDimensions(QSize(16, 16));
int count = 256;
@@ -61,7 +62,7 @@ PaletteView::PaletteView(GameController* controller, QWidget* parent)
connect(m_ui.exportBG, &QAbstractButton::clicked, [this, count] () { exportPalette(0, count); });
connect(m_ui.exportOBJ, &QAbstractButton::clicked, [this, count] () { exportPalette(count, count); });
- connect(controller, &GameController::gameStopped, this, &QWidget::close);
+ connect(controller.get(), &CoreController::stopping, this, &QWidget::close);
}
void PaletteView::updatePalette() {
@@ -133,7 +134,7 @@ void PaletteView::exportPalette(int start, int length) {
length = 512 - start;
}
- GameController::Interrupter interrupter(m_controller);
+ CoreController::Interrupter interrupter(m_controller);
QString filename = GBAApp::app()->getSaveFileName(this, tr("Export palette"),
tr("Windows PAL (*.pal);;Adobe Color Table (*.act)"));
VFile* vf = VFileDevice::open(filename, O_WRONLY | O_CREAT | O_TRUNC);
View
@@ -8,20 +8,22 @@
#include <QWidget>
-#include "GameController.h"
+#include <memory>
+
#include "Swatch.h"
#include "ui_PaletteView.h"
namespace QGBA {
+class CoreController;
class Swatch;
class PaletteView : public QWidget {
Q_OBJECT
public:
- PaletteView(GameController* controller, QWidget* parent = nullptr);
+ PaletteView(std::shared_ptr<CoreController> controller, QWidget* parent = nullptr);
public slots:
void updatePalette();
@@ -34,7 +36,7 @@ private slots:
Ui::PaletteView m_ui;
- GameController* m_controller;
+ std::shared_ptr<CoreController> m_controller;
};
}
View
@@ -6,7 +6,7 @@
#include "ROMInfo.h"
#include "GBAApp.h"
-#include "GameController.h"
+#include "CoreController.h"
#include <mgba/core/core.h>
#ifdef M_CORE_GB
@@ -21,21 +21,17 @@
using namespace QGBA;
-ROMInfo::ROMInfo(GameController* controller, QWidget* parent)
+ROMInfo::ROMInfo(std::shared_ptr<CoreController> controller, QWidget* parent)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
{
m_ui.setupUi(this);
- if (!controller->isLoaded()) {
- return;
- }
-
#ifdef USE_SQLITE3
const NoIntroDB* db = GBAApp::app()->gameDB();
#endif
uint32_t crc32 = 0;
- GameController::Interrupter interrupter(controller);
+ CoreController::Interrupter interrupter(controller);
mCore* core = controller->thread()->core;
char title[17] = {};
core->getGameTitle(core, title);
View
@@ -8,17 +8,19 @@
#include <QWidget>
+#include <memory>
+
#include "ui_ROMInfo.h"
namespace QGBA {
-class GameController;
+class CoreController;
class ROMInfo : public QDialog {
Q_OBJECT
public:
- ROMInfo(GameController* controller, QWidget* parent = nullptr);
+ ROMInfo(std::shared_ptr<CoreController> controller, QWidget* parent = nullptr);
private:
Ui::ROMInfo m_ui;
View
@@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SensorView.h"
-#include "GameController.h"
+#include "CoreController.h"
#include "GamepadAxisEvent.h"
#include "InputController.h"
@@ -14,9 +14,8 @@
using namespace QGBA;
-SensorView::SensorView(GameController* controller, InputController* input, QWidget* parent)
+SensorView::SensorView(InputController* input, QWidget* parent)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
- , m_controller(controller)
, m_input(input)
, m_rotation(input->rotationSource())
{
@@ -26,22 +25,13 @@ SensorView::SensorView(GameController* controller, InputController* input, QWidg
this, &SensorView::setLuminanceValue);
connect(m_ui.lightSlide, &QAbstractSlider::valueChanged, this, &SensorView::setLuminanceValue);
- connect(m_ui.timeNoOverride, &QAbstractButton::clicked, controller, &GameController::setRealTime);
- connect(m_ui.timeFixed, &QRadioButton::clicked, [controller, this] () {
- controller->setFixedTime(m_ui.time->dateTime());
- });
- connect(m_ui.timeFakeEpoch, &QRadioButton::clicked, [controller, this] () {
- controller->setFakeEpoch(m_ui.time->dateTime());
- });
- connect(m_ui.time, &QDateTimeEdit::dateTimeChanged, [controller, this] (const QDateTime&) {
+ connect(m_ui.time, &QDateTimeEdit::dateTimeChanged, [this] (const QDateTime&) {
m_ui.timeButtons->checkedButton()->clicked();
});
- connect(m_ui.timeNow, &QPushButton::clicked, [controller, this] () {
+ connect(m_ui.timeNow, &QPushButton::clicked, [this] () {
m_ui.time->setDateTime(QDateTime::currentDateTime());
});
- connect(m_controller, &GameController::luminanceValueChanged, this, &SensorView::luminanceValueChanged);
-
m_timer.setInterval(2);
connect(&m_timer, &QTimer::timeout, this, &SensorView::updateSensors);
if (!m_rotation || !m_rotation->readTiltX || !m_rotation->readTiltY) {
@@ -66,6 +56,22 @@ SensorView::SensorView(GameController* controller, InputController* input, QWidg
m_input->setGyroSensitivity(value * 1e8f);
});
m_input->stealFocus(this);
+ connect(m_input, &InputController::luminanceValueChanged, this, &SensorView::luminanceValueChanged);
+}
+
+void SensorView::setController(std::shared_ptr<CoreController> controller) {
+ m_controller = controller;
+ connect(m_ui.timeNoOverride, &QAbstractButton::clicked, controller.get(), &CoreController::setRealTime);
+ connect(m_ui.timeFixed, &QRadioButton::clicked, [controller, this] () {
+ controller->setFixedTime(m_ui.time->dateTime());
+ });
+ connect(m_ui.timeFakeEpoch, &QRadioButton::clicked, [controller, this] () {
+ controller->setFakeEpoch(m_ui.time->dateTime());
+ });
+
+ connect(controller.get(), &CoreController::stopping, [this]() {
+ m_controller.reset();
+ });
}
void SensorView::jiggerer(QAbstractButton* button, void (InputController::*setter)(int)) {
@@ -107,16 +113,7 @@ bool SensorView::eventFilter(QObject*, QEvent* event) {
}
void SensorView::updateSensors() {
- GameController::Interrupter interrupter(m_controller);
- if (m_rotation->sample &&
- (!m_controller->isLoaded() || !(static_cast<GBA*>(m_controller->thread()->core->board)->memory.hw.devices & (HW_GYRO | HW_TILT)))) {
- m_rotation->sample(m_rotation);
- m_rotation->sample(m_rotation);
- m_rotation->sample(m_rotation);
- m_rotation->sample(m_rotation);
- m_rotation->sample(m_rotation);
- m_rotation->sample(m_rotation);
- m_rotation->sample(m_rotation);
+ if (m_rotation->sample && (!m_controller || m_controller->isPaused())) {
m_rotation->sample(m_rotation);
}
if (m_rotation->readTiltX && m_rotation->readTiltY) {
@@ -132,7 +129,9 @@ void SensorView::updateSensors() {
void SensorView::setLuminanceValue(int value) {
value = std::max(0, std::min(value, 255));
- m_controller->setLuminanceValue(value);
+ if (m_input) {
+ m_input->setLuminanceValue(value);
+ }
}
void SensorView::luminanceValueChanged(int value) {
View
@@ -10,6 +10,7 @@
#include <QDialog>
#include <functional>
+#include <memory>
#include "ui_SensorView.h"
@@ -18,15 +19,17 @@ struct mRotationSource;
namespace QGBA {
class ConfigController;
-class GameController;
+class CoreController;
class GamepadAxisEvent;
class InputController;
class SensorView : public QDialog {
Q_OBJECT
public:
- SensorView(GameController* controller, InputController* input, QWidget* parent = nullptr);
+ SensorView(InputController* input, QWidget* parent = nullptr);
+
+ void setController(std::shared_ptr<CoreController>);
protected:
bool eventFilter(QObject*, QEvent* event) override;
@@ -41,7 +44,7 @@ private slots:
Ui::SensorView m_ui;
std::function<void(int)> m_jiggered;
- GameController* m_controller;
+ std::shared_ptr<CoreController> m_controller;
InputController* m_input;
mRotationSource* m_rotation;
QTimer m_timer;
View
@@ -183,19 +183,26 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC
SettingsView::~SettingsView() {
#if defined(BUILD_GL) || defined(BUILD_GLES)
- if (m_shader) {
- m_ui.stackedWidget->removeWidget(m_shader);
- m_shader->setParent(nullptr);
- }
+ setShaderSelector(nullptr);
#endif
}
void SettingsView::setShaderSelector(ShaderSelector* shaderSelector) {
#if defined(BUILD_GL) || defined(BUILD_GLES)
+ if (m_shader) {
+ auto items = m_ui.tabs->findItems(tr("Shaders"), Qt::MatchFixedString);
+ for (const auto& item : items) {
+ m_ui.tabs->removeItemWidget(item);
+ }
+ m_ui.stackedWidget->removeWidget(m_shader);
+ m_shader->setParent(nullptr);
+ }
m_shader = shaderSelector;
- m_ui.stackedWidget->addWidget(m_shader);
- m_ui.tabs->addItem(tr("Shaders"));
- connect(m_ui.buttonBox, &QDialogButtonBox::accepted, m_shader, &ShaderSelector::saved);
+ if (shaderSelector) {
+ m_ui.stackedWidget->addWidget(m_shader);
+ m_ui.tabs->addItem(tr("Shaders"));
+ connect(m_ui.buttonBox, &QDialogButtonBox::accepted, m_shader, &ShaderSelector::saved);
+ }
#endif
}
@@ -281,6 +288,7 @@ void SettingsView::updateConfig() {
if (displayDriver != m_controller->getQtOption("displayDriver")) {
m_controller->setQtOption("displayDriver", displayDriver);
Display::setDriver(static_cast<Display::Driver>(displayDriver.toInt()));
+ setShaderSelector(nullptr);
emit displayDriverChanged();
}
View
@@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TileView.h"
+#include "CoreController.h"
#include "GBAApp.h"
#include <QFontDatabase>
@@ -16,7 +17,7 @@
using namespace QGBA;
-TileView::TileView(GameController* controller, QWidget* parent)
+TileView::TileView(std::shared_ptr<CoreController> controller, QWidget* parent)
: AssetView(controller, parent)
, m_controller(controller)
{
@@ -79,40 +80,40 @@ TileView::TileView(GameController* controller, QWidget* parent)
void TileView::updateTilesGBA(bool force) {
if (m_ui.palette256->isChecked()) {
m_ui.tiles->setTileCount(1536);
- mTileCacheSetPalette(m_tileCache.get(), 1);
+ mTileCacheSetPalette(m_tileCache, 1);
for (int i = 0; i < 1024; ++i) {
- const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * i], i, 0);
+ const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache, &m_tileStatus[32 * i], i, 0);
if (data) {
m_ui.tiles->setTile(i, data);
} else if (force) {
- m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), i, 0));
+ m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache, i, 0));
}
}
for (int i = 1024; i < 1536; ++i) {
- const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * i], i, 1);
+ const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache, &m_tileStatus[32 * i], i, 1);
if (data) {
m_ui.tiles->setTile(i, data);
} else if (force) {
- m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), i, 1));
+ m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache, i, 1));
}
}
} else {
m_ui.tiles->setTileCount(3072);
- mTileCacheSetPalette(m_tileCache.get(), 0);
+ mTileCacheSetPalette(m_tileCache, 0);
for (int i = 0; i < 2048; ++i) {
- const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * i], i, m_paletteId);
+ const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache, &m_tileStatus[32 * i], i, m_paletteId);
if (data) {
m_ui.tiles->setTile(i, data);
} else if (force) {
- m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), i, m_paletteId));
+ m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache, i, m_paletteId));
}
}
for (int i = 2048; i < 3072; ++i) {
- const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * i], i, m_paletteId + 16);
+ const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache, &m_tileStatus[32 * i], i, m_paletteId + 16);
if (data) {
m_ui.tiles->setTile(i, data);
} else if (force) {
- m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), i, m_paletteId + 16));
+ m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache, i, m_paletteId + 16));
}
}
}
@@ -124,13 +125,13 @@ void TileView::updateTilesGB(bool force) {
const GB* gb = static_cast<const GB*>(m_controller->thread()->core->board);
int count = gb->model >= GB_MODEL_CGB ? 1024 : 512;
m_ui.tiles->setTileCount(count);
- mTileCacheSetPalette(m_tileCache.get(), 0);
+ mTileCacheSetPalette(m_tileCache, 0);
for (int i = 0; i < count; ++i) {
- const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[16 * i], i, m_paletteId);
+ const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache, &m_tileStatus[16 * i], i, m_paletteId);
if (data) {
m_ui.tiles->setTile(i, data);
} else if (force) {
- m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), i, m_paletteId));
+ m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache, i, m_paletteId));
}
}
}
View
@@ -7,19 +7,20 @@
#define QGBA_TILE_VIEW
#include "AssetView.h"
-#include "GameController.h"
#include "ui_TileView.h"
#include <mgba/core/tile-cache.h>
namespace QGBA {
+class CoreController;
+
class TileView : public AssetView {
Q_OBJECT
public:
- TileView(GameController* controller, QWidget* parent = nullptr);
+ TileView(std::shared_ptr<CoreController> controller, QWidget* parent = nullptr);
public slots:
void updatePalette(int);
@@ -34,7 +35,7 @@ public slots:
Ui::TileView m_ui;
- GameController* m_controller;
+ std::shared_ptr<CoreController> m_controller;
mTileCacheEntry m_tileStatus[3072 * 32] = {}; // TODO: Correct size
int m_paletteId = 0;
};
View
@@ -13,7 +13,33 @@ VFileDevice::VFileDevice(VFile* vf, QObject* parent)
: QIODevice(parent)
, m_vf(vf)
{
- // Nothing to do
+ // TODO: Correct mode
+ if (vf) {
+ setOpenMode(QIODevice::ReadWrite);
+ }
+}
+
+void VFileDevice::close() {
+ QIODevice::close();
+ m_vf->close(m_vf);
+ m_vf = nullptr;
+}
+
+bool VFileDevice::resize(qint64 sz) {
+ m_vf->truncate(m_vf, sz);
+ return true;
+}
+
+bool VFileDevice::seek(qint64 pos) {
+ QIODevice::seek(pos);
+ return m_vf->seek(m_vf, pos, SEEK_SET) == pos;
+}
+
+VFileDevice& VFileDevice::operator=(VFile* vf) {
+ close();
+ m_vf = vf;
+ setOpenMode(QIODevice::ReadWrite);
+ return *this;
}
qint64 VFileDevice::readData(char* data, qint64 maxSize) {
View
@@ -17,7 +17,16 @@ class VFileDevice : public QIODevice {
Q_OBJECT
public:
- VFileDevice(VFile* vf, QObject* parent = nullptr);
+ VFileDevice(VFile* vf = nullptr, QObject* parent = nullptr);
+
+ virtual void close() override;
+ virtual bool seek(qint64 pos) override;
+ virtual qint64 size() const override;
+
+ bool resize(qint64 sz);
+
+ VFileDevice& operator=(VFile*);
+ operator VFile*() { return m_vf; }
static VFile* open(const QString& path, int mode);
static VDir* openDir(const QString& path);
@@ -26,7 +35,6 @@ Q_OBJECT
protected:
virtual qint64 readData(char* data, qint64 maxSize) override;
virtual qint64 writeData(const char* data, qint64 maxSize) override;
- virtual qint64 size() const override;
private:
VFile* m_vf;
View
@@ -195,6 +195,14 @@ VideoView::~VideoView() {
free(m_containerCstr);
}
+void VideoView::setController(std::shared_ptr<CoreController> controller) {
+ connect(controller.get(), &CoreController::stopping, this, &VideoView::stopRecording);
+ connect(this, &VideoView::recordingStarted, controller.get(), &CoreController::setAVStream);
+ connect(this, &VideoView::recordingStopped, controller.get(), &CoreController::clearAVStream, Qt::DirectConnection);
+
+ setNativeResolution(controller->screenDimensions());
+}
+
void VideoView::startRecording() {
if (!validateSettings()) {
return;
View
@@ -10,12 +10,18 @@
#include <QWidget>
+#include <memory>
+
+#include "CoreController.h"
+
#include "ui_VideoView.h"
#include "feature/ffmpeg/ffmpeg-encoder.h"
namespace QGBA {
+class CoreController;
+
class VideoView : public QWidget {
Q_OBJECT
@@ -26,6 +32,8 @@ Q_OBJECT
mAVStream* getStream() { return &m_encoder.d; }
public slots:
+ void setController(std::shared_ptr<CoreController>);
+
void startRecording();
void stopRecording();
void setNativeResolution(const QSize&);
Oops, something went wrong.