Add grids to tileset editor

This commit is contained in:
GriffinR 2023-12-19 21:21:16 -05:00
parent 93fb8cf471
commit a2d230666b
10 changed files with 196 additions and 68 deletions

View file

@ -14,6 +14,7 @@ The **"Breaking Changes"** listed below are changes that have been made in the d
- Add settings for custom images, including the collision graphics, default event icons, and pokémon icons. - Add settings for custom images, including the collision graphics, default event icons, and pokémon icons.
- Add settings to override any symbol or macro names Porymap expects to find. - Add settings to override any symbol or macro names Porymap expects to find.
- Add a zoom slider to the Collision tab. - Add a zoom slider to the Collision tab.
- Add toggleable grids to the Tileset Editor.
- Support for custom metatile ID, collision, and elevation data sizes. - Support for custom metatile ID, collision, and elevation data sizes.
- Support for 8bpp tileset tile images. - Support for 8bpp tileset tile images.

View file

@ -201,83 +201,41 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0"> <item row="1" column="1" colspan="3">
<widget class="QLabel" name="label_BottomTop">
<property name="text">
<string>Bottom/Top</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="3">
<widget class="NoScrollComboBox" name="comboBox_metatileBehaviors"/>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_encounterType">
<property name="text">
<string>Encounter Type</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_terrainType">
<property name="text">
<string>Terrain Type</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="NoScrollComboBox" name="comboBox_terrainType"/>
</item>
<item row="12" column="0" colspan="2">
<widget class="QLabel" name="label_metatileLabel">
<property name="text">
<string>Metatile Label (Optional)</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="NoScrollComboBox" name="comboBox_layerType"/> <widget class="NoScrollComboBox" name="comboBox_layerType"/>
</item> </item>
<item row="13" column="2"> <item row="7" column="0" colspan="4">
<widget class="QToolButton" name="copyButton_metatileLabel"> <widget class="NoScrollComboBox" name="comboBox_metatileBehaviors"/>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Copies the full metatile label to the clipboard.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources/images.qrc">
<normaloff>:/icons/clipboard.ico</normaloff>:/icons/clipboard.ico</iconset>
</property>
</widget>
</item> </item>
<item row="13" column="0" colspan="2"> <item row="13" column="0" colspan="3">
<widget class="QLineEdit" name="lineEdit_metatileLabel"> <widget class="QLineEdit" name="lineEdit_metatileLabel">
<property name="clearButtonEnabled"> <property name="clearButtonEnabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="12" column="0" colspan="3">
<widget class="QLabel" name="label_layerType"> <widget class="QLabel" name="label_metatileLabel">
<property name="text"> <property name="text">
<string>Layer Type</string> <string>Metatile Label (Optional)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0" colspan="2"> <item row="2" column="0" colspan="3">
<widget class="QLabel" name="label_metatileBehavior"> <widget class="QLabel" name="label_metatileBehavior">
<property name="text"> <property name="text">
<string>Metatile Behavior</string> <string>Metatile Behavior</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="0">
<widget class="NoScrollComboBox" name="comboBox_encounterType"/>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QGraphicsView" name="graphicsView_metatileLayers"> <widget class="QGraphicsView" name="graphicsView_metatileLayers">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>66</width> <width>66</width>
@ -298,6 +256,54 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0">
<widget class="QLabel" name="label_BottomTop">
<property name="text">
<string>Bottom/Top</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_encounterType">
<property name="text">
<string>Encounter Type</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_terrainType">
<property name="text">
<string>Terrain Type</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="NoScrollComboBox" name="comboBox_terrainType"/>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_layerType">
<property name="text">
<string>Layer Type</string>
</property>
</widget>
</item>
<item row="13" column="3">
<widget class="QToolButton" name="copyButton_metatileLabel">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Copies the full metatile label to the clipboard.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources/images.qrc">
<normaloff>:/icons/clipboard.ico</normaloff>:/icons/clipboard.ico</iconset>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="NoScrollComboBox" name="comboBox_encounterType"/>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -565,10 +571,6 @@
<addaction name="actionChange_Metatiles_Count"/> <addaction name="actionChange_Metatiles_Count"/>
<addaction name="actionChange_Palettes"/> <addaction name="actionChange_Palettes"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionShow_Unused"/>
<addaction name="actionShow_Counts"/>
<addaction name="actionShow_UnusedTiles"/>
<addaction name="separator"/>
<addaction name="actionExport_Primary_Tiles_Image"/> <addaction name="actionExport_Primary_Tiles_Image"/>
<addaction name="actionExport_Secondary_Tiles_Image"/> <addaction name="actionExport_Secondary_Tiles_Image"/>
<addaction name="actionExport_Primary_Metatiles_Image"/> <addaction name="actionExport_Primary_Metatiles_Image"/>
@ -584,8 +586,20 @@
<addaction name="actionUndo"/> <addaction name="actionUndo"/>
<addaction name="actionRedo"/> <addaction name="actionRedo"/>
</widget> </widget>
<widget class="QMenu" name="menuView">
<property name="title">
<string>View</string>
</property>
<addaction name="actionLayer_Grid"/>
<addaction name="actionMetatile_Grid"/>
<addaction name="separator"/>
<addaction name="actionShow_Counts"/>
<addaction name="actionShow_Unused"/>
<addaction name="actionShow_UnusedTiles"/>
</widget>
<addaction name="menuFile"/> <addaction name="menuFile"/>
<addaction name="menuEdit"/> <addaction name="menuEdit"/>
<addaction name="menuView"/>
<addaction name="menuTools"/> <addaction name="menuTools"/>
</widget> </widget>
<widget class="QStatusBar" name="statusbar"/> <widget class="QStatusBar" name="statusbar"/>
@ -711,6 +725,25 @@
<string>Ctrl+V</string> <string>Ctrl+V</string>
</property> </property>
</action> </action>
<action name="actionLayer_Grid">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Layer Grid</string>
</property>
</action>
<action name="actionMetatile_Grid">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Metatile Grid</string>
</property>
<property name="shortcut">
<string>Ctrl+G</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

