Qt: First pass at a tile view
Jeffrey Pfau jeffrey@endrift.com
Fri, 22 Jul 2016 01:05:49 -0700
8 files changed,
448 insertions(+),
0 deletions(-)
M
src/platform/qt/CMakeLists.txt
→
src/platform/qt/CMakeLists.txt
@@ -102,6 +102,8 @@ ShaderSelector.cpp
ShortcutController.cpp ShortcutView.cpp Swatch.cpp + TilePainter.cpp + TileView.cpp Window.cpp VFileDevice.cpp VideoView.cpp)@@ -121,6 +123,7 @@ SensorView.ui
SettingsView.ui ShaderSelector.ui ShortcutView.ui + TileView.ui VideoView.ui) set(QT_LIBRARIES)
A
src/platform/qt/TilePainter.cpp
@@ -0,0 +1,40 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "TilePainter.h" + +#include <QImage> +#include <QMouseEvent> +#include <QPainter> + +using namespace QGBA; + +TilePainter::TilePainter(QWidget* parent) + : QWidget(parent) +{ + m_backing = QPixmap(256, 768); + m_backing.fill(Qt::transparent); +} + +void TilePainter::paintEvent(QPaintEvent* event) { + QPainter painter(this); + painter.drawPixmap(QPoint(), m_backing); +} + +void TilePainter::mousePressEvent(QMouseEvent* event) { + int x = event->x() / 8; + int y = event->y() / 8; + emit indexPressed(y * 32 + x); +} + +void TilePainter::setTile(int index, const uint16_t* data) { + QPainter painter(&m_backing); + int x = index & 31; + int y = index / 32; + QRect r(x * 8, y * 8, 8, 8); + QImage tile(reinterpret_cast<const uchar*>(data), 8, 8, QImage::Format_RGB555); + painter.fillRect(r, tile.rgbSwapped()); + update(r); +}
A
src/platform/qt/TilePainter.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef QGBA_TILE_PAINTER +#define QGBA_TILE_PAINTER + +#include <QColor> +#include <QWidget> +#include <QVector> + +namespace QGBA { + +class TilePainter : public QWidget { +Q_OBJECT + +public: + TilePainter(QWidget* parent = nullptr); + +public slots: + void setTile(int index, const uint16_t*); + +signals: + void indexPressed(int index); + +protected: + void paintEvent(QPaintEvent*) override; + void mousePressEvent(QMouseEvent*) override; + +private: + QPixmap m_backing; +}; + +} + +#endif
A
src/platform/qt/TileView.cpp
@@ -0,0 +1,111 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "TileView.h" + +#include "GBAApp.h" + +#include <QFontDatabase> + +extern "C" { +#include "gba/gba.h" +} + +using namespace QGBA; + +TileView::TileView(GameController* controller, QWidget* parent) + : QWidget(parent) + , m_controller(controller) + , m_paletteId(0) +{ + m_ui.setupUi(this); + GBAVideoTileCacheInit(&m_tileCache); + + m_ui.preview->setDimensions(QSize(8, 8)); + updateTiles(); + + const QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont); + + m_ui.tileId->setFont(font); + m_ui.address->setFont(font); + + connect(m_controller, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(updateTiles())); + connect(m_controller, SIGNAL(gameStopped(mCoreThread*)), this, SLOT(close())); + connect(m_ui.tiles, SIGNAL(indexPressed(int)), this, SLOT(selectIndex(int))); + connect(m_ui.paletteId, SIGNAL(valueChanged(int)), this, SLOT(updatePalette(int))); + connect(m_ui.palette256, SIGNAL(toggled(bool)), this, SLOT(updateTiles())); +} + +TileView::~TileView() { + GBAVideoTileCacheDeinit(&m_tileCache); +} + +void TileView::selectIndex(int index) { + const uint16_t* data; + m_ui.tileId->setText(QString::number(index)); + if (m_ui.palette256->isChecked()) { + m_ui.address->setText(tr("0x%0").arg(index * 64 | BASE_VRAM, 8, 16, QChar('0'))); + if (index < 1024) { + data = GBAVideoTileCacheGetTile256(&m_tileCache, index, 0); + } else { + data = GBAVideoTileCacheGetTile256(&m_tileCache, index, 1); + } + } else { + m_ui.address->setText(tr("0x%0").arg(index * 32 | BASE_VRAM, 8, 16, QChar('0'))); + if (index < 2048) { + data = GBAVideoTileCacheGetTile16(&m_tileCache, index, m_paletteId); + } else { + data = GBAVideoTileCacheGetTile16(&m_tileCache, index, m_paletteId + 16); + } + } + for (int i = 0; i < 64; ++i) { + m_ui.preview->setColor(i, data[i]); + } + m_ui.preview->update(); +} + +void TileView::updateTiles() { + if (!m_controller->thread() || !m_controller->thread()->core) { + return; + } + + GBA* gba = static_cast<GBA*>(m_controller->thread()->core->board); + GBAVideoTileCacheAssociate(&m_tileCache, &gba->video); + + if (m_ui.palette256->isChecked()) { + m_ui.tiles->setMinimumSize(256, 384); + for (int i = 0; i < 1024; ++i) { + const uint16_t* data = GBAVideoTileCacheGetTile256IfDirty(&m_tileCache, i, 0); + if (data) { + m_ui.tiles->setTile(i, data); + } + } + for (int i = 1024; i < 1536; ++i) { + const uint16_t* data = GBAVideoTileCacheGetTile256IfDirty(&m_tileCache, i, 1); + if (data) { + m_ui.tiles->setTile(i, data); + } + } + } else { + m_ui.tiles->setMinimumSize(256, 768); + for (int i = 0; i < 2048; ++i) { + const uint16_t* data = GBAVideoTileCacheGetTile16IfDirty(&m_tileCache, i, m_paletteId); + if (data) { + m_ui.tiles->setTile(i, data); + } + } + for (int i = 2048; i < 3072; ++i) { + const uint16_t* data = GBAVideoTileCacheGetTile16IfDirty(&m_tileCache, i, m_paletteId + 16); + if (data) { + m_ui.tiles->setTile(i, data); + } + } + } +} + +void TileView::updatePalette(int palette) { + m_paletteId = palette; + updateTiles(); +}
A
src/platform/qt/TileView.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef QGBA_TILE_VIEW +#define QGBA_TILE_VIEW + +#include <QWidget> + +#include "GameController.h" + +#include "ui_TileView.h" + +extern "C" { +#include "gba/renderers/tile-cache.h" +} + +namespace QGBA { + +class TileView : public QWidget { +Q_OBJECT + +public: + TileView(GameController* controller, QWidget* parent = nullptr); + virtual ~TileView(); + +public slots: + void updateTiles(); + void updatePalette(int); + +private slots: + void selectIndex(int); + +private: + Ui::TileView m_ui; + + GameController* m_controller; + GBAVideoTileCache m_tileCache; + int m_paletteId; +}; + +} + +#endif
A
src/platform/qt/TileView.ui
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>TileView</class> + <widget class="QWidget" name="TileView"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>288</width> + <height>269</height> + </rect> + </property> + <property name="windowTitle"> + <string>Tiles</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0"> + <widget class="QCheckBox" name="palette256"> + <property name="text"> + <string>256 colors</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Preview</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </spacer> + </item> + <item> + <widget class="QGBA::Swatch" name="preview" native="true"> + <property name="minimumSize"> + <size> + <width>87</width> + <height>87</height> + </size> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Tile #</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="tileId"> + <property name="text"> + <string>0</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Address</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="address"> + <property name="text"> + <string>0x06000000</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item row="0" column="0"> + <widget class="QSlider" name="paletteId"> + <property name="maximum"> + <number>15</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBelow</enum> + </property> + </widget> + </item> + <item row="0" column="1" rowspan="3"> + <widget class="QScrollArea" name="scrollArea"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>16</width> + <height>16</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGBA::TilePainter" name="tiles" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QGBA::TilePainter</class> + <extends>QWidget</extends> + <header>TilePainter.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>QGBA::Swatch</class> + <extends>QWidget</extends> + <header>Swatch.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui>
M
src/platform/qt/Window.cpp
→
src/platform/qt/Window.cpp
@@ -30,6 +30,7 @@ #include "MultiplayerController.h"
#include "MemoryView.h" #include "OverrideView.h" #include "PaletteView.h" +#include "TileView.h" #include "ROMInfo.h" #include "SensorView.h" #include "SettingsView.h"@@ -428,6 +429,11 @@
void Window::openPaletteWindow() { PaletteView* paletteWindow = new PaletteView(m_controller); openView(paletteWindow); +} + +void Window::openTileWindow() { + TileView* tileWindow = new TileView(m_controller); + openView(tileWindow); } void Window::openMemoryWindow() {@@ -1287,6 +1293,12 @@ connect(paletteView, SIGNAL(triggered()), this, SLOT(openPaletteWindow()));
m_gameActions.append(paletteView); m_gbaActions.append(paletteView); addControlledAction(toolsMenu, paletteView, "paletteWindow"); + + QAction* tileView = new QAction(tr("View &tiles..."), toolsMenu); + connect(tileView, SIGNAL(triggered()), this, SLOT(openTileWindow())); + m_gameActions.append(tileView); + m_gbaActions.append(tileView); + addControlledAction(toolsMenu, tileView, "tileWindow"); QAction* memoryView = new QAction(tr("View memory..."), toolsMenu); connect(memoryView, SIGNAL(triggered()), this, SLOT(openMemoryWindow()));
M
src/platform/qt/Window.h
→
src/platform/qt/Window.h
@@ -82,6 +82,7 @@ void openSensorWindow();
void openCheatsWindow(); void openPaletteWindow(); + void openTileWindow(); void openMemoryWindow(); void openIOViewer();