ref: 7311fc9ef81bcab931b9ca768f018a627f281933
parent: 7d54145e56dcb39430362719a528aff6eebe2edc
author: ISSOtm <[email protected]>
date: Tue Mar 22 14:37:58 EDT 2022
Fix transparency handling Ensure that the color count is properly used, and that transparency is not counted as a color when packing palettes
--- a/include/gfx/proto_palette.hpp
+++ b/include/gfx/proto_palette.hpp
@@ -34,6 +34,7 @@
ComparisonResult compare(ProtoPalette const &other) const;
size_t size() const;
+ bool empty() const;
decltype(_colorIndices)::const_iterator begin() const;
decltype(_colorIndices)::const_iterator end() const;
--- a/src/gfx/convert.cpp
+++ b/src/gfx/convert.cpp
@@ -441,6 +441,8 @@
bool bank;
bool yFlip;
bool xFlip;
+
+ static constexpr decltype(protoPaletteID) transparent = SIZE_MAX;
};
static std::tuple<DefaultInitVec<size_t>, std::vector<Palette>>
@@ -459,6 +461,13 @@
}
std::vector<Palette> palettes(nbPalettes);
+ // If the image contains at least one transparent pixel, force transparency in the first slot of
+ // all palettes
+ if (options.hasTransparentPixels) {
+ for (Palette &pal : palettes) {
+ pal.colors[0] = Rgba::transparent;
+ }
+ }
// Generate the actual palettes from the mappings
for (size_t protoPalID = 0; protoPalID < mappings.size(); ++protoPalID) {
auto &pal = palettes[mappings[protoPalID]];
@@ -676,7 +685,9 @@
auto iter = attrmap.begin();
for (auto tile : png.visitAsTiles(options.columnMajor)) {
- Palette const &palette = palettes[mappings[iter->protoPaletteID]];
+ size_t protoPaletteID = iter->protoPaletteID;
+ // If the tile is fully transparent, default to palette 0
+ Palette const &palette = palettes[protoPaletteID != AttrmapEntry::transparent ? mappings[protoPaletteID] : 0];
for (uint32_t y = 0; y < 8; ++y) {
uint16_t bitplanes = TileData::rowBitplanes(tile, palette, y);
output.sputc(bitplanes & 0xFF);
@@ -843,7 +854,7 @@
options.verbosePrint(Options::VERB_CFG, "Using libpng %s\n", png_get_libpng_ver(nullptr));
options.verbosePrint(Options::VERB_LOG_ACT, "Reading tiles...\n");
- Png png(options.input);
+ Png png(options.input); // This also sets `hasTransparentPixels` as a side effect
ImagePalette const &colors = png.getColors();
// Now, we have all the image's colors in `colors`
@@ -851,13 +862,11 @@
if (options.verbosity >= Options::VERB_INTERM) {
fputs("Image colors: [ ", stderr);
- size_t i = 0;
for (auto const &slot : colors) {
if (!slot.has_value()) {
continue;
}
- fprintf(stderr, "#%08x%s", slot->toCSS(), i != colors.size() - 1 ? ", " : "");
- ++i;
+ fprintf(stderr, "#%08x, ", slot->toCSS());
}
fputs("]\n", stderr);
}
@@ -875,10 +884,19 @@
for (uint32_t y = 0; y < 8; ++y) {
for (uint32_t x = 0; x < 8; ++x) {
- tileColors.add(tile.pixel(x, y).cgbColor());
+ Rgba color = tile.pixel(x, y);
+ if (!color.isTransparent()) { // Do not count transparency in for packing
+ tileColors.add(color.cgbColor());
+ }
}
}
+ if (tileColors.empty()) {
+ // "Empty" proto-palettes screw with the packing process, so discard those
+ attrs.protoPaletteID = AttrmapEntry::transparent;
+ continue;
+ }
+
// Insert the proto-palette, making sure to avoid overlaps
for (size_t n = 0; n < protoPalettes.size(); ++n) {
switch (tileColors.compare(protoPalettes[n])) {
@@ -909,6 +927,9 @@
}
}
attrs.protoPaletteID = protoPalettes.size();
+ if (protoPalettes.size() == AttrmapEntry::transparent) {
+ abort(); // TODO: nice error message
+ }
protoPalettes.push_back(tileColors);
contained:;
}
@@ -915,6 +936,15 @@
options.verbosePrint(Options::VERB_INTERM, "Image contains %zu proto-palette%s\n",
protoPalettes.size(), protoPalettes.size() != 1 ? "s" : "");
+ if (options.verbosity >= Options::VERB_INTERM) {
+ for (auto const &protoPal : protoPalettes) {
+ fputs("[ ", stderr);
+ for (uint16_t color : protoPal) {
+ fprintf(stderr, "$%04x, ", color);
+ }
+ fputs("]\n", stderr);
+ }
+ }
// Sort the proto-palettes by size, which improves the packing algorithm's efficiency
// We sort after all insertions to avoid moving items: https://stackoverflow.com/a/2710332
--- a/src/gfx/pal_packing.cpp
+++ b/src/gfx/pal_packing.cpp
@@ -401,7 +401,7 @@
continue;
}
- options.verbosePrint(Options::VERB_DEBUG, "%zu/%zu: Rel size: %f (size = %zu)\n", i,
+ options.verbosePrint(Options::VERB_DEBUG, "%zu/%zu: Rel size: %f (size = %zu)\n", i + 1,
assignments.size(), assignments[i].relSizeOf(protoPal),
protoPal.size());
if (assignments[i].relSizeOf(protoPal) < bestRelSize) {
--- a/src/gfx/proto_palette.cpp
+++ b/src/gfx/proto_palette.cpp
@@ -66,6 +66,10 @@
return std::distance(begin(), end());
}
+bool ProtoPalette::empty() const {
+ return _colorIndices[0] == UINT16_MAX;
+}
+
auto ProtoPalette::begin() const -> decltype(_colorIndices)::const_iterator {
return _colorIndices.begin();
}