Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add setting for how to render fully transparent pixels #655

Merged
merged 2 commits into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 96 additions & 11 deletions forms/projectsettingseditor.ui
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@
<x>0</x>
<y>0</y>
<width>559</width>
<height>548</height>
<height>560</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_16">
Expand Down Expand Up @@ -602,7 +602,7 @@
</widget>
</item>
<item row="0" column="1">
<widget class="UIntHexSpinBox" name="spinBox_MetatileIdMask" native="true">
<widget class="UIntHexSpinBox" name="spinBox_MetatileIdMask">
<property name="toolTip">
<string>The mask used to read/write metatile IDs in map data.</string>
</property>
Expand All @@ -616,7 +616,7 @@
</widget>
</item>
<item row="1" column="1">
<widget class="UIntHexSpinBox" name="spinBox_CollisionMask" native="true">
<widget class="UIntHexSpinBox" name="spinBox_CollisionMask">
<property name="toolTip">
<string>The mask used to read/write collision values in map data.</string>
</property>
Expand All @@ -630,7 +630,7 @@
</widget>
</item>
<item row="2" column="1">
<widget class="UIntHexSpinBox" name="spinBox_ElevationMask" native="true">
<widget class="UIntHexSpinBox" name="spinBox_ElevationMask">
<property name="toolTip">
<string>The mask used to read/write elevation values in map data.</string>
</property>
Expand Down Expand Up @@ -742,7 +742,7 @@
<x>0</x>
<y>0</y>
<width>559</width>
<height>568</height>
<height>798</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_12">
Expand Down Expand Up @@ -775,6 +775,86 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_TransparentPixelRendering">
<property name="title">
<string>Transparent Pixel Rendering</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_22">
<item>
<widget class="QRadioButton" name="radioButton_RenderBlack">
<property name="toolTip">
<string>Fully transparent pixels will be rendered as black pixels (the Pokémon games do this by default)</string>
</property>
<property name="text">
<string>Render as black</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_RenderFirstPalColor">
<property name="toolTip">
<string>Fully transparent pixels will be rendered using the first palette color (this the default behavior for the GBA)</string>
</property>
<property name="text">
<string>Render using first palette color</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_UnusedLayerRendering">
<property name="title">
<string>Unused Layer Rendering</string>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_UnusedTileNorma">
<property name="text">
<string>Normal</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="UIntHexSpinBox" name="spinBox_UnusedTileNormal">
<property name="toolTip">
<string>This raw tile value will be used to fill the unused bottom layer of Normal metatiles</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_UnusedTileCovered">
<property name="text">
<string>Covered</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="UIntHexSpinBox" name="spinBox_UnusedTileCovered">
<property name="toolTip">
<string>This raw tile value will be used to fill the unused top layer of Covered metatiles</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_UnusedTileSplit">
<property name="text">
<string>Split</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="UIntHexSpinBox" name="spinBox_UnusedTileSplit">
<property name="toolTip">
<string>This raw tile value will be used to fill the unused middle layer of Split metatiles</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_WarningTilesetsTab">
<property name="styleSheet">
Expand Down Expand Up @@ -810,14 +890,14 @@
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="4" column="1">
<widget class="UIntHexSpinBox" name="spinBox_LayerTypeMask" native="true">
<widget class="UIntHexSpinBox" name="spinBox_LayerTypeMask">
<property name="toolTip">
<string>The mask used to read/write Layer Type from the metatile's attributes data. If 0, this attribute is disabled.</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="UIntHexSpinBox" name="spinBox_BehaviorMask" native="true">
<widget class="UIntHexSpinBox" name="spinBox_BehaviorMask">
<property name="toolTip">
<string>The mask used to read/write Metatile Behavior from the metatile's attributes data. If 0, this attribute is disabled.</string>
</property>
Expand Down Expand Up @@ -864,7 +944,7 @@
</widget>
</item>
<item row="7" column="1">
<widget class="UIntHexSpinBox" name="spinBox_TerrainTypeMask" native="true">
<widget class="UIntHexSpinBox" name="spinBox_TerrainTypeMask">
<property name="toolTip">
<string>The mask used to read/write Terrain Type from the metatile's attributes data. If 0, this attribute is disabled.</string>
</property>
Expand All @@ -891,7 +971,7 @@
</widget>
</item>
<item row="5" column="1">
<widget class="UIntHexSpinBox" name="spinBox_EncounterTypeMask" native="true">
<widget class="UIntHexSpinBox" name="spinBox_EncounterTypeMask">
<property name="toolTip">
<string>The mask used to read/write Encounter Type from the metatile's attributes data. If 0, this attribute is disabled.</string>
</property>
Expand Down Expand Up @@ -1549,10 +1629,15 @@
<header>noscrollspinbox.h</header>
</customwidget>
<customwidget>
<class>UIntHexSpinBox</class>
<extends>QWidget</extends>
<class>UIntSpinBox</class>
<extends>QAbstractSpinBox</extends>
<header>uintspinbox.h</header>
</customwidget>
<customwidget>
<class>UIntHexSpinBox</class>
<extends>UIntSpinBox</extends>
<header location="global">uintspinbox.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../resources/images.qrc"/>
Expand Down
8 changes: 8 additions & 0 deletions include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ class ProjectConfig: public KeyValueConfigBase
this->prefabImportPrompted = false;
this->tilesetsHaveCallback = true;
this->tilesetsHaveIsCompressed = true;
this->setTransparentPixelsBlack = true;
this->filePaths.clear();
this->eventIconPaths.clear();
this->pokemonIconPaths.clear();
Expand All @@ -310,6 +311,9 @@ class ProjectConfig: public KeyValueConfigBase
this->blockMetatileIdMask = 0x03FF;
this->blockCollisionMask = 0x0C00;
this->blockElevationMask = 0xF000;
this->unusedTileNormal = 0x3014;
this->unusedTileCovered = 0x0000;
this->unusedTileSplit = 0x0000;
this->identifiers.clear();
this->readKeys.clear();
}
Expand Down Expand Up @@ -362,6 +366,7 @@ class ProjectConfig: public KeyValueConfigBase
bool prefabImportPrompted;
bool tilesetsHaveCallback;
bool tilesetsHaveIsCompressed;
bool setTransparentPixelsBlack;
int metatileAttributesSize;
uint32_t metatileBehaviorMask;
uint32_t metatileTerrainTypeMask;
Expand All @@ -370,6 +375,9 @@ class ProjectConfig: public KeyValueConfigBase
uint16_t blockMetatileIdMask;
uint16_t blockCollisionMask;
uint16_t blockElevationMask;
uint16_t unusedTileNormal;
uint16_t unusedTileCovered;
uint16_t unusedTileSplit;
bool mapAllowFlagsEnabled;
QString collisionSheetPath;
int collisionSheetWidth;
Expand Down
2 changes: 2 additions & 0 deletions include/core/tile.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class Tile
uint16_t rawValue() const;

