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}