all repos — mgba @ 86efc6cc9f138ef54e4478b76cc91c0bb173362d

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 "CoreController.h"
  9#include "GBAApp.h"
 10
 11#include <QFontDatabase>
 12#include <QTimer>
 13
 14#include "LogController.h"
 15#include "VFileDevice.h"
 16
 17#ifdef M_CORE_GBA
 18#include <mgba/internal/gba/gba.h>
 19#endif
 20#ifdef M_CORE_GB
 21#include <mgba/internal/gb/gb.h>
 22#endif
 23#include <mgba-util/vfs.h>
 24
 25using namespace QGBA;
 26
 27ObjView::ObjView(std::shared_ptr<CoreController> controller, QWidget* parent)
 28	: AssetView(controller, parent)
 29	, m_controller(controller)
 30{
 31	m_ui.setupUi(this);
 32	m_ui.tile->setController(controller);
 33
 34	const QFont font = QFontDatabase::systemFont(QFontDatabase::FixedFont);
 35
 36	m_ui.x->setFont(font);
 37	m_ui.y->setFont(font);
 38	m_ui.w->setFont(font);
 39	m_ui.h->setFont(font);
 40	m_ui.address->setFont(font);
 41	m_ui.priority->setFont(font);
 42	m_ui.palette->setFont(font);
 43	m_ui.transform->setFont(font);
 44	m_ui.mode->setFont(font);
 45
 46	connect(m_ui.tiles, &TilePainter::indexPressed, this, &ObjView::translateIndex);
 47	connect(m_ui.tiles, &TilePainter::needsRedraw, this, [this]() {
 48		updateTiles(true);
 49	});
 50	connect(m_ui.objId, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &ObjView::selectObj);
 51	connect(m_ui.magnification, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this]() {
 52		updateTiles(true);
 53	});
 54	connect(m_ui.exportButton, &QAbstractButton::clicked, this, &ObjView::exportObj);
 55}
 56
 57void ObjView::selectObj(int obj) {
 58	m_objId = obj;
 59	updateTiles(true);
 60}
 61
 62void ObjView::translateIndex(int index) {
 63	unsigned x = index % m_objInfo.width;
 64	unsigned y = index / m_objInfo.width;
 65	m_ui.tile->selectIndex(x + y * m_objInfo.stride + m_tileOffset + m_boundary);
 66}
 67
 68#ifdef M_CORE_GBA
 69void ObjView::updateTilesGBA(bool force) {
 70	m_ui.objId->setMaximum(127);
 71	const GBA* gba = static_cast<const GBA*>(m_controller->thread()->core->board);
 72	const GBAObj* obj = &gba->video.oam.obj[m_objId];
 73
 74	ObjInfo newInfo;
 75	lookupObj(m_objId, &newInfo);
 76
 77	m_ui.tiles->setTileCount(newInfo.width * newInfo.height);
 78	m_ui.tiles->setMinimumSize(QSize(newInfo.width * 8, newInfo.height * 8) * m_ui.magnification->value());
 79	m_ui.tiles->resize(QSize(newInfo.width * 8, newInfo.height * 8) * m_ui.magnification->value());
 80	unsigned tileBase = newInfo.tile;
 81	unsigned tile = newInfo.tile;
 82	if (GBAObjAttributesAIs256Color(obj->a)) {
 83		m_ui.palette->setText("256-color");
 84		m_ui.tile->setBoundary(1024, 1, 3);
 85		m_ui.tile->setPalette(0);
 86		m_boundary = 1024;
 87		tileBase *= 2;
 88	} else {
 89		m_ui.palette->setText(QString::number(newInfo.paletteId));
 90		m_ui.tile->setBoundary(2048, 0, 2);
 91		m_ui.tile->setPalette(newInfo.paletteId);
 92	}
 93	if (newInfo != m_objInfo) {
 94		force = true;
 95	}
 96	m_objInfo = newInfo;
 97	m_tileOffset = newInfo.tile;
 98	mTileCache* tileCache = mTileCacheSetGetPointer(&m_cacheSet->tiles, newInfo.paletteSet);
 99
100	int i = 0;
101	for (int y = 0; y < newInfo.height; ++y) {
102		for (int x = 0; x < newInfo.width; ++x, ++i, ++tile, ++tileBase) {
103			const color_t* data = mTileCacheGetTileIfDirty(tileCache, &m_tileStatus[16 * tileBase], tile, newInfo.paletteId);
104			if (data) {
105				m_ui.tiles->setTile(i, data);
106			} else if (force) {
107				m_ui.tiles->setTile(i, mTileCacheGetTile(tileCache, tile, newInfo.paletteId));
108			}
109		}
110		tile += newInfo.stride - newInfo.width;
111		tileBase += newInfo.stride - newInfo.width;
112	}
113
114	m_ui.x->setText(QString::number(newInfo.x));
115	m_ui.y->setText(QString::number(newInfo.y));
116	m_ui.w->setText(QString::number(newInfo.width * 8));
117	m_ui.h->setText(QString::number(newInfo.height * 8));
118
119	m_ui.address->setText(tr("0x%0").arg(BASE_OAM + m_objId * sizeof(*obj), 8, 16, QChar('0')));
120	m_ui.priority->setText(QString::number(newInfo.priority));
121	m_ui.flippedH->setChecked(newInfo.hflip);
122	m_ui.flippedV->setChecked(newInfo.vflip);
123	m_ui.enabled->setChecked(newInfo.enabled);
124	m_ui.doubleSize->setChecked(GBAObjAttributesAIsDoubleSize(obj->a) && GBAObjAttributesAIsTransformed(obj->a));
125	m_ui.mosaic->setChecked(GBAObjAttributesAIsMosaic(obj->a));
126
127	if (GBAObjAttributesAIsTransformed(obj->a)) {
128		m_ui.transform->setText(QString::number(GBAObjAttributesBGetMatIndex(obj->b)));
129	} else {
130		m_ui.transform->setText(tr("Off"));
131	}
132
133	switch (GBAObjAttributesAGetMode(obj->a)) {
134	case OBJ_MODE_NORMAL:
135		m_ui.mode->setText(tr("Normal"));
136		break;
137	case OBJ_MODE_SEMITRANSPARENT:
138		m_ui.mode->setText(tr("Trans"));
139		break;
140	case OBJ_MODE_OBJWIN:
141		m_ui.mode->setText(tr("OBJWIN"));
142		break;
143	default:
144		m_ui.mode->setText(tr("Invalid"));
145		break;
146	}
147}
148#endif
149
150#ifdef M_CORE_GB
151void ObjView::updateTilesGB(bool force) {
152	m_ui.objId->setMaximum(39);
153	const GB* gb = static_cast<const GB*>(m_controller->thread()->core->board);
154	const GBObj* obj = &gb->video.oam.obj[m_objId];
155
156	ObjInfo newInfo;
157	lookupObj(m_objId, &newInfo);
158
159	mTileCache* tileCache = mTileCacheSetGetPointer(&m_cacheSet->tiles, 0);
160	unsigned tile = newInfo.tile;
161	m_ui.tiles->setTileCount(newInfo.height);
162	m_ui.tile->setBoundary(1024, 0, 0);
163	m_ui.tiles->setMinimumSize(QSize(8, newInfo.height * 8) * m_ui.magnification->value());
164	m_ui.tiles->resize(QSize(8, newInfo.height * 8) * m_ui.magnification->value());
165	m_ui.palette->setText(QString::number(newInfo.paletteId - 8));
166
167	if (newInfo != m_objInfo) {
168		force = true;
169	}
170	m_objInfo = newInfo;
171	m_tileOffset = tile;
172	m_boundary = 1024;
173
174	int i = 0;
175	m_ui.tile->setPalette(newInfo.paletteId);
176	for (int y = 0; y < newInfo.height; ++y, ++i) {
177		unsigned t = tile + i;
178		const color_t* data = mTileCacheGetTileIfDirty(tileCache, &m_tileStatus[8 * t], t, newInfo.paletteId);
179		if (data) {
180			m_ui.tiles->setTile(i, data);
181		} else if (force) {
182			m_ui.tiles->setTile(i, mTileCacheGetTile(tileCache, t, newInfo.paletteId));
183		}
184	}
185
186	m_ui.x->setText(QString::number(newInfo.x));
187	m_ui.y->setText(QString::number(newInfo.y));
188	m_ui.w->setText(QString::number(8));
189	m_ui.h->setText(QString::number(newInfo.height * 8));
190
191	m_ui.address->setText(tr("0x%0").arg(GB_BASE_OAM + m_objId * sizeof(*obj), 4, 16, QChar('0')));
192	m_ui.priority->setText(QString::number(newInfo.priority));
193	m_ui.flippedH->setChecked(newInfo.hflip);
194	m_ui.flippedV->setChecked(newInfo.vflip);
195	m_ui.enabled->setChecked(newInfo.enabled);
196	m_ui.doubleSize->setChecked(false);
197	m_ui.mosaic->setChecked(false);
198	m_ui.transform->setText(tr("N/A"));
199	m_ui.mode->setText(tr("N/A"));
200}
201#endif
202
203void ObjView::exportObj() {
204	QString filename = GBAApp::app()->getSaveFileName(this, tr("Export sprite"),
205	                                                  tr("Portable Network Graphics (*.png)"));
206	CoreController::Interrupter interrupter(m_controller);
207	QImage obj = compositeObj(m_objInfo);
208	obj.save(filename, "PNG");
209}