all repos — mgba @ 3b7dbdecbac880fc204a42384151bf34ed35837c

mGBA Game Boy Advance Emulator

src/platform/qt/GameController.cpp (view raw)

  1#include "GameController.h"
  2
  3extern "C" {
  4#include "gba.h"
  5#include "renderers/video-software.h"
  6}
  7
  8using namespace QGBA;
  9
 10GameController::GameController(QObject* parent)
 11	: QObject(parent)
 12	, m_drawContext(new uint32_t[256 * 256])
 13	, m_audioContext(nullptr)
 14{
 15	m_renderer = new GBAVideoSoftwareRenderer;
 16	GBAVideoSoftwareRendererCreate(m_renderer);
 17	m_renderer->outputBuffer = (color_t*) m_drawContext;
 18	m_renderer->outputBufferStride = 256;
 19	m_threadContext = {
 20		.debugger = 0,
 21		.frameskip = 0,
 22		.biosFd = -1,
 23		.renderer = &m_renderer->d,
 24		.sync.videoFrameWait = 0,
 25		.sync.audioWait = 1,
 26		.userData = this,
 27		.rewindBufferCapacity = 0
 28	};
 29	m_threadContext.startCallback = [] (GBAThread* context) {
 30		GameController* controller = static_cast<GameController*>(context->userData);
 31		controller->audioDeviceAvailable(&context->gba->audio);
 32	};
 33	m_threadContext.frameCallback = [] (GBAThread* context) {
 34		GameController* controller = static_cast<GameController*>(context->userData);
 35		controller->m_pauseMutex.lock();
 36		if (controller->m_pauseAfterFrame) {
 37			GBAThreadPause(context);
 38			controller->m_pauseAfterFrame = false;
 39		}
 40		controller->m_pauseMutex.unlock();
 41		controller->frameAvailable(controller->m_drawContext);
 42	};
 43}
 44
 45GameController::~GameController() {
 46	if (GBAThreadIsPaused(&m_threadContext)) {
 47		GBAThreadUnpause(&m_threadContext);
 48	}
 49	GBAThreadEnd(&m_threadContext);
 50	GBAThreadJoin(&m_threadContext);
 51	delete m_renderer;
 52}
 53
 54ARMDebugger* GameController::debugger() {
 55	return m_threadContext.debugger;
 56}
 57
 58void GameController::setDebugger(ARMDebugger* debugger) {
 59	bool wasPaused = isPaused();
 60	setPaused(true);
 61	if (m_threadContext.debugger) {
 62		GBADetachDebugger(m_threadContext.gba);
 63	}
 64	m_threadContext.debugger = debugger;
 65	if (m_threadContext.debugger) {
 66		GBAAttachDebugger(m_threadContext.gba, m_threadContext.debugger);
 67	}
 68	setPaused(wasPaused);
 69}
 70
 71void GameController::loadGame(const QString& path) {
 72	m_rom = new QFile(path);
 73	if (!m_rom->open(QIODevice::ReadOnly)) {
 74		delete m_rom;
 75		m_rom = 0;
 76	}
 77
 78	m_pauseAfterFrame = false;
 79
 80	m_threadContext.fd = m_rom->handle();
 81	m_threadContext.fname = path.toLocal8Bit().constData();
 82	GBAThreadStart(&m_threadContext);
 83	emit gameStarted(&m_threadContext);
 84}
 85
 86bool GameController::isPaused() {
 87	return GBAThreadIsPaused(&m_threadContext);
 88}
 89
 90void GameController::setPaused(bool paused) {
 91	if (paused == GBAThreadIsPaused(&m_threadContext)) {
 92		return;
 93	}
 94	if (paused) {
 95		GBAThreadPause(&m_threadContext);
 96	} else {
 97		GBAThreadUnpause(&m_threadContext);
 98	}
 99}
100
101void GameController::frameAdvance() {
102	m_pauseMutex.lock();
103	m_pauseAfterFrame = true;
104	setPaused(false);
105	m_pauseMutex.unlock();
106}
107
108void GameController::keyPressed(int key) {
109	int mappedKey = 1 << key;
110	m_threadContext.activeKeys |= mappedKey;
111}
112
113void GameController::keyReleased(int key) {
114	int mappedKey = 1 << key;
115	m_threadContext.activeKeys &= ~mappedKey;
116}