all repos — mgba @ ad85acab75a674ec46850a2381323632dae0a83a

mGBA Game Boy Advance Emulator

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	, m_objInfo{}
 29{
 30	m_ui.setupUi(this);
 31	m_ui.tile->setController(controller);
 32
 33	const QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont);
 34
 35	m_ui.x->setFont(font);
 36	m_ui.y->setFont(font);
 37	m_ui.w->setFont(font);
 38	m_ui.h->setFont(font);
 39	m_ui.address->setFont(font);
 40	m_ui.priority->setFont(font);
 41	m_ui.palette->setFont(font);
 42	m_ui.transform->setFont(font);
 43	m_ui.mode->setFont(font);
 44
 45	connect(m_ui.tiles, SIGNAL(indexPressed(int)), this, SLOT(translateIndex(int)));
 46	connect(m_ui.objId, SIGNAL(valueChanged(int)), this, SLOT(selectObj(int)));
 47	connect(m_ui.magnification, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this]() {
 48		updateTiles(true);
 49	});
 50}
 51
 52void ObjView::selectObj(int obj) {
 53	m_objId = obj;
 54	updateTiles(true);
 55}
 56
 57void ObjView::translateIndex(int index) {
 58	unsigned x = index % m_objInfo.width;
 59	unsigned y = index / m_objInfo.width;
 60	m_ui.tile->selectIndex(x + y * m_objInfo.stride + m_tileOffset);
 61}
 62
 63#ifdef M_CORE_GBA
 64void ObjView::updateTilesGBA(bool force) {
 65	const GBA* gba = static_cast<const GBA*>(m_controller->thread()->core->board);
 66	const GBAObj* obj = &gba->video.oam.obj[m_objId];
 67
 68	unsigned shape = GBAObjAttributesAGetShape(obj->a);
 69	unsigned size = GBAObjAttributesBGetSize(obj->b);
 70	unsigned width = GBAVideoObjSizes[shape * 4 + size][0];
 71	unsigned height = GBAVideoObjSizes[shape * 4 + size][1];
 72	unsigned tile = GBAObjAttributesCGetTile(obj->c);
 73	ObjInfo newInfo{
 74		tile,
 75		width / 8,
 76		height / 8,
 77		width / 8
 78	};
 79	m_ui.tiles->setTileCount(width * height / 64);
 80	m_ui.tiles->setMinimumSize(QSize(width, height) * m_ui.magnification->value());
 81	unsigned palette = GBAObjAttributesCGetPalette(obj->c);
 82	GBARegisterDISPCNT dispcnt = gba->memory.io[0]; // FIXME: Register name can't be imported due to namespacing issues
 83	if (!GBARegisterDISPCNTIsObjCharacterMapping(dispcnt)) {
 84		newInfo.stride = 0x20 >> (GBAObjAttributesAGet256Color(obj->a));
 85	};
 86	if (newInfo != m_objInfo) {
 87		force = true;
 88	}
 89	m_objInfo = newInfo;
 90	int i = 0;
 91	if (GBAObjAttributesAIs256Color(obj->a)) {
 92		m_ui.palette->setText("256-color");
 93		mTileCacheSetPalette(m_tileCache.get(), 1);
 94		m_ui.tile->setPalette(0);
 95		m_ui.tile->setPaletteSet(1, 1024, 1536);
 96		tile /= 2;
 97		unsigned t = tile + i;
 98		for (int y = 0; y < height / 8; ++y) {
 99			for (int x = 0; x < width / 8; ++x, ++i, ++t) {
100				const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * t], t + 1024, 1);
101				if (data) {
102					m_ui.tiles->setTile(i, data);
103				} else if (force) {
104					m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), t + 1024, 1));
105				}
106			}
107			t += newInfo.stride - width / 8;
108		}
109		tile += 1024;
110	} else {
111		m_ui.palette->setText(QString::number(palette));
112		mTileCacheSetPalette(m_tileCache.get(), 0);
113		m_ui.tile->setPalette(palette);
114		m_ui.tile->setPaletteSet(0, 2048, 3072);
115		unsigned t = tile + i;
116		for (int y = 0; y < height / 8; ++y) {
117			for (int x = 0; x < width / 8; ++x, ++i, ++t) {
118				const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * t], t + 2048, palette + 16);
119				if (data) {
120					m_ui.tiles->setTile(i, data);
121				} else if (force) {
122					m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), t + 2048, palette + 16));
123				}
124			}
125			t += newInfo.stride - width / 8;
126		}
127		tile += 2048;
128	}
129	m_tileOffset = tile;
130
131	m_ui.x->setText(QString::number(GBAObjAttributesBGetX(obj->b)));
132	m_ui.y->setText(QString::number(GBAObjAttributesAGetY(obj->a)));
133	m_ui.w->setText(QString::number(width));
134	m_ui.h->setText(QString::number(height));
135
136	m_ui.address->setText(tr("0x%0").arg(BASE_OAM + m_objId * sizeof(*obj), 8, 16, QChar('0')));
137	m_ui.priority->setText(QString::number(GBAObjAttributesCGetPriority(obj->c)));
138	m_ui.flippedH->setChecked(GBAObjAttributesBIsHFlip(obj->b));
139	m_ui.flippedV->setChecked(GBAObjAttributesBIsVFlip(obj->b));
140	m_ui.enabled->setChecked(!GBAObjAttributesAIsDisable(obj->a) || GBAObjAttributesAIsTransformed(obj->a));
141	m_ui.doubleSize->setChecked(GBAObjAttributesAIsDoubleSize(obj->a) && GBAObjAttributesAIsTransformed(obj->a));
142	m_ui.mosaic->setChecked(GBAObjAttributesAIsMosaic(obj->a));
143
144	if (GBAObjAttributesAIsTransformed(obj->a)) {
145		m_ui.transform->setText(QString::number(GBAObjAttributesBGetMatIndex(obj->b)));
146	} else {
147		m_ui.transform->setText(tr("Off"));
148	}
149
150	switch (GBAObjAttributesAGetMode(obj->a)) {
151	case OBJ_MODE_NORMAL:
152		m_ui.mode->setText(tr("Normal"));
153		break;
154	case OBJ_MODE_SEMITRANSPARENT:
155		m_ui.mode->setText(tr("Trans"));
156		break;
157	case OBJ_MODE_OBJWIN:
158		m_ui.mode->setText(tr("OBJWIN"));
159		break;
160	default:
161		m_ui.mode->setText(tr("Invalid"));
162		break;
163	}
164}
165#endif
166
167#ifdef M_CORE_GB
168void ObjView::updateTilesGB(bool force) {
169	const GB* gb = static_cast<const GB*>(m_controller->thread()->core->board);
170	const GBObj* obj = &gb->video.oam.obj[m_objId];
171
172	unsigned width = 8;
173	unsigned height = 8;
174	GBRegisterLCDC lcdc = gb->memory.io[REG_LCDC];
175	if (GBRegisterLCDCIsObjSize(lcdc)) {
176		height = 16;
177	}
178	unsigned tile = obj->tile;
179	ObjInfo newInfo{
180		tile,
181		1,
182		height / 8,
183		1
184	};
185	if (newInfo != m_objInfo) {
186		force = true;
187	}
188	m_objInfo = newInfo;
189	m_ui.tiles->setTileCount(width * height / 64);
190	m_ui.tiles->setMinimumSize(QSize(width, height) * m_ui.magnification->value());
191	int palette = 0;
192	if (gb->model >= GB_MODEL_CGB) {
193		if (GBObjAttributesIsBank(obj->attr)) {
194			tile += 512;
195		}
196		palette = GBObjAttributesGetCGBPalette(obj->attr);
197	} else {
198		palette = GBObjAttributesGetPalette(obj->attr);
199	}
200	int i = 0;
201	m_ui.palette->setText(QString::number(palette));
202	mTileCacheSetPalette(m_tileCache.get(), 0);
203	m_ui.tile->setPalette(palette + 8);
204	m_ui.tile->setPaletteSet(0, 512, 1024);
205	for (int y = 0; y < height / 8; ++y, ++i) {
206		unsigned t = tile + i;
207		const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[16 * t], t, palette + 8);
208		if (data) {
209			m_ui.tiles->setTile(i, data);
210		} else if (force) {
211			m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), t, palette + 8));
212		}
213	}
214	m_tileOffset = tile;
215
216	m_ui.x->setText(QString::number(obj->x));
217	m_ui.y->setText(QString::number(obj->y));
218	m_ui.w->setText(QString::number(width));
219	m_ui.h->setText(QString::number(height));
220
221	m_ui.address->setText(tr("0x%0").arg(GB_BASE_OAM + m_objId * sizeof(*obj), 4, 16, QChar('0')));
222	m_ui.priority->setText(QString::number(GBObjAttributesGetPriority(obj->attr)));
223	m_ui.flippedH->setChecked(GBObjAttributesIsXFlip(obj->attr));
224	m_ui.flippedV->setChecked(GBObjAttributesIsYFlip(obj->attr));
225	m_ui.enabled->setChecked(obj->y != 0 && obj->y < 160);
226	m_ui.doubleSize->setChecked(false);
227	m_ui.mosaic->setChecked(false);
228	m_ui.transform->setText(tr("N/A"));
229	m_ui.mode->setText(tr("N/A"));
230}
231#endif
232
233
234bool ObjView::ObjInfo::operator!=(const ObjInfo& other) {
235	return other.tile != tile ||
236		other.width != width ||
237		other.height != height ||
238		other.stride != stride;
239}