View file

@ -62,6 +62,8 @@ public:
this->showCursorTile = true; this->showCursorTile = true;
this->showBorder = true; this->showBorder = true;
this->showGrid = false; this->showGrid = false;
this->showTilesetEditorMetatileGrid = false;
this->showTilesetEditorLayerGrid = true;
this->monitorFiles = true; this->monitorFiles = true;
this->tilesetCheckerboardFill = true; this->tilesetCheckerboardFill = true;
this->theme = "default"; this->theme = "default";
@ -88,6 +90,8 @@ public:
void setShowCursorTile(bool enabled); void setShowCursorTile(bool enabled);
void setShowBorder(bool enabled); void setShowBorder(bool enabled);
void setShowGrid(bool enabled); void setShowGrid(bool enabled);
void setShowTilesetEditorMetatileGrid(bool enabled);
void setShowTilesetEditorLayerGrid(bool enabled);
void setMonitorFiles(bool monitor); void setMonitorFiles(bool monitor);
void setTilesetCheckerboardFill(bool checkerboard); void setTilesetCheckerboardFill(bool checkerboard);
void setTheme(QString theme); void setTheme(QString theme);
@ -113,6 +117,8 @@ public:
bool getShowCursorTile(); bool getShowCursorTile();
bool getShowBorder(); bool getShowBorder();
bool getShowGrid(); bool getShowGrid();
bool getShowTilesetEditorMetatileGrid();
bool getShowTilesetEditorLayerGrid();
bool getMonitorFiles(); bool getMonitorFiles();
bool getTilesetCheckerboardFill(); bool getTilesetCheckerboardFill();
QString getTheme(); QString getTheme();
@ -156,6 +162,8 @@ private:
bool showCursorTile; bool showCursorTile;
bool showBorder; bool showBorder;
bool showGrid; bool showGrid;
bool showTilesetEditorMetatileGrid;
bool showTilesetEditorLayerGrid;
bool monitorFiles; bool monitorFiles;
bool tilesetCheckerboardFill; bool tilesetCheckerboardFill;
QString theme; QString theme;

View file

@ -19,6 +19,7 @@ public:
void setTilesets(Tileset*, Tileset*); void setTilesets(Tileset*, Tileset*);
void setMetatile(Metatile*); void setMetatile(Metatile*);
void clearLastModifiedCoords(); void clearLastModifiedCoords();
bool showGrid;
private: private:
Metatile* metatile; Metatile* metatile;
Tileset *primaryTileset; Tileset *primaryTileset;

