src/platform/qt/Display.cpp (view raw)
1#include "Display.h"
2
3#include <QResizeEvent>
4
5extern "C" {
6#include "gba-thread.h"
7}
8
9using namespace QGBA;
10
11static const GLint _glVertices[] = {
12 0, 0,
13 256, 0,
14 256, 256,
15 0, 256
16};
17
18static const GLint _glTexCoords[] = {
19 0, 0,
20 1, 0,
21 1, 1,
22 0, 1
23};
24
25Display::Display(QWidget* parent)
26 : QGLWidget(QGLFormat(QGL::Rgba | QGL::SingleBuffer), parent)
27 , m_painter(nullptr)
28 , m_drawThread(nullptr)
29{
30 setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
31 setAutoBufferSwap(false);
32}
33
34void Display::startDrawing(const uint32_t* buffer, GBAThread* thread) {
35 m_drawThread = new QThread(this);
36 m_painter = new Painter(this);
37 m_painter->setGLContext(this);
38 m_painter->setContext(thread);
39 m_painter->setBacking(buffer);
40 m_painter->moveToThread(m_drawThread);
41 doneCurrent();
42 context()->moveToThread(m_drawThread);
43 connect(m_drawThread, SIGNAL(started()), m_painter, SLOT(start()));
44 m_drawThread->start();
45}
46
47void Display::stopDrawing() {
48 if (m_drawThread) {
49 QMetaObject::invokeMethod(m_painter, "stop", Qt::BlockingQueuedConnection);
50 m_drawThread->exit();
51 }
52}
53
54void Display::resizeEvent(QResizeEvent* event) {
55 if (m_painter) {
56 m_painter->resize(event->size());
57 }
58}
59
60Painter::Painter(Display* parent) {
61 m_size = parent->size();
62}
63
64void Painter::setContext(GBAThread* context) {
65 m_context = context;
66}
67
68void Painter::setBacking(const uint32_t* backing) {
69 m_backing = backing;
70}
71
72void Painter::setGLContext(QGLWidget* context) {
73 m_gl = context;
74}
75
76void Painter::resize(const QSize& size) {
77 m_size = size;
78}
79
80void Painter::start() {
81 m_gl->makeCurrent();
82 glEnable(GL_TEXTURE_2D);
83 glGenTextures(1, &m_tex);
84 glBindTexture(GL_TEXTURE_2D, m_tex);
85 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
86 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
87 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
88 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
89 glEnableClientState(GL_VERTEX_ARRAY);
90 glVertexPointer(2, GL_INT, 0, _glVertices);
91 glTexCoordPointer(2, GL_INT, 0, _glTexCoords);
92 glMatrixMode(GL_PROJECTION);
93 glLoadIdentity();
94 glOrtho(0, 240, 160, 0, 0, 1);
95 glMatrixMode(GL_MODELVIEW);
96 glLoadIdentity();
97 m_gl->doneCurrent();
98
99 m_drawTimer = new QTimer;
100 m_drawTimer->moveToThread(QThread::currentThread());
101 m_drawTimer->setInterval(0);
102 connect(m_drawTimer, SIGNAL(timeout()), this, SLOT(draw()));
103 m_drawTimer->start();
104}
105
106void Painter::draw() {
107 m_gl->makeCurrent();
108 if (GBASyncWaitFrameStart(&m_context->sync, m_context->frameskip)) {
109 glViewport(0, 0, m_size.width() * m_gl->devicePixelRatio(), m_size.height() * m_gl->devicePixelRatio());
110 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_backing);
111 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
112 if (m_context->sync.videoFrameWait) {
113 glFlush();
114 }
115 }
116 GBASyncWaitFrameEnd(&m_context->sync);
117 m_gl->swapBuffers();
118 m_gl->doneCurrent();
119}
120
121void Painter::stop() {
122 m_drawTimer->stop();
123 delete m_drawTimer;
124 m_gl->makeCurrent();
125 glDeleteTextures(1, &m_tex);
126 m_gl->doneCurrent();
127}