From 428548b7e17e8ab967811052bc3dc4fe64719f92 Mon Sep 17 00:00:00 2001 From: Marcus Huderle Date: Tue, 2 Oct 2018 19:01:09 -0500 Subject: [PATCH] Add metatile attribute editing, and add tileset saving --- forms/tileseteditor.ui | 25 +++++++++++ include/core/metatile.h | 2 + include/core/tileset.h | 2 + include/project.h | 6 +++ include/ui/tileseteditor.h | 10 ++++- src/mainwindow.cpp | 1 + src/project.cpp | 83 ++++++++++++++++++++++++++++++----- src/ui/metatilelayersitem.cpp | 2 - src/ui/tileseteditor.cpp | 36 ++++++++++++++- 9 files changed, 150 insertions(+), 17 deletions(-) diff --git a/forms/tileseteditor.ui b/forms/tileseteditor.ui index 3d7d733a..57b66a1d 100644 --- a/forms/tileseteditor.ui +++ b/forms/tileseteditor.ui @@ -337,6 +337,16 @@ + + + + Layer Type + + + + + + @@ -354,8 +364,23 @@ 21 + + + File + + + + + + + Save Tileset + + + Ctrl+S + + diff --git a/include/core/metatile.h b/include/core/metatile.h index b5cb19d5..0a61f9fd 100644 --- a/include/core/metatile.h +++ b/include/core/metatile.h @@ -10,6 +10,8 @@ public: Metatile(); public: QList *tiles = nullptr; + uint8_t behavior; + uint8_t layerType; static int getBlockIndex(int); }; diff --git a/include/core/tileset.h b/include/core/tileset.h index 82113e4b..dea009eb 100644 --- a/include/core/tileset.h +++ b/include/core/tileset.h @@ -17,8 +17,10 @@ public: QString tiles_label; QString palettes_label; QString metatiles_label; + QString metatiles_path; QString callback_label; QString metatile_attrs_label; + QString metatile_attrs_path; QList *tiles = nullptr; QList *metatiles = nullptr; diff --git a/include/project.h b/include/project.h index 4efe58a6..856e3562 100644 --- a/include/project.h +++ b/include/project.h @@ -40,6 +40,8 @@ public: QStringList *secretBaseIds = nullptr; QStringList *bgEventFacingDirections = nullptr; QStringList mapsWithConnections; + QMap metatileBehaviorMap; + QMap metatileBehaviorMapInverse; QMap *map_cache; Map* loadMap(QString); @@ -83,6 +85,7 @@ public: void saveMapGroupsTable(); void saveMapConstantsHeader(); void saveHealLocationStruct(Map*); + void saveTilesets(Tileset*, Tileset*); QList* parseAsm(QString text); QStringList getSongNames(); @@ -100,6 +103,7 @@ public: void readCoordEventWeatherNames(); void readSecretBaseIds(); void readBgEventFacingDirections(); + void readMetatileBehaviors(); void loadEventPixmaps(QList objects); QMap getEventObjGfxConstants(); @@ -127,6 +131,8 @@ private: QString getMapLayoutFilepath(QString); void saveMapHeader(Map*); void saveMapConnections(Map*); + void saveTilesetMetatileAttributes(Tileset*); + void saveTilesetMetatiles(Tileset*); void updateMapsWithConnections(Map*); void saveMapsWithConnections(); void saveMapLayoutsTable(); diff --git a/include/ui/tileseteditor.h b/include/ui/tileseteditor.h index 084d3af1..9126985c 100644 --- a/include/ui/tileseteditor.h +++ b/include/ui/tileseteditor.h @@ -34,6 +34,12 @@ private slots: void on_checkBox_yFlip_stateChanged(int arg1); + void on_comboBox_metatileBehaviors_currentIndexChanged(const QString &arg1); + + void on_comboBox_layerType_currentIndexChanged(int index); + + void on_actionSave_Tileset_triggered(); + private: void initMetatileSelector(); void initTileSelector(); @@ -44,8 +50,8 @@ private: TilesetEditorMetatileSelector *metatileSelector = nullptr; TilesetEditorTileSelector *tileSelector = nullptr; MetatileLayersItem *metatileLayersItem = nullptr; - Project *project; - Metatile *metatile; + Project *project = nullptr; + Metatile *metatile = nullptr; int paletteId; bool tileXFlip; bool tileYFlip; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 9f77938d..bba152a7 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -406,6 +406,7 @@ void MainWindow::loadDataStructures() { project->readSecretBaseIds(); project->readBgEventFacingDirections(); project->readMapsWithConnections(); + project->readMetatileBehaviors(); project->readTilesetProperties(); } diff --git a/src/project.cpp b/src/project.cpp index 63899604..5fcd5b71 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -576,6 +576,49 @@ void Project::saveHealLocationStruct(Map *map) { saveTextFile(root + "/include/constants/heal_locations.h", constants_text); } +void Project::saveTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) { + saveTilesetMetatileAttributes(primaryTileset); + saveTilesetMetatileAttributes(secondaryTileset); + saveTilesetMetatiles(primaryTileset); + saveTilesetMetatiles(secondaryTileset); +} + +void Project::saveTilesetMetatileAttributes(Tileset *tileset) { + QFile attrs_file(tileset->metatile_attrs_path); + if (attrs_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + QByteArray data; + for (Metatile *metatile : *tileset->metatiles) { + data.append(static_cast(metatile->behavior)); + data.append(static_cast((metatile->layerType << 4) & 0xF0)); + } + attrs_file.write(data); + } else { + qDebug() << QString("Could not save tileset metatile attributes file '%1'").arg(tileset->metatile_attrs_path); + } +} + +void Project::saveTilesetMetatiles(Tileset *tileset) { + QFile metatiles_file(tileset->metatiles_path); + if (metatiles_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + QByteArray data; + for (Metatile *metatile : *tileset->metatiles) { + for (int i = 0; i < 8; i++) { + Tile tile = metatile->tiles->at(i); + uint16_t value = static_cast((tile.tile & 0x3ff) + | ((tile.xflip & 1) << 10) + | ((tile.yflip & 1) << 11) + | ((tile.palette & 0xf) << 12)); + data.append(static_cast(value & 0xff)); + data.append(static_cast((value >> 8) & 0xff)); + } + } + metatiles_file.write(data); + } else { + tileset->metatiles = new QList; + qDebug() << QString("Could not open tileset metatiles file '%1'").arg(tileset->metatiles_path); + } +} + void Project::loadMapTilesets(Map* map) { if (map->layout->has_unsaved_changes) { return; @@ -780,21 +823,19 @@ void Project::loadTilesetAssets(Tileset* tileset) { } } - QString metatiles_path; - QString metatile_attrs_path; QString metatiles_text = readTextFile(root + "/data/tilesets/metatiles.inc"); QList *metatiles_macros = parser->parseAsm(metatiles_text); QStringList *metatiles_values = getLabelValues(metatiles_macros, tileset->metatiles_label); if (!metatiles_values->isEmpty()) { - metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1); + tileset->metatiles_path = root + "/" + metatiles_values->value(0).section('"', 1, 1); } else { - metatiles_path = dir_path + "/metatiles.bin"; + tileset->metatiles_path = dir_path + "/metatiles.bin"; } QStringList *metatile_attrs_values = getLabelValues(metatiles_macros, tileset->metatile_attrs_label); if (!metatile_attrs_values->isEmpty()) { - metatile_attrs_path = root + "/" + metatile_attrs_values->value(0).section('"', 1, 1); + tileset->metatile_attrs_path = root + "/" + metatile_attrs_values->value(0).section('"', 1, 1); } else { - metatile_attrs_path = dir_path + "/metatile_attributes.bin"; + tileset->metatile_attrs_path = dir_path + "/metatile_attributes.bin"; } // tiles @@ -813,7 +854,7 @@ void Project::loadTilesetAssets(Tileset* tileset) { tileset->tiles = tiles; // metatiles - QFile metatiles_file(metatiles_path); + QFile metatiles_file(tileset->metatiles_path); if (metatiles_file.open(QIODevice::ReadOnly)) { QByteArray data = metatiles_file.readAll(); int num_metatiles = data.length() / 16; @@ -837,11 +878,10 @@ void Project::loadTilesetAssets(Tileset* tileset) { tileset->metatiles = metatiles; } else { tileset->metatiles = new QList; - qDebug() << QString("Could not open '%1'").arg(metatiles_path); + qDebug() << QString("Could not open tileset metatiles file '%1'").arg(tileset->metatiles_path); } - QFile attrs_file(metatile_attrs_path); - //qDebug() << metatile_attrs_path; + QFile attrs_file(tileset->metatile_attrs_path); if (attrs_file.open(QIODevice::ReadOnly)) { QByteArray data = attrs_file.readAll(); int num_metatiles = tileset->metatiles->count(); @@ -851,8 +891,13 @@ void Project::loadTilesetAssets(Tileset* tileset) { if (num_metatiles > num_metatileAttrs) num_metatiles = num_metatileAttrs; } + for (int i = 0; i < num_metatileAttrs; i++) { + int value = (static_cast(data.at(i * 2 + 1)) << 8) | static_cast(data.at(i * 2)); + tileset->metatiles->at(i)->behavior = value & 0xFF; + tileset->metatiles->at(i)->layerType = (value & 0xF000) >> 12; + } } else { - qDebug() << QString("Could not open '%1'").arg(metatile_attrs_path); + qDebug() << QString("Could not open tileset metatile attributes file '%1'").arg(tileset->metatile_attrs_path); } // palettes @@ -1249,6 +1294,22 @@ void Project::readBgEventFacingDirections() { readCDefinesSorted(filepath, prefixes, bgEventFacingDirections); } +void Project::readMetatileBehaviors() { + this->metatileBehaviorMap.clear(); + this->metatileBehaviorMapInverse.clear(); + QString filepath = root + "/include/constants/metatile_behaviors.h"; + QString text = readTextFile(filepath); + if (!text.isNull()) { + QStringList prefixes = (QStringList() << "MB_"); + this->metatileBehaviorMap = readCDefines(text, prefixes); + for (QString defineName : this->metatileBehaviorMap.keys()) { + this->metatileBehaviorMapInverse.insert(this->metatileBehaviorMap[defineName], defineName); + } + } else { + qDebug() << "Failed to read C defines file: " << filepath; + } +} + void Project::readCDefinesSorted(QString filepath, QStringList prefixes, QStringList* definesToSet) { QString text = readTextFile(filepath); if (!text.isNull()) { diff --git a/src/ui/metatilelayersitem.cpp b/src/ui/metatilelayersitem.cpp index 14e6d95c..50e6afaa 100644 --- a/src/ui/metatilelayersitem.cpp +++ b/src/ui/metatilelayersitem.cpp @@ -1,7 +1,6 @@ #include "metatilelayersitem.h" #include "imageproviders.h" #include -#include void MetatileLayersItem::draw() { const QList tileCoords = QList{ @@ -43,6 +42,5 @@ void MetatileLayersItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { int x = static_cast(pos.x()) / 16; int y = static_cast(pos.y()) / 16; int tileIndex = (x / 2 * 4) + (y * 2) + (x % 2); - qDebug() << tileIndex; emit this->tileChanged(tileIndex); } diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index 8fcf9117..06a889eb 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -16,8 +16,16 @@ TilesetEditor::TilesetEditor(Project *project, QString primaryTilesetLabel, QStr this->primaryTilesetLabel = primaryTilesetLabel; this->secondaryTilesetLabel = secondaryTilesetLabel; - ui->spinBox_paletteSelector->setMinimum(0); - ui->spinBox_paletteSelector->setMaximum(Project::getNumPalettesTotal() - 1); + QList sortedBehaviors; + for (int num : project->metatileBehaviorMapInverse.keys()) { + this->ui->comboBox_metatileBehaviors->addItem(project->metatileBehaviorMapInverse[num], num); + } + this->ui->comboBox_layerType->addItem("Normal - Middle/Top", 0); + this->ui->comboBox_layerType->addItem("Covered - Bottom/Middle", 1); + this->ui->comboBox_layerType->addItem("Split - Bottom/Top", 2); + this->ui->spinBox_paletteSelector->setMinimum(0); + this->ui->spinBox_paletteSelector->setMaximum(Project::getNumPalettesTotal() - 1); + this->initMetatileSelector(); this->initMetatileLayersItem(); this->initTileSelector(); @@ -120,6 +128,8 @@ void TilesetEditor::onSelectedMetatileChanged(uint16_t metatileId) { this->metatile = Tileset::getMetatile(metatileId, primaryTileset, secondaryTileset); this->metatileLayersItem->setMetatile(metatile); this->metatileLayersItem->draw(); + this->ui->comboBox_metatileBehaviors->setCurrentIndex(this->ui->comboBox_metatileBehaviors->findData(this->metatile->behavior)); + this->ui->comboBox_layerType->setCurrentIndex(this->ui->comboBox_layerType->findData(this->metatile->layerType)); } void TilesetEditor::onHoveredTileChanged(uint16_t tile) { @@ -165,3 +175,25 @@ void TilesetEditor::on_checkBox_yFlip_stateChanged(int checked) this->tileYFlip = checked; this->drawSelectedTile(); } + +void TilesetEditor::on_comboBox_metatileBehaviors_currentIndexChanged(const QString &metatileBehavior) +{ + if (this->metatile) { + this->metatile->behavior = static_cast(project->metatileBehaviorMap[metatileBehavior]); + } +} + + +void TilesetEditor::on_comboBox_layerType_currentIndexChanged(int layerType) +{ + if (this->metatile) { + this->metatile->layerType = static_cast(layerType); + } +} + +void TilesetEditor::on_actionSave_Tileset_triggered() +{ + Tileset *primaryTileset = this->project->getTileset(this->primaryTilesetLabel); + Tileset *secondaryTileset = this->project->getTileset(this->secondaryTilesetLabel); + this->project->saveTilesets(primaryTileset, secondaryTileset); +}