static int getIndexInTileset(int);

static const uint16_t maxValue;
};

inline bool operator==(const Tile &a, const Tile &b) {
Expand Down
4 changes: 2 additions & 2 deletions include/ui/imageproviders.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

QImage getCollisionMetatileImage(Block);
QImage getCollisionMetatileImage(int, int);
QImage getMetatileImage(uint16_t, Tileset*, Tileset*, QList<int>, QList<float>, bool useTruePalettes = false);
QImage getMetatileImage(Metatile*, Tileset*, Tileset*, QList<int>, QList<float>, bool useTruePalettes = false);
QImage getMetatileImage(uint16_t, Tileset*, Tileset*, const QList<int>&, const QList<float>&, bool useTruePalettes = false);
QImage getMetatileImage(Metatile*, Tileset*, Tileset*, const QList<int>&, const QList<float>&, 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);
Expand Down
12 changes: 12 additions & 0 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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") {
Expand Down Expand Up @@ -839,6 +847,7 @@ QMap<QString, QString> 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());
Expand All @@ -847,6 +856,9 @@ QMap<QString, QString> 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]);
Expand Down
29 changes: 20 additions & 9 deletions src/core/tile.cpp
Original file line number Diff line number Diff line change
@@ -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),
Expand All @@ -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<uint16_t>(
(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) {
Expand Down
28 changes: 19 additions & 9 deletions src/project.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2096,19 +2096,29 @@ bool Project::readFieldmapProperties() {
fileWatcher.addPath(root + "/" + filename);
const QMap<QString, int> 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()) {
Expand Down Expand Up @@ -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() {
Expand Down
Loading
Loading