all repos — mgba @ f3b66397a2a598e5cfb63acd0c0b84f5796d0802

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