shithub: rgbds

Download patch

ref: 33a0857b8d2f382b21f4efad7bd25b400185019f
parent: 4e712807d7a2add9f93a265b25638e6f1ca32ff3
author: ISSOtm <[email protected]>
date: Tue Feb 7 19:20:55 EST 2023

Properly detect tiles with more than 4 colours

Fixes #1127, which was caused by a dumb logic error. Duh me.

--- a/include/gfx/proto_palette.hpp
+++ b/include/gfx/proto_palette.hpp
@@ -15,15 +15,20 @@
 #include <stdint.h>
 
 class ProtoPalette {
+public:
+	static constexpr size_t capacity = 4;
+
+private:
 	// Up to 4 colors, sorted, and where SIZE_MAX means the slot is empty
 	// (OK because it's not a valid color index)
 	// 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:
 	/*
-	 * Adds the specified color to the set
-	 * Returns false if the set is full
+	 * Adds the specified color to the set, or **silently drops it** if the set is full.
+	 *
+	 * Returns whether the color was unique.
 	 */
 	bool add(uint16_t color);
 
--- a/src/gfx/process.cpp
+++ b/src/gfx/process.cpp
@@ -986,12 +986,16 @@
 	for (auto tile : png.visitAsTiles()) {
 		ProtoPalette tileColors;
 		AttrmapEntry &attrs = attrmap.emplace_back();
+		uint8_t nbColorsInTile = 0;
 
 		for (uint32_t y = 0; y < 8; ++y) {
 			for (uint32_t x = 0; x < 8; ++x) {
 				Rgba color = tile.pixel(x, y);
 				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 @@
 			}
 		}
 
-		if (tileColors.size() > options.maxOpaqueColors()) {
+		if (nbColorsInTile > options.maxOpaqueColors()) {
 			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();
--- a/src/gfx/proto_palette.cpp
+++ b/src/gfx/proto_palette.cpp
@@ -17,24 +17,29 @@
 bool ProtoPalette::add(uint16_t color) {
 	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,
 	// and there are very few slots anyway)
 	while (_colorIndices[i] < color) {
 		++i;
-		if (i == _colorIndices.size())
-			return false;
+		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 ourselves, great!
-	if (_colorIndices[i] == color)
-		return true;
+	// If we found it, great! Nothing else to do.
+	if (_colorIndices[i] == color) {
+		return false;
+	}
 
 	// Swap entries until the end
 	while (_colorIndices[i] != UINT16_MAX) {
 		std::swap(_colorIndices[i], color);
 		++i;
-		if (i == _colorIndices.size())
-			return false; // Oh well
+		if (i == _colorIndices.size()) {
+			// The set is full, but doesn't include the new color.
+			return true;
+		}
 	}
 	// Write that last one into the new slot
 	_colorIndices[i] = color;