diff --git a/forms/projectsettingseditor.ui b/forms/projectsettingseditor.ui
index 9aa521a8..fc156a72 100644
--- a/forms/projectsettingseditor.ui
+++ b/forms/projectsettingseditor.ui
@@ -369,7 +369,7 @@
0
0
559
- 548
+ 560
@@ -602,7 +602,7 @@
-
-
+
The mask used to read/write metatile IDs in map data.
@@ -616,7 +616,7 @@
-
-
+
The mask used to read/write collision values in map data.
@@ -630,7 +630,7 @@
-
-
+
The mask used to read/write elevation values in map data.
@@ -742,7 +742,7 @@
0
0
559
- 568
+ 798
@@ -775,6 +775,86 @@
+ -
+
+
+ Transparent Pixel Rendering
+
+
+
-
+
+
+ Fully transparent pixels will be rendered as black pixels (the Pokémon games do this by default)
+
+
+ Render as black
+
+
+
+ -
+
+
+ Fully transparent pixels will be rendered using the first palette color (this the default behavior for the GBA)
+
+
+ Render using first palette color
+
+
+
+
+
+
+ -
+
+
+ Unused Layer Rendering
+
+
+
-
+
+
+ Normal
+
+
+
+ -
+
+
+ This raw tile value will be used to fill the unused bottom layer of Normal metatiles
+
+
+
+ -
+
+
+ Covered
+
+
+
+ -
+
+
+ This raw tile value will be used to fill the unused top layer of Covered metatiles
+
+
+
+ -
+
+
+ Split
+
+
+
+ -
+
+
+ This raw tile value will be used to fill the unused middle layer of Split metatiles
+
+
+
+
+
+
-
@@ -810,14 +890,14 @@
-
-
+
The mask used to read/write Layer Type from the metatile's attributes data. If 0, this attribute is disabled.
-
-
+
The mask used to read/write Metatile Behavior from the metatile's attributes data. If 0, this attribute is disabled.
@@ -864,7 +944,7 @@
-
-
+
The mask used to read/write Terrain Type from the metatile's attributes data. If 0, this attribute is disabled.
@@ -891,7 +971,7 @@
-
-
+
The mask used to read/write Encounter Type from the metatile's attributes data. If 0, this attribute is disabled.
@@ -1549,10 +1629,15 @@
- UIntHexSpinBox
- QWidget
+ UIntSpinBox
+ QAbstractSpinBox
+
+ UIntHexSpinBox
+ UIntSpinBox
+
+
diff --git a/include/config.h b/include/config.h
index 39ae4cdc..1a588c0a 100644
--- a/include/config.h
+++ b/include/config.h
@@ -301,6 +301,7 @@ public:
this->prefabImportPrompted = false;
this->tilesetsHaveCallback = true;
this->tilesetsHaveIsCompressed = true;
+ this->setTransparentPixelsBlack = true;
this->filePaths.clear();
this->eventIconPaths.clear();
this->pokemonIconPaths.clear();
@@ -310,6 +311,9 @@ public:
this->blockMetatileIdMask = 0x03FF;
this->blockCollisionMask = 0x0C00;
this->blockElevationMask = 0xF000;
+ this->unusedTileNormal = 0x3014;
+ this->unusedTileCovered = 0x0000;
+ this->unusedTileSplit = 0x0000;
this->identifiers.clear();
this->readKeys.clear();
}
@@ -362,6 +366,7 @@ public:
bool prefabImportPrompted;
bool tilesetsHaveCallback;
bool tilesetsHaveIsCompressed;
+ bool setTransparentPixelsBlack;
int metatileAttributesSize;
uint32_t metatileBehaviorMask;
uint32_t metatileTerrainTypeMask;
@@ -370,6 +375,9 @@ public:
uint16_t blockMetatileIdMask;
uint16_t blockCollisionMask;
uint16_t blockElevationMask;
+ uint16_t unusedTileNormal;
+ uint16_t unusedTileCovered;
+ uint16_t unusedTileSplit;
bool mapAllowFlagsEnabled;
QString collisionSheetPath;
int collisionSheetWidth;
diff --git a/include/core/tile.h b/include/core/tile.h
index 5d85066a..b58a187d 100644
--- a/include/core/tile.h
+++ b/include/core/tile.h
@@ -19,6 +19,8 @@ public:
uint16_t rawValue() const;
static int getIndexInTileset(int);
+
+ static const uint16_t maxValue;
};
inline bool operator==(const Tile &a, const Tile &b) {
diff --git a/include/ui/imageproviders.h b/include/ui/imageproviders.h
index fefa5546..806ffd5b 100644
--- a/include/ui/imageproviders.h
+++ b/include/ui/imageproviders.h
@@ -8,8 +8,8 @@
QImage getCollisionMetatileImage(Block);
QImage getCollisionMetatileImage(int, int);
-QImage getMetatileImage(uint16_t, Tileset*, Tileset*, QList, QList, bool useTruePalettes = false);
-QImage getMetatileImage(Metatile*, Tileset*, Tileset*, QList, QList, bool useTruePalettes = false);
+QImage getMetatileImage(uint16_t, Tileset*, Tileset*, const QList&, const QList&, bool useTruePalettes = false);
+QImage getMetatileImage(Metatile*, Tileset*, Tileset*, const QList&, const QList&, bool useTruePalettes = false);
QImage getTileImage(uint16_t, Tileset*, Tileset*);
QImage getPalettedTileImage(uint16_t, Tileset*, Tileset*, int, bool useTruePalettes = false);
QImage getGreyscaleTileImage(uint16_t tile, Tileset *primaryTileset, Tileset *secondaryTileset);
diff --git a/src/config.cpp b/src/config.cpp
index da58ecde..f1a52ec0 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -720,6 +720,12 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
this->blockCollisionMask = getConfigUint32(key, value, 0, Block::maxValue);
} else if (key == "block_elevation_mask") {
this->blockElevationMask = getConfigUint32(key, value, 0, Block::maxValue);
+ } else if (key == "unused_tile_normal") {
+ this->unusedTileNormal = getConfigUint32(key, value, 0, Tile::maxValue);
+ } else if (key == "unused_tile_covered") {
+ this->unusedTileCovered = getConfigUint32(key, value, 0, Tile::maxValue);
+ } else if (key == "unused_tile_split") {
+ this->unusedTileSplit = getConfigUint32(key, value, 0, Tile::maxValue);
} else if (key == "enable_map_allow_flags") {
this->mapAllowFlagsEnabled = getConfigBool(key, value);
#ifdef CONFIG_BACKWARDS_COMPATABILITY
@@ -752,6 +758,8 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
this->tilesetsHaveCallback = getConfigBool(key, value);
} else if (key == "tilesets_have_is_compressed") {
this->tilesetsHaveIsCompressed = getConfigBool(key, value);
+ } else if (key == "set_transparent_pixels_black") {
+ this->setTransparentPixelsBlack = getConfigBool(key, value);
} else if (key == "event_icon_path_object") {
this->eventIconPaths[Event::Group::Object] = value;
} else if (key == "event_icon_path_warp") {
@@ -839,6 +847,7 @@ QMap ProjectConfig::getKeyValueMap() {
}
map.insert("tilesets_have_callback", QString::number(this->tilesetsHaveCallback));
map.insert("tilesets_have_is_compressed", QString::number(this->tilesetsHaveIsCompressed));
+ map.insert("set_transparent_pixels_black", QString::number(this->setTransparentPixelsBlack));
map.insert("metatile_attributes_size", QString::number(this->metatileAttributesSize));
map.insert("metatile_behavior_mask", "0x" + QString::number(this->metatileBehaviorMask, 16).toUpper());
map.insert("metatile_terrain_type_mask", "0x" + QString::number(this->metatileTerrainTypeMask, 16).toUpper());
@@ -847,6 +856,9 @@ QMap ProjectConfig::getKeyValueMap() {
map.insert("block_metatile_id_mask", "0x" + QString::number(this->blockMetatileIdMask, 16).toUpper());
map.insert("block_collision_mask", "0x" + QString::number(this->blockCollisionMask, 16).toUpper());
map.insert("block_elevation_mask", "0x" + QString::number(this->blockElevationMask, 16).toUpper());
+ map.insert("unused_tile_normal", "0x" + QString::number(this->unusedTileNormal, 16).toUpper());
+ map.insert("unused_tile_covered", "0x" + QString::number(this->unusedTileCovered, 16).toUpper());
+ map.insert("unused_tile_split", "0x" + QString::number(this->unusedTileSplit, 16).toUpper());
map.insert("enable_map_allow_flags", QString::number(this->mapAllowFlagsEnabled));
map.insert("event_icon_path_object", this->eventIconPaths[Event::Group::Object]);
map.insert("event_icon_path_warp", this->eventIconPaths[Event::Group::Warp]);
diff --git a/src/core/tile.cpp b/src/core/tile.cpp
index cc89c2a9..1aab7a9b 100644
--- a/src/core/tile.cpp
+++ b/src/core/tile.cpp
@@ -1,5 +1,17 @@
#include "tile.h"
#include "project.h"
+#include "bitpacker.h"
+
+// Upper limit for raw value (i.e., uint16_t max).
+const uint16_t Tile::maxValue = 0xFFFF;
+
+// At the moment these are fixed, and not exposed to the user.
+// We're only using them for convenience when converting between raw values.
+// The actual job of clamping Tile's members to correct values is handled by the widths in the bit field.
+const BitPacker bitsTileId = BitPacker(0x03FF);
+const BitPacker bitsXFlip = BitPacker(0x0400);
+const BitPacker bitsYFlip = BitPacker(0x0800);
+const BitPacker bitsPalette = BitPacker(0xF000);
Tile::Tile() :
tileId(0),
@@ -16,18 +28,17 @@
{ }
Tile::Tile(uint16_t raw) :
- tileId(raw & 0x3FF),
- xflip((raw >> 10) & 1),
- yflip((raw >> 11) & 1),
- palette((raw >> 12) & 0xF)
+ tileId(bitsTileId.unpack(raw)),
+ xflip(bitsXFlip.unpack(raw)),
+ yflip(bitsYFlip.unpack(raw)),
+ palette(bitsPalette.unpack(raw))
{ }
uint16_t Tile::rawValue() const {
- return static_cast(
- (this->tileId & 0x3FF)
- | ((this->xflip & 1) << 10)
- | ((this->yflip & 1) << 11)
- | ((this->palette & 0xF) << 12));
+ return bitsTileId.pack(this->tileId)
+ | bitsXFlip.pack(this->xflip)
+ | bitsYFlip.pack(this->yflip)
+ | bitsPalette.pack(this->palette);
}
int Tile::getIndexInTileset(int tileId) {
diff --git a/src/project.cpp b/src/project.cpp
index 43b62ecf..1791bcdf 100644
--- a/src/project.cpp
+++ b/src/project.cpp
@@ -2096,19 +2096,29 @@ bool Project::readFieldmapProperties() {
fileWatcher.addPath(root + "/" + filename);
const QMap defines = parser.readCDefinesByName(filename, names);
- auto loadDefine = [defines](const QString name, int * dest) {
+ auto loadDefine = [defines](const QString name, int * dest, int min, int max) {
auto it = defines.find(name);
if (it != defines.end()) {
*dest = it.value();
+ if (*dest < min) {
+ logWarn(QString("Value for tileset property '%1' (%2) is below the minimum (%3). Defaulting to minimum.").arg(name).arg(*dest).arg(min));
+ *dest = min;
+ } else if (*dest > max) {
+ logWarn(QString("Value for tileset property '%1' (%2) is above the maximum (%3). Defaulting to maximum.").arg(name).arg(*dest).arg(max));
+ *dest = max;
+ }
} else {
logWarn(QString("Value for tileset property '%1' not found. Using default (%2) instead.").arg(name).arg(*dest));
}
};
- loadDefine(numTilesPrimaryName, &Project::num_tiles_primary);
- loadDefine(numTilesTotalName, &Project::num_tiles_total);
- loadDefine(numMetatilesPrimaryName, &Project::num_metatiles_primary);
- loadDefine(numPalsPrimaryName, &Project::num_pals_primary);
- loadDefine(numPalsTotalName, &Project::num_pals_total);
+ loadDefine(numPalsTotalName, &Project::num_pals_total, 2, INT_MAX); // In reality the max would be 16, but as far as Porymap is concerned it doesn't matter.
+ loadDefine(numTilesTotalName, &Project::num_tiles_total, 2, 1024); // 1024 is fixed because we store tile IDs in a 10-bit field.
+ loadDefine(numPalsPrimaryName, &Project::num_pals_primary, 1, Project::num_pals_total - 1);
+ loadDefine(numTilesPrimaryName, &Project::num_tiles_primary, 1, Project::num_tiles_total - 1);
+
+ // This maximum is overly generous, because until we parse the appropriate masks from the project
+ // we don't actually know what the maximum number of metatiles is.
+ loadDefine(numMetatilesPrimaryName, &Project::num_metatiles_primary, 1, 0xFFFF - 1);
auto it = defines.find(maxMapSizeName);
if (it != defines.end()) {
@@ -3020,12 +3030,12 @@ void Project::applyParsedLimits() {
Block::setLayout();
Metatile::setLayout(this);
- Project::num_metatiles_primary = qMin(Project::num_metatiles_primary, Block::getMaxMetatileId() + 1);
+ Project::num_metatiles_primary = qMin(qMax(Project::num_metatiles_primary, 1), Block::getMaxMetatileId() + 1);
projectConfig.defaultMetatileId = qMin(projectConfig.defaultMetatileId, Block::getMaxMetatileId());
projectConfig.defaultElevation = qMin(projectConfig.defaultElevation, Block::getMaxElevation());
projectConfig.defaultCollision = qMin(projectConfig.defaultCollision, Block::getMaxCollision());
- projectConfig.collisionSheetHeight = qMin(projectConfig.collisionSheetHeight, Block::getMaxElevation() + 1);
- projectConfig.collisionSheetWidth = qMin(projectConfig.collisionSheetWidth, Block::getMaxCollision() + 1);
+ projectConfig.collisionSheetHeight = qMin(qMax(projectConfig.collisionSheetHeight, 1), Block::getMaxElevation() + 1);
+ projectConfig.collisionSheetWidth = qMin(qMax(projectConfig.collisionSheetWidth, 1), Block::getMaxCollision() + 1);
}
bool Project::hasUnsavedChanges() {
diff --git a/src/ui/imageproviders.cpp b/src/ui/imageproviders.cpp
index 86f0c07a..8fa72699 100644
--- a/src/ui/imageproviders.cpp
+++ b/src/ui/imageproviders.cpp
@@ -17,8 +17,8 @@ QImage getMetatileImage(
uint16_t metatileId,
Tileset *primaryTileset,
Tileset *secondaryTileset,
- QList layerOrder,
- QList layerOpacity,
+ const QList &layerOrder,
+ const QList &layerOpacity,
bool useTruePalettes)
{
Metatile* metatile = Tileset::getMetatile(metatileId, primaryTileset, secondaryTileset);
@@ -34,8 +34,8 @@ QImage getMetatileImage(
Metatile *metatile,
Tileset *primaryTileset,
Tileset *secondaryTileset,
- QList layerOrder,
- QList layerOpacity,
+ const QList &layerOrder,
+ const QList &layerOpacity,
bool useTruePalettes)
{
QImage metatile_image(16, 16, QImage::Format_RGBA8888);
@@ -43,10 +43,16 @@ QImage getMetatileImage(
metatile_image.fill(Qt::magenta);
return metatile_image;
}
- metatile_image.fill(Qt::black);
QList> palettes = Tileset::getBlockPalettes(primaryTileset, secondaryTileset, useTruePalettes);
+ // We need to fill the metatile image with something so that if any transparent
+ // tile pixels line up across layers we will still have something to render.
+ // The GBA renders transparent pixels using palette 0 color 0. We have this color,
+ // but all 3 games actually overwrite it with black when loading the tileset palettes,
+ // so we have a setting to choose between these two behaviors.
+ metatile_image.fill(projectConfig.setTransparentPixelsBlack ? QColor("black") : QColor(palettes.value(0).value(0)));
+
QPainter metatile_painter(&metatile_image);
const int numLayers = 3; // When rendering, metatiles always have 3 layers
uint32_t layerType = metatile->layerType();
@@ -54,7 +60,6 @@ QImage getMetatileImage(
for (int y = 0; y < 2; y++)
for (int x = 0; x < 2; x++) {
int l = layerOrder.size() >= numLayers ? layerOrder[layer] : layer;
- int bottomLayer = layerOrder.size() >= numLayers ? layerOrder[0] : 0;
// Get the tile to render next
Tile tile;
@@ -63,25 +68,25 @@ QImage getMetatileImage(
tile = metatile->tiles.value(tileOffset + (l * 4));
} else {
// "Vanilla" metatiles only have 8 tiles, but render 12.
- // The remaining 4 tiles are rendered either as tile 0 or 0x3014 (tile 20, palette 3) depending on layer type.
+ // The remaining 4 tiles are rendered using user-specified tiles depending on layer type.
switch (layerType)
{
default:
case METATILE_LAYER_MIDDLE_TOP:
if (l == 0)
- tile = Tile(0x3014);
+ tile = Tile(projectConfig.unusedTileNormal);
else // Tiles are on layers 1 and 2
tile = metatile->tiles.value(tileOffset + ((l - 1) * 4));
break;
case METATILE_LAYER_BOTTOM_MIDDLE:
if (l == 2)
- tile = Tile();
+ tile = Tile(projectConfig.unusedTileCovered);
else // Tiles are on layers 0 and 1
tile = metatile->tiles.value(tileOffset + (l * 4));
break;
case METATILE_LAYER_BOTTOM_TOP:
if (l == 1)
- tile = Tile();
+ tile = Tile(projectConfig.unusedTileSplit);
else // Tiles are on layers 0 and 2
tile = metatile->tiles.value(tileOffset + ((l == 0 ? 0 : 1) * 4));
break;
@@ -91,18 +96,14 @@ QImage getMetatileImage(
QImage tile_image = getTileImage(tile.tileId, primaryTileset, secondaryTileset);
if (tile_image.isNull()) {
// Some metatiles specify tiles that are outside the valid range.
- // These are treated as completely transparent, so they can be skipped without
- // being drawn unless they're on the bottom layer, in which case we need
- // a placeholder because garbage will be drawn otherwise.
- if (l == bottomLayer) {
- metatile_painter.fillRect(x * 8, y * 8, 8, 8, palettes.value(0).value(0));
- }
+ // The way the GBA will render these depends on what's in memory (which Porymap can't know)
+ // so we treat them as if they were transparent.
continue;
}
// Colorize the metatile tiles with its palette.
if (tile.palette < palettes.length()) {
- QList palette = palettes.value(tile.palette);
+ const QList palette = palettes.value(tile.palette);
for (int j = 0; j < palette.length(); j++) {
tile_image.setColor(j, palette.value(j));
}
@@ -121,12 +122,10 @@ QImage getMetatileImage(
}
}
- // The top layer of the metatile has its first color displayed at transparent.
- if (l != bottomLayer) {
- QColor color(tile_image.color(0));
- color.setAlpha(0);
- tile_image.setColor(0, color.rgba());
- }
+ // Color 0 is displayed as transparent.
+ QColor color(tile_image.color(0));
+ color.setAlpha(0);
+ tile_image.setColor(0, color.rgba());
metatile_painter.drawImage(origin, tile_image.mirrored(tile.xflip, tile.yflip));
}
@@ -144,7 +143,7 @@ QImage getTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondary
return tileset->tiles.value(index, QImage());
}
-QImage getColoredTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset, QList palette) {
+QImage getColoredTileImage(uint16_t tileId, Tileset *primaryTileset, Tileset *secondaryTileset, const QList &palette) {
QImage tileImage = getTileImage(tileId, primaryTileset, secondaryTileset);
if (tileImage.isNull()) {
tileImage = QImage(8, 8, QImage::Format_RGBA8888);
diff --git a/src/ui/projectsettingseditor.cpp b/src/ui/projectsettingseditor.cpp
index 2f5de651..1c68137c 100644
--- a/src/ui/projectsettingseditor.cpp
+++ b/src/ui/projectsettingseditor.cpp
@@ -82,6 +82,8 @@ void ProjectSettingsEditor::connectSignals() {
}
for (auto checkBox : ui->centralwidget->findChildren())
connect(checkBox, &QCheckBox::stateChanged, this, &ProjectSettingsEditor::markEdited);
+ for (auto radioButton : ui->centralwidget->findChildren())
+ connect(radioButton, &QRadioButton::toggled, this, &ProjectSettingsEditor::markEdited);
for (auto lineEdit : ui->centralwidget->findChildren())
connect(lineEdit, &QLineEdit::textEdited, this, &ProjectSettingsEditor::markEdited);
for (auto spinBox : ui->centralwidget->findChildren())
@@ -135,6 +137,9 @@ void ProjectSettingsEditor::initUi() {
ui->spinBox_MetatileIdMask->setMaximum(Block::maxValue);
ui->spinBox_CollisionMask->setMaximum(Block::maxValue);
ui->spinBox_ElevationMask->setMaximum(Block::maxValue);
+ ui->spinBox_UnusedTileNormal->setMaximum(Tile::maxValue);
+ ui->spinBox_UnusedTileCovered->setMaximum(Tile::maxValue);
+ ui->spinBox_UnusedTileSplit->setMaximum(Tile::maxValue);
// The values for some of the settings we provide in this window can be determined using constants in the user's projects.
// If the user has these constants we disable these settings in the UI -- they can modify them using their constants.
@@ -442,6 +447,12 @@ void ProjectSettingsEditor::refresh() {
ui->checkBox_OutputIsCompressed->setChecked(projectConfig.tilesetsHaveIsCompressed);
ui->checkBox_DisableWarning->setChecked(porymapConfig.warpBehaviorWarningDisabled);
+ // Radio buttons
+ if (projectConfig.setTransparentPixelsBlack)
+ ui->radioButton_RenderBlack->setChecked(true);
+ else
+ ui->radioButton_RenderFirstPalColor->setChecked(true);
+
// Set spin box values
ui->spinBox_Elevation->setValue(projectConfig.defaultElevation);
ui->spinBox_Collision->setValue(projectConfig.defaultCollision);
@@ -455,6 +466,9 @@ void ProjectSettingsEditor::refresh() {
ui->spinBox_MetatileIdMask->setValue(projectConfig.blockMetatileIdMask & ui->spinBox_MetatileIdMask->maximum());
ui->spinBox_CollisionMask->setValue(projectConfig.blockCollisionMask & ui->spinBox_CollisionMask->maximum());
ui->spinBox_ElevationMask->setValue(projectConfig.blockElevationMask & ui->spinBox_ElevationMask->maximum());
+ ui->spinBox_UnusedTileNormal->setValue(projectConfig.unusedTileNormal);
+ ui->spinBox_UnusedTileCovered->setValue(projectConfig.unusedTileCovered);
+ ui->spinBox_UnusedTileSplit->setValue(projectConfig.unusedTileSplit);
// Set (and sync) border metatile IDs
this->setBorderMetatileIds(false, projectConfig.newMapBorderMetatileIds);
@@ -511,6 +525,7 @@ void ProjectSettingsEditor::save() {
projectConfig.tilesetsHaveCallback = ui->checkBox_OutputCallback->isChecked();
projectConfig.tilesetsHaveIsCompressed = ui->checkBox_OutputIsCompressed->isChecked();
porymapConfig.warpBehaviorWarningDisabled = ui->checkBox_DisableWarning->isChecked();
+ projectConfig.setTransparentPixelsBlack = ui->radioButton_RenderBlack->isChecked();
// Save spin box settings
projectConfig.defaultElevation = ui->spinBox_Elevation->value();
@@ -525,6 +540,9 @@ void ProjectSettingsEditor::save() {
projectConfig.blockMetatileIdMask = ui->spinBox_MetatileIdMask->value();
projectConfig.blockCollisionMask = ui->spinBox_CollisionMask->value();
projectConfig.blockElevationMask = ui->spinBox_ElevationMask->value();
+ projectConfig.unusedTileNormal = ui->spinBox_UnusedTileNormal->value();
+ projectConfig.unusedTileCovered = ui->spinBox_UnusedTileCovered->value();
+ projectConfig.unusedTileSplit = ui->spinBox_UnusedTileSplit->value();
// Save line edit settings
projectConfig.prefabFilepath = ui->lineEdit_PrefabsPath->text();
diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp
index 49cfe147..b8da1912 100644
--- a/src/ui/tileseteditor.cpp
+++ b/src/ui/tileseteditor.cpp
@@ -99,7 +99,13 @@ void TilesetEditor::initUi() {
this->paletteId = ui->spinBox_paletteSelector->value();
this->ui->spinBox_paletteSelector->setMinimum(0);
this->ui->spinBox_paletteSelector->setMaximum(Project::getNumPalettesTotal() - 1);
- this->ui->actionShow_Tileset_Divider->setChecked(porymapConfig.showTilesetEditorDivider);
+
+ // TODO: The dividing line at the moment is only accurate if the number of primary metatiles is divisible by 8.
+ // If it's not, the secondary metatiles will wrap above the line. This has other problems (like skewing
+ // metatile groups the user may have designed) so this should be fixed by filling the primary metatiles
+ // image with invalid magenta metatiles until it's divisible by 8. Then the line can be re-enabled as-is.
+ this->ui->actionShow_Tileset_Divider->setChecked(/*porymapConfig.showTilesetEditorDivider*/false);
+ this->ui->actionShow_Tileset_Divider->setVisible(false);
this->setAttributesUi();
this->setMetatileLabelValidator();