View file

@ -84,6 +84,8 @@ private slots:
void on_actionShow_Unused_toggled(bool checked); void on_actionShow_Unused_toggled(bool checked);
void on_actionShow_Counts_toggled(bool checked); void on_actionShow_Counts_toggled(bool checked);
void on_actionShow_UnusedTiles_toggled(bool checked); void on_actionShow_UnusedTiles_toggled(bool checked);
void on_actionMetatile_Grid_triggered(bool checked);
void on_actionLayer_Grid_triggered(bool checked);
void on_actionUndo_triggered(); void on_actionUndo_triggered();

View file

@ -22,6 +22,7 @@ public:
QVector<uint16_t> usedMetatiles; QVector<uint16_t> usedMetatiles;
bool selectorShowUnused = false; bool selectorShowUnused = false;
bool selectorShowCounts = false; bool selectorShowCounts = false;
bool showGrid;
protected: protected:
void mousePressEvent(QGraphicsSceneMouseEvent*); void mousePressEvent(QGraphicsSceneMouseEvent*);
@ -35,10 +36,12 @@ private:
Tileset *secondaryTileset = nullptr; Tileset *secondaryTileset = nullptr;
uint16_t selectedMetatile; uint16_t selectedMetatile;
int numMetatilesWide; int numMetatilesWide;
int numMetatilesHigh;
uint16_t getMetatileId(int x, int y); uint16_t getMetatileId(int x, int y);
QPoint getMetatileIdCoords(uint16_t); QPoint getMetatileIdCoords(uint16_t);
bool shouldAcceptEvent(QGraphicsSceneMouseEvent*); bool shouldAcceptEvent(QGraphicsSceneMouseEvent*);
int numRows(int numMetatiles);
int numRows();
void drawFilters(); void drawFilters();
void drawUnused(); void drawUnused();
void drawCounts(); void drawCounts();

View file

@ -354,6 +354,10 @@ void PorymapConfig::parseConfigKeyValue(QString key, QString value) {
this->showBorder = getConfigBool(key, value); this->showBorder = getConfigBool(key, value);
} else if (key == "show_grid") { } else if (key == "show_grid") {
this->showGrid = getConfigBool(key, value); this->showGrid = getConfigBool(key, value);
} else if (key == "show_tileset_editor_metatile_grid") {
this->showTilesetEditorMetatileGrid = getConfigBool(key, value);
} else if (key == "show_tileset_editor_layer_grid") {
this->showTilesetEditorLayerGrid = getConfigBool(key, value);
} else if (key == "monitor_files") { } else if (key == "monitor_files") {
this->monitorFiles = getConfigBool(key, value); this->monitorFiles = getConfigBool(key, value);
} else if (key == "tileset_checkerboard_fill") { } else if (key == "tileset_checkerboard_fill") {
@ -405,6 +409,8 @@ QMap<QString, QString> PorymapConfig::getKeyValueMap() {
map.insert("show_cursor_tile", this->showCursorTile ? "1" : "0"); map.insert("show_cursor_tile", this->showCursorTile ? "1" : "0");
map.insert("show_border", this->showBorder ? "1" : "0"); map.insert("show_border", this->showBorder ? "1" : "0");
map.insert("show_grid", this->showGrid ? "1" : "0"); map.insert("show_grid", this->showGrid ? "1" : "0");
map.insert("show_tileset_editor_metatile_grid", this->showTilesetEditorMetatileGrid ? "1" : "0");
map.insert("show_tileset_editor_layer_grid", this->showTilesetEditorLayerGrid ? "1" : "0");
map.insert("monitor_files", this->monitorFiles ? "1" : "0"); map.insert("monitor_files", this->monitorFiles ? "1" : "0");
map.insert("tileset_checkerboard_fill", this->tilesetCheckerboardFill ? "1" : "0"); map.insert("tileset_checkerboard_fill", this->tilesetCheckerboardFill ? "1" : "0");
map.insert("theme", this->theme); map.insert("theme", this->theme);
@ -538,6 +544,16 @@ void PorymapConfig::setShowGrid(bool enabled) {
this->save(); this->save();
} }
void PorymapConfig::setShowTilesetEditorMetatileGrid(bool enabled) {
this->showTilesetEditorMetatileGrid = enabled;
this->save();
}
void PorymapConfig::setShowTilesetEditorLayerGrid(bool enabled) {
this->showTilesetEditorLayerGrid = enabled;
this->save();
}
void PorymapConfig::setTheme(QString theme) { void PorymapConfig::setTheme(QString theme) {
this->theme = theme; this->theme = theme;
} }
@ -662,6 +678,14 @@ bool PorymapConfig::getShowGrid() {
return this->showGrid; return this->showGrid;
} }
bool PorymapConfig::getShowTilesetEditorMetatileGrid() {
return this->showTilesetEditorMetatileGrid;
}
bool PorymapConfig::getShowTilesetEditorLayerGrid() {
return this->showTilesetEditorLayerGrid;
}
bool PorymapConfig::getMonitorFiles() { bool PorymapConfig::getMonitorFiles() {
return this->monitorFiles; return this->monitorFiles;
} }

