all repos — mgba @ 038d21debd6885a7ae74fd2bf24869eafa50d6da

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