From 01c6d09bc2c77780f72102eb587aa5a5e931213b Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Thu, 4 Apr 2019 01:44:31 -0400 Subject: [PATCH 1/5] 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. --- forms/tileseteditor.ui | 12 ++++- include/core/metatile.h | 2 + include/project.h | 2 + include/ui/tileseteditor.h | 2 + src/core/metatile.cpp | 2 + src/editor.cpp | 10 +++- src/project.cpp | 96 ++++++++++++++++++++++++++++++++++++++ src/ui/tileseteditor.cpp | 28 +++++++++-- 8 files changed, 148 insertions(+), 6 deletions(-) diff --git a/forms/tileseteditor.ui b/forms/tileseteditor.ui index 626351cb..0e14cd2d 100644 --- a/forms/tileseteditor.ui +++ b/forms/tileseteditor.ui @@ -7,7 +7,7 @@ 0 0 700 - 600 + 700 @@ -198,6 +198,16 @@ false + + + + Metatile Label (Optional) + + + + + + diff --git a/include/core/metatile.h b/include/core/metatile.h index 955c4264..b1be4d75 100644 --- a/include/core/metatile.h +++ b/include/core/metatile.h @@ -3,6 +3,7 @@ #include "tile.h" #include +#include class Metatile { @@ -12,6 +13,7 @@ public: QList *tiles = nullptr; uint8_t behavior; uint8_t layerType; + QString label; Metatile *copy(); void copyInPlace(Metatile*); diff --git a/include/project.h b/include/project.h index c63ff766..37de2b8f 100644 --- a/include/project.h +++ b/include/project.h @@ -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*); diff --git a/include/ui/tileseteditor.h b/include/ui/tileseteditor.h index 6e3ed3df..663fcbdb 100644 --- a/include/ui/tileseteditor.h +++ b/include/ui/tileseteditor.h @@ -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(); diff --git a/src/core/metatile.cpp b/src/core/metatile.cpp index e239085d..c35a7fcf 100644 --- a/src/core/metatile.cpp +++ b/src/core/metatile.cpp @@ -12,6 +12,7 @@ Metatile* Metatile::copy() { copy->behavior = this->behavior; copy->layerType = this->layerType; copy->tiles = new QList; + 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); } diff --git a/src/editor.cpp b/src/editor.cpp index 5674721b..46090257 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -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); } diff --git a/src/project.cpp b/src/project.cpp index 60ff3273..2413dcbb 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -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 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> *palettes = new QList>; @@ -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 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); diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index 1df9f2b9..614ce38a 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -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(); From 6b661db95219f2aa5801cbc54a881d33d04b0ed3 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Sun, 7 Apr 2019 20:46:53 -0400 Subject: [PATCH 2/5] Fix incorrect regex validator This fixes the bug where an empty line wouldn't clear the metatile label. It also removes the '.' and '-' characters. --- src/ui/tileseteditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index 614ce38a..ca6f89ab 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -62,7 +62,7 @@ void TilesetEditor::init(Project *project, QString primaryTilesetLabel, QString this->ui->spinBox_paletteSelector->setMaximum(Project::getNumPalettesTotal() - 1); //only allow characters valid for a symbol - QRegExp expression("[-_.A-Za-z0-9]+$"); + QRegExp expression("[_A-Za-z0-9]*$"); QRegExpValidator *validator = new QRegExpValidator(expression); this->ui->lineEdit_metatileLabel->setValidator(validator); From 03186e4591e420a66b0dae6a7c3105447d0c6c20 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Mon, 8 Apr 2019 00:13:55 -0400 Subject: [PATCH 3/5] Fix metatile label bug while saving The metatile label only saved when the text field lost focus. But saving doesn't cause the lineEdit to lose focus. This forces a check whenever the tileset is saved. --- include/ui/tileseteditor.h | 1 + src/ui/tileseteditor.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/include/ui/tileseteditor.h b/include/ui/tileseteditor.h index 663fcbdb..1095b0be 100644 --- a/include/ui/tileseteditor.h +++ b/include/ui/tileseteditor.h @@ -95,6 +95,7 @@ private: void importTilesetTiles(Tileset*, bool); void importTilesetMetatiles(Tileset*, bool); void refresh(); + void saveMetatileLabel(); Ui::TilesetEditor *ui; History metatileHistory; TilesetEditorMetatileSelector *metatileSelector = nullptr; diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index ca6f89ab..49119430 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -318,6 +318,11 @@ void TilesetEditor::on_comboBox_metatileBehaviors_activated(const QString &metat } void TilesetEditor::on_lineEdit_metatileLabel_editingFinished() +{ + saveMetatileLabel(); +} + +void TilesetEditor::saveMetatileLabel() { if (this->metatile) { Metatile *prevMetatile = this->metatile->copy(); @@ -339,6 +344,12 @@ void TilesetEditor::on_comboBox_layerType_activated(int layerType) void TilesetEditor::on_actionSave_Tileset_triggered() { + if (this->metatile) { + if (this->metatile->label != this->ui->lineEdit_metatileLabel->text()) { + saveMetatileLabel(); + } + } + this->project->saveTilesets(this->primaryTileset, this->secondaryTileset); emit this->tilesetsSaved(this->primaryTileset->name, this->secondaryTileset->name); if (this->paletteEditor) { From edcb8f928530982f06698aa6121930411d4c7ea5 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Mon, 8 Apr 2019 00:17:30 -0400 Subject: [PATCH 4/5] Only commit metatile label if it changes --- src/ui/tileseteditor.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index 49119430..1db0ad5b 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -324,7 +324,8 @@ void TilesetEditor::on_lineEdit_metatileLabel_editingFinished() void TilesetEditor::saveMetatileLabel() { - if (this->metatile) { + // Only commit if the field has changed. + if (this->metatile && this->metatile->label != this->ui->lineEdit_metatileLabel->text()) { Metatile *prevMetatile = this->metatile->copy(); this->metatile->label = this->ui->lineEdit_metatileLabel->text(); MetatileHistoryItem *commit = new MetatileHistoryItem(metatileSelector->getSelectedMetatile(), prevMetatile, this->metatile->copy()); @@ -344,11 +345,7 @@ void TilesetEditor::on_comboBox_layerType_activated(int layerType) void TilesetEditor::on_actionSave_Tileset_triggered() { - if (this->metatile) { - if (this->metatile->label != this->ui->lineEdit_metatileLabel->text()) { - saveMetatileLabel(); - } - } + saveMetatileLabel(); this->project->saveTilesets(this->primaryTileset, this->secondaryTileset); emit this->tilesetsSaved(this->primaryTileset->name, this->secondaryTileset->name); From e7732bfb426c417478c36b2548215d7510b490a0 Mon Sep 17 00:00:00 2001 From: garak Date: Thu, 18 Jul 2019 16:35:00 -0400 Subject: [PATCH 5/5] fix secondary tileset metatile values; format save file --- src/project.cpp | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/project.cpp b/src/project.cpp index 2413dcbb..d89bff50 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -719,7 +719,7 @@ void Project::saveTilesetMetatileLabels(Tileset *primaryTileset, Tileset *second Metatile *metatile = secondaryTileset->metatiles->at(i); if (metatile->label.size() != 0) { QString defineName = QString("%1%2").arg(secondaryPrefix, metatile->label); - defines.insert(defineName, i); + defines.insert(defineName, i + Project::num_tiles_primary); definesFileModified = true; } } @@ -728,24 +728,37 @@ void Project::saveTilesetMetatileLabels(Tileset *primaryTileset, Tileset *second return; } - // Setup pretty formatting. - int longestDefineNameLength = 0; - for (QString defineName : defines.keys()) { - if (defineName.size() > longestDefineNameLength) { - longestDefineNameLength = defineName.size(); - } - } + auto getTilesetFromLabel = [](QString labelName) { + return QRegularExpression("METATILE_(?[A-Za-z0-9]+)_").match(labelName).captured("tileset"); + }; - // Write the file. QString outputText = "#ifndef GUARD_METATILE_LABELS_H\n"; - outputText += "#define GUARD_METATILE_LABELS_H\n\n"; + outputText += "#define GUARD_METATILE_LABELS_H\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; + for (int i = 0; i < defines.size();) { + QString defineName = defines.keys()[i]; + QString currentTileset = getTilesetFromLabel(defineName); + outputText += QString("\n// gTileset_%1\n").arg(currentTileset); + + int j = 0, longestLength = 0; + QMap definesOut; + + // Setup for pretty formatting. + while (i + j < defines.size() && getTilesetFromLabel(defines.keys()[i + j]) == currentTileset) { + defineName = defines.keys()[i + j]; + if (defineName.size() > longestLength) + longestLength = defineName.size(); + definesOut.insert(defineName, defines[defineName]); + j++; + } + for (QString defineName : definesOut.keys()) { + int value = defines[defineName]; + QString line = QString("#define %1 0x%2\n") + .arg(defineName, -1 * longestLength) + .arg(QString("%1").arg(value, 3, 16, QChar('0')).toUpper()); + outputText += line; + } + i += j; } outputText += "\n#endif // GUARD_METATILE_LABELS_H\n"; @@ -1283,7 +1296,8 @@ void Project::loadTilesetMetatileLabels(Tileset* tileset) { for (QString labelName : labels.keys()) { int metatileId = labels[labelName]; - Metatile *metatile = Tileset::getMetatile(metatileId, tileset, nullptr); + // subtract Project::num_tiles_primary from secondary metatiles + Metatile *metatile = Tileset::getMetatile(metatileId - (tileset->is_secondary == "TRUE" ? Project::num_tiles_primary : 0), tileset, nullptr); if (metatile) { metatile->label = labelName.replace(tilesetPrefix, ""); } else {