Skip to content

Commit

Permalink
Tile Viewer WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
fleroviux committed Feb 14, 2024
1 parent a30da20 commit d26b39c
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/platform/qt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ set(SOURCES
src/widget/debugger/ppu/sprite_viewer_window.cpp
src/widget/debugger/ppu/palette_box.cpp
src/widget/debugger/ppu/palette_viewer_window.cpp
src/widget/debugger/ppu/tile_viewer.cpp
src/widget/debugger/ppu/tile_viewer_window.cpp
src/widget/controller_manager.cpp
src/widget/input_window.cpp
src/widget/main_window.cpp
Expand All @@ -23,6 +25,8 @@ set(HEADERS
src/widget/debugger/ppu/palette_viewer_window.hpp
src/widget/debugger/ppu/sprite_viewer.hpp
src/widget/debugger/ppu/sprite_viewer_window.hpp
src/widget/debugger/ppu/tile_viewer.hpp
src/widget/debugger/ppu/tile_viewer_window.hpp
src/widget/debugger/utility.hpp
src/widget/controller_manager.hpp
src/widget/input_window.hpp
Expand Down
145 changes: 145 additions & 0 deletions src/platform/qt/src/widget/debugger/ppu/tile_viewer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* Copyright (C) 2024 fleroviux
*
* Licensed under GPLv3 or any later version.
* Refer to the included LICENSE file.
*/

#include <fmt/format.h>
#include <nba/common/punning.hpp>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QPainter>
#include <QRadioButton>
#include <QVBoxLayout>

#include "widget/debugger/utility.hpp"
#include "tile_viewer.hpp"

TileViewer::TileViewer(nba::CoreBase* core, QWidget* parent) : QWidget(parent) {
vram = core->GetVRAM();
pram = (u16*)core->GetPRAM();

QHBoxLayout* hbox = new QHBoxLayout{};

{
QVBoxLayout* vbox = new QVBoxLayout{};

magnification_input = new QSpinBox{};
magnification_input->setMinimum(1);
magnification_input->setMaximum(16);
vbox->addWidget(magnification_input);

palette_input = new QSpinBox{};
palette_input->setMinimum(0);
palette_input->setMaximum(15);
vbox->addWidget(palette_input);

QGroupBox* tile_base_group_box = new QGroupBox{};
tile_base_group_box->setTitle(tr("Tile Base"));

QVBoxLayout* tile_base_vbox = new QVBoxLayout{};

for(u32 tile_base = 0x06000000u; tile_base <= 0x06010000u; tile_base += 0x4000u) {
QRadioButton* radio_button = new QRadioButton{
QString::fromStdString(fmt::format("0x{:08X}", tile_base))};

connect(radio_button, &QRadioButton::pressed, [this, tile_base]() {
this->tile_base = tile_base & 0xFFFFFFu;
});

tile_base_vbox->addWidget(radio_button);

if(tile_base == 0x06000000u) radio_button->click();
}

tile_base_group_box->setLayout(tile_base_vbox);

vbox->addWidget(tile_base_group_box);

hbox->addLayout(vbox);
}

canvas = new QWidget{};
canvas->installEventFilter(this);
hbox->addWidget(canvas);

setLayout(hbox);
}

bool TileViewer::eventFilter(QObject* object, QEvent* event) {
if(object == canvas && event->type() == QEvent::Paint) {
const int canvas_w = canvas->size().width();
const int canvas_h = canvas->size().height();

const QRect src_rect{0, 0, 256, 256 * canvas_h / canvas_w};
const QRect dst_rect{0, 0, canvas_w, canvas_h};

QPainter painter{canvas};
painter.drawImage(dst_rect, image_rgb32, src_rect);
return true;
}

return false;
}

void TileViewer::Update() {
if(!isVisible()) {
return;
}

const int magnification = magnification_input->value();
const int palette_offset = tile_base == 0x10000u ? 256 : 0;

u32* const buffer = (u32*)image_rgb32.bits();

int height = 256;
u32 tile_address = tile_base;

if(eight_bpp) {
u16* const palette = &pram[palette_offset];

for(int tile = 0; tile < 512; tile++) {
const int tile_base_x = (tile % 32) * 8;
const int tile_base_y = (tile / 32) * 8;

for(int y = 0; y < 8; y++) {
u64 tile_row_data = nba::read<u64>(vram, tile_address);

for(int x = 0; x < 8; x++) {
buffer[(tile_base_y + y) * 256 + tile_base_x + x] = Rgb565ToArgb8888(palette[(u8)tile_row_data]);
tile_row_data >>= 8;
}

tile_address += sizeof(u64);
}
}

height /= 2;
} else {
u16* const palette = &pram[palette_input->value() * 16 + palette_offset];

for(int tile = 0; tile < 1024; tile++) {
const int tile_base_x = (tile % 32) * 8;
const int tile_base_y = (tile / 32) * 8;

for(int y = 0; y < 8; y++) {
u32 tile_row_data = nba::read<u32>(vram, tile_address);

for(int x = 0; x < 8; x++) {
buffer[(tile_base_y + y) * 256 + tile_base_x + x] = Rgb565ToArgb8888(palette[tile_row_data & 15]);
tile_row_data >>= 4;
}

tile_address += sizeof(u32);
}
}
}

if(tile_base == 0xC000u) {
height /= 2;
}

canvas->setFixedSize(256 * magnification, height * magnification);
canvas->update();
}
36 changes: 36 additions & 0 deletions src/platform/qt/src/widget/debugger/ppu/tile_viewer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2024 fleroviux
*
* Licensed under GPLv3 or any later version.
* Refer to the included LICENSE file.
*/

#pragma once

#include <nba/core.hpp>
#include <QLabel>
#include <QPaintEvent>
#include <QSpinBox>
#include <QWidget>

struct TileViewer : QWidget {
TileViewer(nba::CoreBase* core, QWidget* parent = nullptr);

bool eventFilter(QObject* object, QEvent* event) override;

void Update();

private:
u8* vram;
u16* pram;
QImage image_rgb32{256, 256, QImage::Format_RGB32};
QSpinBox* palette_input;
QSpinBox* magnification_input;
QWidget* canvas;

u32 tile_base = 0;
bool eight_bpp = false;
//int palette_index = 0;

Q_OBJECT
};
28 changes: 28 additions & 0 deletions src/platform/qt/src/widget/debugger/ppu/tile_viewer_window.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2024 fleroviux
*
* Licensed under GPLv3 or any later version.
* Refer to the included LICENSE file.
*/

#include <QVBoxLayout>

#include "tile_viewer_window.hpp"

TileViewerWindow::TileViewerWindow(nba::CoreBase* core, QWidget* parent) : QDialog(parent) {
const auto vbox = new QVBoxLayout{};

tile_viewer = new TileViewer{core, nullptr};
vbox->addWidget(tile_viewer);
setLayout(vbox);

setWindowTitle(tr("Tile Viewer"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
}

void TileViewerWindow::Update() {
if(!isVisible()) {
return;
}
tile_viewer->Update();
}
26 changes: 26 additions & 0 deletions src/platform/qt/src/widget/debugger/ppu/tile_viewer_window.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2024 fleroviux
*
* Licensed under GPLv3 or any later version.
* Refer to the included LICENSE file.
*/

#pragma once

#include <nba/core.hpp>
#include <QDialog>
#include <QLabel>

#include "tile_viewer.hpp"

struct TileViewerWindow : QDialog {
TileViewerWindow(nba::CoreBase* core, QWidget* parent = nullptr);

public slots:
void Update();

private:
TileViewer* tile_viewer;

Q_OBJECT
};
9 changes: 9 additions & 0 deletions src/platform/qt/src/widget/main_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,15 @@ void MainWindow::CreateToolsMenu() {
background_viewer_window->show();
});

connect(tools_menu->addAction(tr("Tile Viewer")), &QAction::triggered, [this]() {
if(!tile_viewer_window) {
tile_viewer_window = new TileViewerWindow{core_not_thread_safe, this};
connect(screen.get(), &Screen::RequestDraw, tile_viewer_window, &TileViewerWindow::Update);
}

tile_viewer_window->show();
});

connect(tools_menu->addAction(tr("Sprite Viewer")), &QAction::triggered, [this]() {
const auto sprite_viewer_window = new SpriteViewerWindow{core_not_thread_safe, this};
connect(screen.get(), &Screen::RequestDraw, sprite_viewer_window, &SpriteViewerWindow::Update);
Expand Down
6 changes: 4 additions & 2 deletions src/platform/qt/src/widget/main_window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@
#include <vector>

#include "widget/debugger/ppu/background_viewer_window.hpp"
#include "widget/debugger/ppu/palette_viewer_window.hpp"
#include "widget/debugger/ppu/sprite_viewer_window.hpp"
#include "widget/debugger/ppu/tile_viewer_window.hpp"
#include "widget/controller_manager.hpp"
#include "widget/input_window.hpp"
#include "widget/debugger/ppu/palette_viewer_window.hpp"
#include "widget/screen.hpp"
#include "widget/debugger/ppu/sprite_viewer_window.hpp"
#include "config.hpp"

struct MainWindow : QMainWindow {
Expand Down Expand Up @@ -155,6 +156,7 @@ private slots:

PaletteViewerWindow* palette_viewer_window;
BackgroundViewerWindow* background_viewer_window;
TileViewerWindow* tile_viewer_window;

QString base_window_title;

Expand Down

0 comments on commit d26b39c

Please sign in to comment.