all repos — mgba @ 4659635fb57e27c15bc2419130d5e0c9542d6fef

mGBA Game Boy Advance Emulator

Start Qt frontend
Jeffrey Pfau jeffrey@endrift.com
Tue, 28 Jan 2014 06:53:38 -0800
commit

4659635fb57e27c15bc2419130d5e0c9542d6fef

parent

f0481d94135b9f671bea3847559431e67a07bf48

M CMakeLists.txtCMakeLists.txt

@@ -4,6 +4,7 @@ set(BINARY_NAME gbac CACHE INTERNAL "Name of output binaries")

set(CMAKE_C_FLAGS_DEBUG "-g -Wall -Wextra -Wno-error=type-limits --std=gnu99") set(CMAKE_C_FLAGS_RELEASE "-O3 -Wall -Wextra --std=gnu99") set(USE_DEBUGGER ON CACHE BOOL "Whether or not to enable the ARM debugger") +set(BUILD_QT ON CACHE BOOL "Build Qt frontend") set(EXTRA_LIB "") file(GLOB ARM_SRC ${CMAKE_SOURCE_DIR}/src/arm/*.c) file(GLOB GBA_SRC ${CMAKE_SOURCE_DIR}/src/gba/*.c)

@@ -67,3 +68,7 @@

add_executable(${BINARY_NAME}-bin WIN32 ${MAIN_SRC}) target_link_libraries(${BINARY_NAME}-bin ${BINARY_NAME}) set_target_properties(${BINARY_NAME}-bin PROPERTIES OUTPUT_NAME ${BINARY_NAME}) + +if(BUILD_QT) + add_subdirectory(src/platform/qt) +endif()
A src/platform/qt/CMakeLists.txt

@@ -0,0 +1,24 @@

+cmake_minimum_required(VERSION 2.8.8) +project(QGBAc) + +set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wextra --std=c++11") +set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall -Wextra --std=c++11") + +if(APPLE) + set(CMAKE_PREFIX_PATH "/usr/local/opt/qt5") # Temporary stopgap measure +endif() + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +find_package(Qt5Widgets REQUIRED) + +set(UI_FILES Window.ui) +set(SOURCE_FILES Display.cpp GameController.cpp Window.cpp) + +qt5_wrap_ui(UI_HEADERS ${UI_FILES}) + +add_executable(QGBAc WIN32 MACOSX_BUNDLE ${UI_FILES} ${UI_HEADERS} main.cpp ${SOURCE_FILES}) + +qt5_use_modules(QGBAc Widgets OpenGL) +target_link_libraries(QGBAc ${OPENGL_LIBRARY} ${BINARY_NAME})
A src/platform/qt/Display.cpp

@@ -0,0 +1,56 @@

+#include "Display.h" + +#include <QTimer> + +using namespace QGBA; + +static const GLint _glVertices[] = { + 0, 0, + 256, 0, + 256, 256, + 0, 256 +}; + +static const GLint _glTexCoords[] = { + 0, 0, + 1, 0, + 1, 1, + 0, 1 +}; + +Display::Display(QWidget* parent) : QGLWidget(QGLFormat(QGL::Rgba | QGL::DoubleBuffer), parent) { + setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + QTimer* timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(updateGL())); + timer->setInterval(0); + timer->start(); +} + +void Display::initializeGL() { + glEnable(GL_TEXTURE_2D); + glGenTextures(1, &m_tex); + glBindTexture(GL_TEXTURE_2D, m_tex); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +} + +void Display::draw(const QImage& image) { + makeCurrent(); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits()); +} + +void Display::paintGL() { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_INT, 0, _glVertices); + glTexCoordPointer(2, GL_INT, 0, _glTexCoords); + glMatrixMode (GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, 240, 160, 0, 0, 1); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_tex); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +}
A src/platform/qt/Display.h

@@ -0,0 +1,27 @@

+#ifndef QGBA_DISPLAY +#define QGBA_DISPLAY + +#include <QGLWidget> + +namespace QGBA { + +class Display : public QGLWidget { +Q_OBJECT + +public: + Display(QWidget* parent = 0); + +protected: + virtual void initializeGL(); + +public slots: + void draw(const QImage& image); + void paintGL(); + +private: + GLuint m_tex; +}; + +} + +#endif
A src/platform/qt/GameController.cpp

@@ -0,0 +1,48 @@

+#include "GameController.h" + +extern "C" { +#include "renderers/video-software.h" +} + +using namespace QGBA; + +GameController::GameController(QObject* parent) + : QObject(parent) + , m_drawContext(256, 256, QImage::Format_RGB32) +{ + m_renderer = new GBAVideoSoftwareRenderer; + GBAVideoSoftwareRendererCreate(m_renderer); + m_renderer->outputBuffer = (color_t*) m_drawContext.bits(); + m_renderer->outputBufferStride = m_drawContext.bytesPerLine() / 4; + m_threadContext.useDebugger = 0; + m_threadContext.frameskip = 0; + m_threadContext.renderer = &m_renderer->d; + m_threadContext.frameskip = 0; + m_threadContext.sync.videoFrameWait = 0; + m_threadContext.sync.audioWait = 0; + m_threadContext.startCallback = 0; + m_threadContext.cleanCallback = 0; + m_threadContext.frameCallback = [] (GBAThread* context) { + GameController* controller = (GameController*) context->userData; + controller->frameAvailable(controller->m_drawContext); + }; + m_threadContext.userData = this; + m_threadContext.rewindBufferCapacity = 0; +} + +GameController::~GameController() { + delete m_renderer; +} + +bool GameController::loadGame(const QString& path) { + m_rom = new QFile(path); + if (!m_rom->open(QIODevice::ReadOnly)) { + delete m_rom; + m_rom = 0; + return false; + } + m_threadContext.fd = m_rom->handle(); + m_threadContext.fname = path.toLocal8Bit().constData(); + GBAThreadStart(&m_threadContext); + return true; +}
A src/platform/qt/GameController.h

@@ -0,0 +1,41 @@

+#ifndef QGBA_GAME_CONTROLLER +#define QGBA_GAME_CONTROLLER + +#include <QFile> +#include <QImage> +#include <QObject> +#include <QString> + +extern "C" { +#include "gba-thread.h" +} + +struct GBAVideoSoftwareRenderer; + +namespace QGBA { + +class GameController : public QObject { +Q_OBJECT + +public: + GameController(QObject* parent = 0); + ~GameController(); + +signals: + void frameAvailable(const QImage&); + +public slots: + bool loadGame(const QString& path); + +private: + QImage m_drawContext; + GBAThread m_threadContext; + GBAVideoSoftwareRenderer* m_renderer; + + QFile* m_rom; + QFile* m_bios; +}; + +} + +#endif
A src/platform/qt/Window.cpp

@@ -0,0 +1,23 @@

+#include "Window.h" + +#include <QFileDialog> + +using namespace QGBA; + +Window::Window(QWidget* parent) : QMainWindow(parent) { + setupUi(this); + + m_controller = new GameController(this); + m_display = new Display(this); + setCentralWidget(m_display); + connect(m_controller, SIGNAL(frameAvailable(const QImage&)), m_display, SLOT(draw(const QImage&))); + + connect(actionOpen, SIGNAL(triggered()), this, SLOT(selectROM())); +} + +void Window::selectROM() { + QString filename = QFileDialog::getOpenFileName(this, tr("Select ROM")); + if (!filename.isEmpty()) { + m_controller->loadGame(filename); + } +}
A src/platform/qt/Window.h

@@ -0,0 +1,29 @@

+#ifndef QGBA_WINDOW +#define QGBA_WINDOW + +#include <QMainWindow> + +#include "GameController.h" +#include "Display.h" + +#include "ui_Window.h" + +namespace QGBA { + +class Window : public QMainWindow, Ui::GBAWindow { +Q_OBJECT + +public: + Window(QWidget* parent = 0); + +public slots: + void selectROM(); + +private: + GameController* m_controller; + Display* m_display; +}; + +} + +#endif
A src/platform/qt/Window.ui

@@ -0,0 +1,73 @@

+<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>GBAWindow</class> + <widget class="QMainWindow" name="GBAWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>240</width> + <height>160</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Ignored" vsizetype="Ignored"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="baseSize"> + <size> + <width>240</width> + <height>160</height> + </size> + </property> + <property name="windowTitle"> + <string>GBA</string> + </property> + <widget class="QWidget" name="centralwidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Ignored" vsizetype="Ignored"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="baseSize"> + <size> + <width>240</width> + <height>160</height> + </size> + </property> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>240</width> + <height>22</height> + </rect> + </property> + <property name="defaultUp"> + <bool>false</bool> + </property> + <widget class="QMenu" name="menuFile"> + <property name="title"> + <string>File</string> + </property> + <addaction name="actionOpen"/> + </widget> + <addaction name="menuFile"/> + </widget> + <action name="actionOpen"> + <property name="text"> + <string>Open</string> + </property> + <property name="shortcut"> + <string>Ctrl+O</string> + </property> + </action> + </widget> + <resources/> + <connections/> +</ui>
A src/platform/qt/main.cpp

@@ -0,0 +1,10 @@

+#include <QApplication> +#include "Window.h" + +int main(int argc, char* argv[]) { + QApplication application(argc, argv); + QGBA::Window window; + window.show(); + + return application.exec(); +}