diff --git a/src/gba/gba-config.c b/src/gba/gba-config.c index 35d2bb159..8ff5bd346 100644 --- a/src/gba/gba-config.c +++ b/src/gba/gba-config.c @@ -196,6 +196,9 @@ void GBAConfigMap(const struct GBAConfig* config, struct GBAOptions* opts) { if (_lookupIntValue(config, "videoSync", &fakeBool)) { opts->videoSync = fakeBool; } + if (_lookupIntValue(config, "lockAspectRatio", &fakeBool)) { + opts->lockAspectRatio = fakeBool; + } _lookupIntValue(config, "fullscreen", &opts->fullscreen); _lookupIntValue(config, "width", &opts->width); @@ -215,6 +218,7 @@ void GBAConfigLoadDefaults(struct GBAConfig* config, const struct GBAOptions* op ConfigurationSetIntValue(&config->defaultsTable, 0, "fullscreen", opts->fullscreen); ConfigurationSetIntValue(&config->defaultsTable, 0, "width", opts->width); ConfigurationSetIntValue(&config->defaultsTable, 0, "height", opts->height); + ConfigurationSetIntValue(&config->defaultsTable, 0, "lockAspectRatio", opts->lockAspectRatio); } void GBAConfigFreeOpts(struct GBAOptions* opts) { diff --git a/src/gba/gba-config.h b/src/gba/gba-config.h index 88dba5e5f..59daf9ce8 100644 --- a/src/gba/gba-config.h +++ b/src/gba/gba-config.h @@ -28,6 +28,7 @@ struct GBAOptions { int fullscreen; int width; int height; + bool lockAspectRatio; bool videoSync; bool audioSync; diff --git a/src/platform/qt/Display.cpp b/src/platform/qt/Display.cpp index 6198b6711..82deb155b 100644 --- a/src/platform/qt/Display.cpp +++ b/src/platform/qt/Display.cpp @@ -53,6 +53,8 @@ void Display::startDrawing(const uint32_t* buffer, GBAThread* thread) { context()->moveToThread(m_drawThread); connect(m_drawThread, SIGNAL(started()), m_painter, SLOT(start())); m_drawThread->start(QThread::TimeCriticalPriority); + + lockAspectRatio(m_lockAspectRatio); } void Display::stopDrawing() { @@ -105,6 +107,13 @@ void Display::forceDraw() { } } +void Display::lockAspectRatio(bool lock) { + m_lockAspectRatio = lock; + if (m_drawThread) { + QMetaObject::invokeMethod(m_painter, "lockAspectRatio", Qt::QueuedConnection, Q_ARG(bool, lock)); + } +} + #ifdef USE_PNG void Display::screenshot() { GBAThreadInterrupt(m_context); @@ -131,6 +140,7 @@ void Display::resizeEvent(QResizeEvent* event) { Painter::Painter(Display* parent) : m_gl(parent) + , m_lockAspectRatio(false) { m_size = parent->size(); } @@ -145,11 +155,12 @@ void Painter::setBacking(const uint32_t* backing) { void Painter::resize(const QSize& size) { m_size = size; - m_gl->makeCurrent(); - glViewport(0, 0, m_size.width() * m_gl->devicePixelRatio(), m_size.height() * m_gl->devicePixelRatio()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - m_gl->swapBuffers(); - m_gl->doneCurrent(); + forceDraw(); +} + +void Painter::lockAspectRatio(bool lock) { + m_lockAspectRatio = lock; + forceDraw(); } void Painter::start() { @@ -181,12 +192,7 @@ void Painter::start() { void Painter::draw() { m_gl->makeCurrent(); if (GBASyncWaitFrameStart(&m_context->sync, m_context->frameskip)) { - glViewport(0, 0, m_size.width() * m_gl->devicePixelRatio(), m_size.height() * m_gl->devicePixelRatio()); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_backing); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - if (m_context->sync.videoFrameWait) { - glFlush(); - } + performDraw(); } GBASyncWaitFrameEnd(&m_context->sync); m_gl->swapBuffers(); @@ -195,12 +201,7 @@ void Painter::draw() { void Painter::forceDraw() { m_gl->makeCurrent(); - glViewport(0, 0, m_size.width() * m_gl->devicePixelRatio(), m_size.height() * m_gl->devicePixelRatio()); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_backing); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - if (m_context->sync.videoFrameWait) { - glFlush(); - } + performDraw(); m_gl->swapBuffers(); m_gl->doneCurrent(); } @@ -226,3 +227,25 @@ void Painter::pause() { void Painter::unpause() { m_drawTimer->start(); } + +void Painter::performDraw() { + glViewport(0, 0, m_size.width() * m_gl->devicePixelRatio(), m_size.height() * m_gl->devicePixelRatio()); + glClear(GL_COLOR_BUFFER_BIT); + int w = m_size.width() * m_gl->devicePixelRatio(); + int h = m_size.height() * m_gl->devicePixelRatio(); + int drawW = w; + int drawH = h; + if (m_lockAspectRatio) { + if (w * 2 > h * 3) { + drawW = h * 3 / 2; + } else if (w * 2 < h * 3) { + drawH = w * 2 / 3; + } + } + glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_backing); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + if (m_context->sync.videoFrameWait) { + glFlush(); + } +} diff --git a/src/platform/qt/Display.h b/src/platform/qt/Display.h index 97a96fa38..f06a81606 100644 --- a/src/platform/qt/Display.h +++ b/src/platform/qt/Display.h @@ -27,6 +27,7 @@ public slots: void pauseDrawing(); void unpauseDrawing(); void forceDraw(); + void lockAspectRatio(bool lock); #ifdef USE_PNG void screenshot(); #endif @@ -40,6 +41,7 @@ private: Painter* m_painter; QThread* m_drawThread; GBAThread* m_context; + bool m_lockAspectRatio; }; class Painter : public QObject { @@ -59,14 +61,18 @@ public slots: void pause(); void unpause(); void resize(const QSize& size); + void lockAspectRatio(bool lock); private: + void performDraw(); + QTimer* m_drawTimer; GBAThread* m_context; const uint32_t* m_backing; GLuint m_tex; QGLWidget* m_gl; QSize m_size; + bool m_lockAspectRatio; }; } diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 7a56d3d0e..215896e78 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -133,6 +133,7 @@ void Window::loadConfig() { m_controller->setFrameskip(opts->frameskip); m_controller->setAudioSync(opts->audioSync); m_controller->setVideoSync(opts->videoSync); + m_display->lockAspectRatio(opts->lockAspectRatio); if (opts->bios) { m_controller->loadBIOS(opts->bios); @@ -509,6 +510,11 @@ void Window::setupMenu(QMenuBar* menubar) { frameMenu->addAction(setSize); addAction(frameMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), QKeySequence("Ctrl+F"))); + ConfigOption* lockAspectRatio = m_config->addOption("lockAspectRatio"); + lockAspectRatio->addBoolean(tr("Lock aspect ratio"), avMenu); + lockAspectRatio->connect([this](const QVariant& value) { m_display->lockAspectRatio(value.toBool()); }); + m_config->updateOption("lockAspectRatio"); + QMenu* skipMenu = avMenu->addMenu(tr("Frame&skip")); ConfigOption* skip = m_config->addOption("frameskip"); skip->connect([this](const QVariant& value) { m_controller->setFrameskip(value.toInt()); });