Add a way to name metatiles, for use in c code

Metatiles can be given a name. The name becomes a constant in
includes/contstants/metatile_labels.h.

The plan is to be able to reference metatiles in code using a macro
like `METATILE(Building, TV_ON, Primary)`, which will evaluate to the
value 0x003, or `METATILE(BrendansMaysHouse, MOVING_BOX_OPEN, Secondary)`,
which will evaluate to the value 0x270.
This commit is contained in:
Phlosioneer 2019-04-04 01:44:31 -04:00
parent e305e42e61
commit 01c6d09bc2
8 changed files with 148 additions and 6 deletions

View file

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>700</width>
<height>600</height>
<height>700</height>
</rect>
</property>
<property name="focusPolicy">
@ -198,6 +198,16 @@
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="4" column="0" colspan="3">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Metatile Label (Optional)</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="3">
<widget class="QLineEdit" name="lineEdit_metatileLabel"/>
</item>
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="label_5">
<property name="text">

View file

@ -3,6 +3,7 @@
#include "tile.h"
#include <QImage>
#include <QString>
class Metatile
{
@ -12,6 +13,7 @@ public:
QList<Tile> *tiles = nullptr;
uint8_t behavior;
uint8_t layerType;
QString label;
Metatile *copy();
void copyInPlace(Metatile*);

View file

@ -78,6 +78,7 @@ public:
void loadTilesetAssets(Tileset*);
void loadTilesetTiles(Tileset*, QImage);
void loadTilesetMetatiles(Tileset*);
void loadTilesetMetatileLabels(Tileset*);
void saveLayoutBlockdata(Map*);
void saveLayoutBorder(Map*);
@ -90,6 +91,7 @@ public:
void saveMapConstantsHeader();
void saveHealLocationStruct(Map*);
void saveTilesets(Tileset*, Tileset*);
void saveTilesetMetatileLabels(Tileset*, Tileset*);
void saveTilesetMetatileAttributes(Tileset*);
void saveTilesetMetatiles(Tileset*);
void saveTilesetTilesImage(Tileset*);

View file

@ -73,6 +73,8 @@ private slots:
void on_comboBox_metatileBehaviors_activated(const QString &arg1);
void on_lineEdit_metatileLabel_editingFinished();
void on_comboBox_layerType_activated(int arg1);
void on_actionExport_Primary_Tiles_Image_triggered();

View file

@ -12,6 +12,7 @@ Metatile* Metatile::copy() {
copy->behavior = this->behavior;
copy->layerType = this->layerType;
copy->tiles = new QList<Tile>;
copy->label = this->label;
for (Tile tile : *this->tiles) {
copy->tiles->append(tile);
}
@ -21,6 +22,7 @@ Metatile* Metatile::copy() {
void Metatile::copyInPlace(Metatile *other) {
this->behavior = other->behavior;
this->layerType = other->layerType;
this->label = other->label;
for (int i = 0; i < this->tiles->length(); i++) {
(*this->tiles)[i] = other->tiles->at(i);
}

View file

@ -348,8 +348,14 @@ void Editor::onHoveredMovementPermissionCleared() {
}
void Editor::onHoveredMetatileSelectionChanged(uint16_t metatileId) {
QString message = QString("Metatile: 0x%1")
.arg(QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper());
Metatile *metatile = Tileset::getMetatile(metatileId, map->layout->tileset_primary, map->layout->tileset_secondary);
QString message;
QString hexString = QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper();
if (metatile && metatile->label.size() != 0) {
message = QString("Metatile: 0x%1 \"%2\"").arg(hexString, metatile->label);
} else {
message = QString("Metatile: 0x%1").arg(hexString);
}
this->ui->statusBar->showMessage(message);
}

View file

@ -670,6 +670,7 @@ void Project::saveHealLocationStruct(Map *map) {
}
void Project::saveTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
saveTilesetMetatileLabels(primaryTileset, secondaryTileset);
saveTilesetMetatileAttributes(primaryTileset);
saveTilesetMetatileAttributes(secondaryTileset);
saveTilesetMetatiles(primaryTileset);
@ -680,6 +681,77 @@ void Project::saveTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
saveTilesetPalettes(secondaryTileset, false);
}
void Project::saveTilesetMetatileLabels(Tileset *primaryTileset, Tileset *secondaryTileset) {
QString filepath = root + "/include/constants/metatile_labels.h";
QString originalText = readTextFile(filepath);
QString primaryPrefix = QString("METATILE_%1_").arg(QString(primaryTileset->name).replace("gTileset_", ""));
QString secondaryPrefix = QString("METATILE_%1_").arg(QString(secondaryTileset->name).replace("gTileset_", ""));
QMap<QString, int> defines;
bool definesFileModified = false;
if (!originalText.isNull()) {
defines = readCDefines(originalText, (QStringList() << "METATILE_"));
// Purge old entries from the file.
QStringList definesToRemove;
for (QString defineName : defines.keys()) {
if (defineName.startsWith(primaryPrefix) || defineName.startsWith(secondaryPrefix)) {
definesToRemove << defineName;
}
}
for (QString defineName : definesToRemove) {
defines.remove(defineName);
definesFileModified = true;
}
}
// Add the new labels.
for (int i = 0; i < primaryTileset->metatiles->size(); i++) {
Metatile *metatile = primaryTileset->metatiles->at(i);
if (metatile->label.size() != 0) {
QString defineName = QString("%1%2").arg(primaryPrefix, metatile->label);
defines.insert(defineName, i);
definesFileModified = true;
}
}
for (int i = 0; i < secondaryTileset->metatiles->size(); i++) {
Metatile *metatile = secondaryTileset->metatiles->at(i);
if (metatile->label.size() != 0) {
QString defineName = QString("%1%2").arg(secondaryPrefix, metatile->label);
defines.insert(defineName, i);
definesFileModified = true;
}
}
if (!definesFileModified) {
return;
}
// Setup pretty formatting.
int longestDefineNameLength = 0;
for (QString defineName : defines.keys()) {
if (defineName.size() > longestDefineNameLength) {
longestDefineNameLength = defineName.size();
}
}
// Write the file.
QString outputText = "#ifndef GUARD_METATILE_LABELS_H\n";
outputText += "#define GUARD_METATILE_LABELS_H\n\n";
for (QString defineName : defines.keys()) {
int value = defines[defineName];
QString line = QString("#define %1 0x%2\n")
.arg(defineName, -1 * longestDefineNameLength)
.arg(QString("%1").arg(value, 3, 16, QChar('0')).toUpper());
outputText += line;
}
outputText += "\n#endif // GUARD_METATILE_LABELS_H\n";
saveTextFile(filepath, outputText);
}
void Project::saveTilesetMetatileAttributes(Tileset *tileset) {
QFile attrs_file(tileset->metatile_attrs_path);
if (attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
@ -1098,6 +1170,7 @@ void Project::loadTilesetAssets(Tileset* tileset) {
QImage image = QImage(tileset->tilesImagePath);
this->loadTilesetTiles(tileset, image);
this->loadTilesetMetatiles(tileset);
this->loadTilesetMetatileLabels(tileset);
// palettes
QList<QList<QRgb>> *palettes = new QList<QList<QRgb>>;
@ -1200,6 +1273,29 @@ void Project::loadTilesetMetatiles(Tileset* tileset) {
}
}
void Project::loadTilesetMetatileLabels(Tileset* tileset) {
QString filepath = root + "/include/constants/metatile_labels.h";
QString text = readTextFile(filepath);
if (!text.isNull()) {
QString tilesetPrefix = QString("METATILE_%1_").arg(QString(tileset->name).replace("gTileset_", ""));
QMap<QString, int> labels = readCDefines(text, QStringList() << tilesetPrefix);
for (QString labelName : labels.keys()) {
int metatileId = labels[labelName];
Metatile *metatile = Tileset::getMetatile(metatileId, tileset, nullptr);
if (metatile) {
metatile->label = labelName.replace(tilesetPrefix, "");
} else {
QString hexString = QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper();
logError(QString("Metatile 0x%1 cannot be found in tileset '%2'").arg(hexString, tileset->name));
}
}
} else {
logError(QString("Failed to read C defines file: '%1'").arg(filepath));
}
}
Blockdata* Project::readBlockdata(QString path) {
Blockdata *blockdata = new Blockdata;
QFile file(path);

View file

@ -61,6 +61,11 @@ void TilesetEditor::init(Project *project, QString primaryTilesetLabel, QString
this->ui->spinBox_paletteSelector->setMinimum(0);
this->ui->spinBox_paletteSelector->setMaximum(Project::getNumPalettesTotal() - 1);
//only allow characters valid for a symbol
QRegExp expression("[-_.A-Za-z0-9]+$");
QRegExpValidator *validator = new QRegExpValidator(expression);
this->ui->lineEdit_metatileLabel->setValidator(validator);
this->initMetatileSelector();
this->initMetatileLayersItem();
this->initTileSelector();
@ -179,8 +184,14 @@ void TilesetEditor::initMetatileLayersItem() {
}
void TilesetEditor::onHoveredMetatileChanged(uint16_t metatileId) {
QString message = QString("Metatile: 0x%1")
.arg(QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper());
Metatile *metatile = Tileset::getMetatile(metatileId, this->primaryTileset, this->secondaryTileset);
QString message;
QString hexString = QString("%1").arg(metatileId, 3, 16, QChar('0')).toUpper();
if (metatile && metatile->label.size() != 0) {
message = QString("Metatile: 0x%1 \"%2\"").arg(hexString, metatile->label);
} else {
message = QString("Metatile: 0x%1").arg(hexString);
}
this->ui->statusbar->showMessage(message);
}
@ -193,6 +204,7 @@ void TilesetEditor::onSelectedMetatileChanged(uint16_t metatileId) {
this->metatileLayersItem->setMetatile(metatile);
this->metatileLayersItem->draw();
this->ui->comboBox_metatileBehaviors->setCurrentIndex(this->ui->comboBox_metatileBehaviors->findData(this->metatile->behavior));
this->ui->lineEdit_metatileLabel->setText(this->metatile->label);
this->ui->comboBox_layerType->setCurrentIndex(this->ui->comboBox_layerType->findData(this->metatile->layerType));
}
@ -305,6 +317,16 @@ void TilesetEditor::on_comboBox_metatileBehaviors_activated(const QString &metat
}
}
void TilesetEditor::on_lineEdit_metatileLabel_editingFinished()
{
if (this->metatile) {
Metatile *prevMetatile = this->metatile->copy();
this->metatile->label = this->ui->lineEdit_metatileLabel->text();
MetatileHistoryItem *commit = new MetatileHistoryItem(metatileSelector->getSelectedMetatile(), prevMetatile, this->metatile->copy());
metatileHistory.push(commit);
}
}
void TilesetEditor::on_comboBox_layerType_activated(int layerType)
{
if (this->metatile) {
@ -668,7 +690,7 @@ void TilesetEditor::importTilesetMetatiles(Tileset *tileset, bool primary)
msgBox.exec();
return;
}
\
// TODO: This is crude because it makes a history entry for every newly-imported metatile.
// Revisit this when tiles and num metatiles are added to tileset editory history.
int metatileIdBase = primary ? 0 : Project::getNumMetatilesPrimary();