View file

@ -4,7 +4,7 @@
#include <QPainter> #include <QPainter>
void MetatileLayersItem::draw() { void MetatileLayersItem::draw() {
const QList<QPoint> tileCoords = QList<QPoint>{ static const QList<QPoint> tileCoords = QList<QPoint>{
QPoint(0, 0), QPoint(0, 0),
QPoint(16, 0), QPoint(16, 0),
QPoint(0, 16), QPoint(0, 16),
@ -19,8 +19,11 @@ void MetatileLayersItem::draw() {
QPoint(80, 16), QPoint(80, 16),
}; };
QPixmap pixmap(projectConfig.getNumLayersInMetatile() * 32, 32); const int numLayers = projectConfig.getNumLayersInMetatile();
QPixmap pixmap(numLayers * 32, 32);
QPainter painter(&pixmap); QPainter painter(&pixmap);
// Draw tile images
int numTiles = projectConfig.getNumTilesInMetatile(); int numTiles = projectConfig.getNumTilesInMetatile();
for (int i = 0; i < numTiles; i++) { for (int i = 0; i < numTiles; i++) {
Tile tile = this->metatile->tiles.at(i); Tile tile = this->metatile->tiles.at(i);
@ -29,6 +32,14 @@ void MetatileLayersItem::draw() {
.scaled(16, 16); .scaled(16, 16);
painter.drawImage(tileCoords.at(i), tileImage); painter.drawImage(tileCoords.at(i), tileImage);
} }
if (this->showGrid) {
// Draw grid
painter.setPen(Qt::white);
for (int i = 1; i < numLayers; i++) {
int x = i * 32;
painter.drawLine(x, 0, x, 32);
}
}
this->setPixmap(pixmap); this->setPixmap(pixmap);
} }

View file

@ -186,6 +186,10 @@ void TilesetEditor::initMetatileSelector()
connect(this->metatileSelector, &TilesetEditorMetatileSelector::selectedMetatileChanged, connect(this->metatileSelector, &TilesetEditorMetatileSelector::selectedMetatileChanged,
this, &TilesetEditor::onSelectedMetatileChanged); this, &TilesetEditor::onSelectedMetatileChanged);
bool showGrid = porymapConfig.getShowTilesetEditorMetatileGrid();
this->ui->actionMetatile_Grid->setChecked(showGrid);
this->metatileSelector->showGrid = showGrid;
this->metatilesScene = new QGraphicsScene; this->metatilesScene = new QGraphicsScene;
this->metatilesScene->addItem(this->metatileSelector); this->metatilesScene->addItem(this->metatileSelector);
this->metatileSelector->draw(); this->metatileSelector->draw();
@ -202,6 +206,10 @@ void TilesetEditor::initMetatileLayersItem() {
connect(this->metatileLayersItem, &MetatileLayersItem::selectedTilesChanged, connect(this->metatileLayersItem, &MetatileLayersItem::selectedTilesChanged,
this, &TilesetEditor::onMetatileLayerSelectionChanged); this, &TilesetEditor::onMetatileLayerSelectionChanged);
bool showGrid = porymapConfig.getShowTilesetEditorLayerGrid();
this->ui->actionLayer_Grid->setChecked(showGrid);
this->metatileLayersItem->showGrid = showGrid;
this->metatileLayersScene = new QGraphicsScene; this->metatileLayersScene = new QGraphicsScene;
this->metatileLayersScene->addItem(this->metatileLayersItem); this->metatileLayersScene->addItem(this->metatileLayersItem);
this->ui->graphicsView_metatileLayers->setScene(this->metatileLayersScene); this->ui->graphicsView_metatileLayers->setScene(this->metatileLayersScene);
@ -1036,6 +1044,18 @@ void TilesetEditor::on_actionShow_UnusedTiles_toggled(bool checked) {
this->tileSelector->draw(); this->tileSelector->draw();
} }
void TilesetEditor::on_actionMetatile_Grid_triggered(bool checked) {
this->metatileSelector->showGrid = checked;
this->metatileSelector->draw();
porymapConfig.setShowTilesetEditorMetatileGrid(checked);
}
void TilesetEditor::on_actionLayer_Grid_triggered(bool checked) {
this->metatileLayersItem->showGrid = checked;
this->metatileLayersItem->draw();
porymapConfig.setShowTilesetEditorLayerGrid(checked);
}
void TilesetEditor::countMetatileUsage() { void TilesetEditor::countMetatileUsage() {
// do not double count // do not double count
metatileSelector->usedMetatiles.fill(0); metatileSelector->usedMetatiles.fill(0);

View file

@ -12,6 +12,19 @@ TilesetEditorMetatileSelector::TilesetEditorMetatileSelector(Tileset *primaryTil
this->usedMetatiles.resize(Project::getNumMetatilesTotal()); this->usedMetatiles.resize(Project::getNumMetatilesTotal());
} }
int TilesetEditorMetatileSelector::numRows(int numMetatiles) {
int numMetatilesHigh = numMetatiles / this->numMetatilesWide;
if (numMetatiles % this->numMetatilesWide != 0) {
// Round up height for incomplete last row
numMetatilesHigh++;
}
return numMetatilesHigh;
}
int TilesetEditorMetatileSelector::numRows() {
return this->numRows(this->primaryTileset->metatiles.length() + this->secondaryTileset->metatiles.length());
}
QImage TilesetEditorMetatileSelector::buildAllMetatilesImage() { QImage TilesetEditorMetatileSelector::buildAllMetatilesImage() {
return this->buildImage(0, this->primaryTileset->metatiles.length() + this->secondaryTileset->metatiles.length()); return this->buildImage(0, this->primaryTileset->metatiles.length() + this->secondaryTileset->metatiles.length());
} }
@ -25,11 +38,7 @@ QImage TilesetEditorMetatileSelector::buildSecondaryMetatilesImage() {
} }
QImage TilesetEditorMetatileSelector::buildImage(int metatileIdStart, int numMetatiles) { QImage TilesetEditorMetatileSelector::buildImage(int metatileIdStart, int numMetatiles) {
int numMetatilesHigh = numMetatiles / this->numMetatilesWide; int numMetatilesHigh = this->numRows(numMetatiles);
if (numMetatiles % this->numMetatilesWide != 0) {
// Round up height for incomplete last row
numMetatilesHigh++;
}
int numPrimary = this->primaryTileset->metatiles.length(); int numPrimary = this->primaryTileset->metatiles.length();
int maxPrimary = Project::getNumMetatilesPrimary(); int maxPrimary = Project::getNumMetatilesPrimary();
bool includesPrimary = metatileIdStart < maxPrimary; bool includesPrimary = metatileIdStart < maxPrimary;
@ -158,6 +167,22 @@ QPoint TilesetEditorMetatileSelector::getMetatileIdCoordsOnWidget(uint16_t metat
} }
void TilesetEditorMetatileSelector::drawFilters() { void TilesetEditorMetatileSelector::drawFilters() {
if (this->showGrid) {
QPixmap pixmap = this->pixmap();
QPainter painter(&pixmap);
const int numColumns = this->numMetatilesWide;
const int numRows = this->numRows();
for (int column = 1; column < numColumns; column++) {
int x = column * 32;
painter.drawLine(x, 0, x, numRows * 32);
}
for (int row = 1; row < numRows; row++) {
int y = row * 32;
painter.drawLine(0, y, numColumns * 32, y);
}
painter.end();
this->setPixmap(pixmap);
}
if (selectorShowUnused) { if (selectorShowUnused) {
drawUnused(); drawUnused();
} }