From a3bd875d77b4b0df7c7878c10a5a70f68efebbe3 Mon Sep 17 00:00:00 2001 From: Nathaniel van Diepen Date: Thu, 11 Jan 2024 23:03:02 -0700 Subject: [PATCH] Add black and white mode --- src/FilePicker.qml | 2 +- src/gameboy.h | 60 ++++++++++++++++++++++++++++++++++++++++++--- src/gameboy.oxide | 3 ++- src/gameboythread.h | 2 +- src/main.qml | 16 +++++++++--- 5 files changed, 73 insertions(+), 10 deletions(-) diff --git a/src/FilePicker.qml b/src/FilePicker.qml index fcc6de4..85f5af0 100644 --- a/src/FilePicker.qml +++ b/src/FilePicker.qml @@ -42,7 +42,7 @@ Item { Component { id: fileDelegate Clickable { - visible: fileName != "." + visible: fileName !== "." text: fileName !== ".." ? fileName + (fileIsDir ? "/" : "") : "(Parent Directory)" width: { if(parent == undefined){ diff --git a/src/gameboy.h b/src/gameboy.h index 4ec3f66..216653f 100644 --- a/src/gameboy.h +++ b/src/gameboy.h @@ -5,8 +5,14 @@ #include #include #include +#include +#include #include +#ifdef EPAPER +#include +#endif + #include "gameboythread.h" class Gameboy : public QQuickPaintedItem { @@ -14,6 +20,7 @@ class Gameboy : public QQuickPaintedItem { Q_PROPERTY(bool running READ running NOTIFY runningChanged REVISION 1) Q_PROPERTY(bool paused READ paused NOTIFY pausedChanged REVISION 1) Q_PROPERTY(bool slowedDown READ slowedDown NOTIFY slowedDownChanged REVISION 1) + Q_PROPERTY(bool greyscale READ isGreyscale WRITE setGreyscale NOTIFY greyscaleChanged REVISION 1) Q_PROPERTY(QString homeFolder READ homeFolder CONSTANT REVISION 1) Q_PROPERTY(QString romsFolder READ romsFolder CONSTANT REVISION 1) Q_PROPERTY(QString romName READ romName NOTIFY romNameChanged REVISION 1) @@ -21,7 +28,8 @@ class Gameboy : public QQuickPaintedItem { public: explicit Gameboy(QQuickItem* parent = nullptr) - : QQuickPaintedItem(parent) + : QQuickPaintedItem(parent), + greyscale(true) { image = nullptr; connect(this, &Gameboy::runningChanged, [this](bool){ @@ -32,18 +40,20 @@ class Gameboy : public QQuickPaintedItem { } }); thread = new GameboyThread(this); - connect(thread, &GameboyThread::updated, this, [this]{ update(rect()); }, Qt::QueuedConnection); + connect(thread, &GameboyThread::updated, this, &Gameboy::updated, Qt::QueuedConnection); connect(thread, &GameboyThread::started, this, [this]{ emit runningChanged(running()); }, Qt::QueuedConnection); connect(thread, &GameboyThread::finished, this, [this]{ emit runningChanged(running()); }, Qt::QueuedConnection); connect(thread, &GameboyThread::paused, this, [this]{ emit pausedChanged(true); }, Qt::QueuedConnection); connect(thread, &GameboyThread::resumed, this, [this]{ emit pausedChanged(false); }, Qt::QueuedConnection); connect(thread, &GameboyThread::slowedDownChanged, this, &Gameboy::slowedDownChanged, Qt::QueuedConnection); connect(thread, &GameboyThread::romNameChanged, this, &Gameboy::romNameChanged, Qt::QueuedConnection); +#ifdef EPAPER + screenCentre = qGuiApp->primaryScreen()->geometry().center(); +#endif } ~Gameboy(){ delete thread; } - QRect rect(){ return QRect(0, 0, width(), height()); } bool running(){ return thread->isRunning(); } bool paused(){ return thread->isPaused(); } Q_REVISION(1) Q_INVOKABLE void loadROM(QString path){ thread->loadROM(path); } @@ -63,21 +73,63 @@ class Gameboy : public QQuickPaintedItem { } bool slowedDown(){ return thread->slowedDown(); } QString romName(){ return thread->romName(); } + bool isGreyscale(){ return greyscale; } + void setGreyscale(bool value){ + greyscale = value; + emit greyscaleChanged(greyscale); + } signals: void runningChanged(bool); void pausedChanged(bool); void slowedDownChanged(bool); void romNameChanged(QString); + void greyscaleChanged(bool); + +protected slots: + void updated(){ + QRect rect = boundingRect().toRect(); +#ifdef EPAPER + rect.moveCenter(screenCentre); + QPainter painter(EPFrameBuffer::instance()->framebuffer()); + painter.drawImage(rect, *image, image->rect()); + painter.end(); + EPFrameBuffer::sendUpdate( + rect, + greyscale ? EPFrameBuffer::Grayscale : EPFrameBuffer::Mono, + EPFrameBuffer::PartialUpdate + ); +#else + update(rect); +#endif + } protected: void paint(QPainter* painter){ +#ifndef EPAPER if(image != nullptr){ - painter->drawImage(rect(), *image, image->rect()); + painter->drawImage( + boundingRect(), + greyscale ? *image : monoImage(), + image->rect() + ); } +#else + Q_UNUSED(painter) +#endif + } +#ifndef EPAPER + QImage monoImage(){ + return image->convertToFormat( + QImage::Format_Mono, + Qt::MonoOnly | Qt::DiffuseDither | Qt::DiffuseAlphaDither | Qt::PreferDither + ); } +#endif private: QImage* image; GameboyThread* thread; + QPoint screenCentre; + bool greyscale; }; diff --git a/src/gameboy.oxide b/src/gameboy.oxide index 4fbd520..9ed1905 100644 --- a/src/gameboy.oxide +++ b/src/gameboy.oxide @@ -4,5 +4,6 @@ "bin": "/opt/bin/gameboy", "icon": "oxide:gameboy-48", "splash": "oxide:splash:gameboy-48", - "type": "foreground" + "type": "foreground", + "flags": ["preload.qt"] } diff --git a/src/gameboythread.h b/src/gameboythread.h index 2960ea9..602f35e 100644 --- a/src/gameboythread.h +++ b/src/gameboythread.h @@ -113,7 +113,7 @@ class GameboyThread : public QThread{ qDebug() << "Starting emulation"; pauseRequested = false; int thirds = 0; - auto lastFrame = std::chrono::steady_clock::now();; + auto lastFrame = std::chrono::steady_clock::now(); while(!isInterruptionRequested()){ if(pauseRequested){ mutex.lock(); diff --git a/src/main.qml b/src/main.qml index 2de87e1..efb17ed 100644 --- a/src/main.qml +++ b/src/main.qml @@ -115,7 +115,6 @@ ApplicationWindow { ColumnLayout { id: speedButtons - enabled: gameboy.running anchors.bottom: { if(gameboyContainer.bottom < buttonUp.top){ return gameboyContainer.bottom @@ -130,7 +129,7 @@ ApplicationWindow { } anchors.right: gameboyContainer.left anchors.rightMargin: 20 - width: 150 + width: 180 Clickable { text: "1x" onClicked: gameboyContainer.scale = 1 @@ -166,6 +165,14 @@ ApplicationWindow { Layout.fillWidth: true backgroundColor: "white" } + Clickable { + text: gameboy.greyscale ? "Greyscale" : "B&W" + color: "black" + backgroundColor: gameboy.greyscale ? "grey" : "white" + onClicked: gameboy.greyscale = !gameboy.greyscale + border: 1 + Layout.fillWidth: true + } } Rectangle { @@ -203,7 +210,7 @@ ApplicationWindow { } anchors.left: gameboyContainer.right anchors.leftMargin: 20 - width: 150 + width: speedButtons.width Clickable { id: stopButton @@ -407,6 +414,9 @@ ApplicationWindow { from: "*"; to: "picker" SequentialAnimation { ScriptAction { script: { + if(gameboy.running && !gameboy.paused){ + gameboy.toggle(); + } console.log("Showing file picker"); picker.currentIndex = -1; picker.forceActiveFocus();