src/platform/qt/ObjView.cpp (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "ObjView.h"
7
8#include "GBAApp.h"
9
10#include <QFontDatabase>
11#include <QTimer>
12
13extern "C" {
14#include "gba/gba.h"
15#ifdef M_CORE_GB
16#include "gb/gb.h"
17#include "gb/io.h"
18#endif
19}
20
21using namespace QGBA;
22
23ObjView::ObjView(GameController* controller, QWidget* parent)
24 : AssetView(controller, parent)
25 , m_controller(controller)
26 , m_tileStatus{}
27 , m_objId(0)
28{
29 m_ui.setupUi(this);
30 m_ui.tile->setController(controller);
31
32 const QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont);
33
34 m_ui.x->setFont(font);
35 m_ui.y->setFont(font);
36 m_ui.w->setFont(font);
37 m_ui.h->setFont(font);
38 m_ui.address->setFont(font);
39 m_ui.priority->setFont(font);
40 m_ui.palette->setFont(font);
41 m_ui.transform->setFont(font);
42 m_ui.mode->setFont(font);
43
44 connect(m_ui.tiles, SIGNAL(indexPressed(int)), this, SLOT(translateIndex(int)));
45 connect(m_ui.objId, SIGNAL(valueChanged(int)), this, SLOT(selectObj(int)));
46 connect(m_ui.magnification, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this]() {
47 updateTiles(true);
48 });
49}
50
51void ObjView::selectObj(int obj) {
52 m_objId = obj;
53 updateTiles(true);
54}
55
56void ObjView::translateIndex(int index) {
57 m_ui.tile->selectIndex(index + m_tileOffset);
58}
59
60#ifdef M_CORE_GBA
61void ObjView::updateTilesGBA(bool force) {
62 const GBA* gba = static_cast<const GBA*>(m_controller->thread()->core->board);
63 const GBAObj* obj = &gba->video.oam.obj[m_objId];
64
65 unsigned shape = GBAObjAttributesAGetShape(obj->a);
66 unsigned size = GBAObjAttributesBGetSize(obj->b);
67 unsigned width = GBAVideoObjSizes[shape * 4 + size][0];
68 unsigned height = GBAVideoObjSizes[shape * 4 + size][1];
69 m_ui.tiles->setTileCount(width * height / 64);
70 m_ui.tiles->setMinimumSize(QSize(width, height) * m_ui.magnification->value());
71 unsigned palette = GBAObjAttributesCGetPalette(obj->c);
72 unsigned tile = GBAObjAttributesCGetTile(obj->c);
73 GBARegisterDISPCNT dispcnt = gba->memory.io[0]; // FIXME: Register name can't be imported due to namespacing issues
74 int i = 0;
75 // TODO: Tile stride
76 // TODO: Check to see if parameters are changed (so as to enable force if needed)
77 if (GBAObjAttributesAIs256Color(obj->a)) {
78 m_ui.palette->setText("256-color");
79 mTileCacheSetPalette(m_tileCache.get(), 1);
80 m_ui.tile->setPalette(0);
81 m_ui.tile->setPaletteSet(1, 1024, 1536);
82 tile /= 2;
83 for (int y = 0; y < height / 8; ++y) {
84 for (int x = 0; x < width / 8; ++x, ++i) {
85 unsigned t = tile + i;
86 const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * t], t + 1024, 1);
87 if (data) {
88 m_ui.tiles->setTile(i, data);
89 } else if (force) {
90 m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), t + 1024, 1));
91 }
92 }
93 }
94 tile += 1024;
95 } else {
96 m_ui.palette->setText(QString::number(palette));
97 mTileCacheSetPalette(m_tileCache.get(), 0);
98 m_ui.tile->setPalette(palette);
99 m_ui.tile->setPaletteSet(0, 2048, 3072);
100 unsigned t = tile + i;
101 for (int y = 0; y < height / 8; ++y) {
102 for (int x = 0; x < width / 8; ++x, ++i, ++t) {
103 const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * t], t + 2048, palette + 16);
104 if (data) {
105 m_ui.tiles->setTile(i, data);
106 } else if (force) {
107 m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), t + 2048, palette + 16));
108 }
109 }
110 if (!GBARegisterDISPCNTIsObjCharacterMapping(dispcnt)) {
111 t += 0x20 - width / 8;
112 }
113 }
114 tile += 2048;
115 }
116 m_tileOffset = tile;
117
118 m_ui.x->setText(QString::number(GBAObjAttributesBGetX(obj->b)));
119 m_ui.y->setText(QString::number(GBAObjAttributesAGetY(obj->a)));
120 m_ui.w->setText(QString::number(width));
121 m_ui.h->setText(QString::number(height));
122
123 m_ui.address->setText(tr("0x%0").arg(BASE_OAM + m_objId * sizeof(*obj), 8, 16, QChar('0')));
124 m_ui.priority->setText(QString::number(GBAObjAttributesCGetPriority(obj->c)));
125 m_ui.flippedH->setChecked(GBAObjAttributesBIsHFlip(obj->b));
126 m_ui.flippedV->setChecked(GBAObjAttributesBIsVFlip(obj->b));
127 m_ui.enabled->setChecked(!GBAObjAttributesAIsDisable(obj->a) || GBAObjAttributesAIsTransformed(obj->a));
128 m_ui.doubleSize->setChecked(GBAObjAttributesAIsDoubleSize(obj->a) && GBAObjAttributesAIsTransformed(obj->a));
129 m_ui.mosaic->setChecked(GBAObjAttributesAIsMosaic(obj->a));
130
131 if (GBAObjAttributesAIsTransformed(obj->a)) {
132 m_ui.transform->setText(QString::number(GBAObjAttributesBGetMatIndex(obj->b)));
133 } else {
134 m_ui.transform->setText(tr("Off"));
135 }
136
137 switch (GBAObjAttributesAGetMode(obj->a)) {
138 case OBJ_MODE_NORMAL:
139 m_ui.mode->setText(tr("Normal"));
140 break;
141 case OBJ_MODE_SEMITRANSPARENT:
142 m_ui.mode->setText(tr("Trans"));
143 break;
144 case OBJ_MODE_OBJWIN:
145 m_ui.mode->setText(tr("OBJWIN"));
146 break;
147 default:
148 m_ui.mode->setText(tr("Invalid"));
149 break;
150 }
151}
152#endif
153
154#ifdef M_CORE_GB
155void ObjView::updateTilesGB(bool force) {
156 const GB* gb = static_cast<const GB*>(m_controller->thread()->core->board);
157 const GBObj* obj = &gb->video.oam.obj[m_objId];
158
159 unsigned width = 8;
160 unsigned height = 8; // TODO
161 GBRegisterLCDC lcdc = gb->memory.io[REG_LCDC];
162 if (GBRegisterLCDCIsObjSize(lcdc)) {
163 height = 16;
164 }
165 m_ui.tiles->setTileCount(width * height / 64);
166 m_ui.tiles->setMinimumSize(QSize(width, height) * m_ui.magnification->value());
167 int palette = 0;
168 unsigned tile = obj->tile;
169 if (gb->model >= GB_MODEL_CGB) {
170 if (GBObjAttributesIsBank(obj->attr)) {
171 tile += 512;
172 }
173 palette = GBObjAttributesGetCGBPalette(obj->attr);
174 } else {
175 palette = GBObjAttributesGetPalette(obj->attr);
176 }
177 int i = 0;
178 // TODO: Check to see if parameters are changed (so as to enable force if needed)
179 m_ui.palette->setText(QString::number(palette));
180 mTileCacheSetPalette(m_tileCache.get(), 0);
181 m_ui.tile->setPalette(palette + 8);
182 m_ui.tile->setPaletteSet(0, 512, 1024);
183 for (int y = 0; y < height / 8; ++y, ++i) {
184 unsigned t = tile + i;
185 const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[16 * t], t, palette + 8);
186 if (data) {
187 m_ui.tiles->setTile(i, data);
188 } else if (force) {
189 m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), t, palette + 8));
190 }
191 }
192 m_tileOffset = tile;
193
194 m_ui.x->setText(QString::number(obj->x));
195 m_ui.y->setText(QString::number(obj->y));
196 m_ui.w->setText(QString::number(width));
197 m_ui.h->setText(QString::number(height));
198
199 m_ui.address->setText(tr("0x%0").arg(GB_BASE_OAM + m_objId * sizeof(*obj), 4, 16, QChar('0')));
200 m_ui.priority->setText(QString::number(GBObjAttributesGetPriority(obj->attr)));
201 m_ui.flippedH->setChecked(GBObjAttributesIsXFlip(obj->attr));
202 m_ui.flippedV->setChecked(GBObjAttributesIsYFlip(obj->attr));
203 m_ui.enabled->setChecked(obj->y != 0 && obj->y < 160);
204 m_ui.doubleSize->setChecked(false);
205 m_ui.mosaic->setChecked(false);
206 m_ui.transform->setText(tr("N/A"));
207 m_ui.mode->setText(tr("N/A"));
208}
209#endif