Properly detect tiles with more than 4 colours

Fixes #1127, which was caused by a dumb logic error. Duh me.
This commit is contained in:
ISSOtm
2023-02-08 00:20:55 +01:00
parent 4e712807d7
commit 33a0857b8d
3 changed files with 28 additions and 14 deletions

View File

@@ -15,15 +15,20 @@
#include <stdint.h> #include <stdint.h>
class ProtoPalette { class ProtoPalette {
public:
static constexpr size_t capacity = 4;
private:
// Up to 4 colors, sorted, and where SIZE_MAX means the slot is empty // Up to 4 colors, sorted, and where SIZE_MAX means the slot is empty
// (OK because it's not a valid color index) // (OK because it's not a valid color index)
// Sorting is done on the raw numerical values to lessen `compare`'s complexity // Sorting is done on the raw numerical values to lessen `compare`'s complexity
std::array<uint16_t, 4> _colorIndices{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX}; std::array<uint16_t, capacity> _colorIndices{UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX};
public: public:
/* /*
* Adds the specified color to the set * Adds the specified color to the set, or **silently drops it** if the set is full.
* Returns false if the set is full *
* Returns whether the color was unique.
*/ */
bool add(uint16_t color); bool add(uint16_t color);

View File

@@ -986,12 +986,16 @@ void process() {
for (auto tile : png.visitAsTiles()) { for (auto tile : png.visitAsTiles()) {
ProtoPalette tileColors; ProtoPalette tileColors;
AttrmapEntry &attrs = attrmap.emplace_back(); AttrmapEntry &attrs = attrmap.emplace_back();
uint8_t nbColorsInTile = 0;
for (uint32_t y = 0; y < 8; ++y) { for (uint32_t y = 0; y < 8; ++y) {
for (uint32_t x = 0; x < 8; ++x) { for (uint32_t x = 0; x < 8; ++x) {
Rgba color = tile.pixel(x, y); Rgba color = tile.pixel(x, y);
if (!color.isTransparent()) { // Do not count transparency in for packing if (!color.isTransparent()) { // Do not count transparency in for packing
tileColors.add(color.cgbColor()); // Add the color to the proto-pal (if not full), and count it if it was unique.
if (tileColors.add(color.cgbColor())) {
++nbColorsInTile;
}
} }
} }
} }
@@ -1033,9 +1037,9 @@ void process() {
} }
} }
if (tileColors.size() > options.maxOpaqueColors()) { if (nbColorsInTile > options.maxOpaqueColors()) {
fatal("Tile at (%" PRIu32 ", %" PRIu32 ") has %zu opaque colors, more than %" PRIu8 "!", fatal("Tile at (%" PRIu32 ", %" PRIu32 ") has %zu opaque colors, more than %" PRIu8 "!",
tile.x, tile.y, tileColors.size(), options.maxOpaqueColors()); tile.x, tile.y, nbColorsInTile, options.maxOpaqueColors());
} }
attrs.protoPaletteID = protoPalettes.size(); attrs.protoPaletteID = protoPalettes.size();

View File

@@ -17,24 +17,29 @@
bool ProtoPalette::add(uint16_t color) { bool ProtoPalette::add(uint16_t color) {
size_t i = 0; size_t i = 0;
// Seek the first slot greater than our color // Seek the first slot greater than the new color
// (A linear search is better because we don't store the array size, // (A linear search is better because we don't store the array size,
// and there are very few slots anyway) // and there are very few slots anyway)
while (_colorIndices[i] < color) { while (_colorIndices[i] < color) {
++i; ++i;
if (i == _colorIndices.size()) if (i == _colorIndices.size()) {
// We reached the end of the array without finding the color, so it's a new one.
return true;
}
}
// If we found it, great! Nothing else to do.
if (_colorIndices[i] == color) {
return false; return false;
} }
// If we found ourselves, great!
if (_colorIndices[i] == color)
return true;
// Swap entries until the end // Swap entries until the end
while (_colorIndices[i] != UINT16_MAX) { while (_colorIndices[i] != UINT16_MAX) {
std::swap(_colorIndices[i], color); std::swap(_colorIndices[i], color);
++i; ++i;
if (i == _colorIndices.size()) if (i == _colorIndices.size()) {
return false; // Oh well // The set is full, but doesn't include the new color.
return true;
}
} }
// Write that last one into the new slot // Write that last one into the new slot
_colorIndices[i] = color; _colorIndices[i] = color;