shithub: rgbds

Download patch

ref: fcce42d3d2bbe6ad905557dec701094858a7c9dd
parent: ed104a9f703358c6192228103237c49a9dc830d2
author: ISSOtm <eldredhabert0@gmail.com>
date: Sun Apr 24 11:03:27 EDT 2022

Avoid sorting proto-palettes breaking mappings

The sorting was performed without updating the mappings, which broke the world.
We can instead sort the IDs as they are inserted into the packing queue,
which should also be faster than moving the actual proto-pal objects around.

--- a/src/gfx/main.cpp
+++ b/src/gfx/main.cpp
@@ -736,6 +736,9 @@
 	}
 }
 
+/**
+ * Returns the ID of the color in the palette, or `size()` if the color is not in
+ */
 uint8_t Palette::indexOf(uint16_t color) const {
 	return std::find(colors.begin(), colors.end(), color) - colors.begin();
 }
--- a/src/gfx/pal_packing.cpp
+++ b/src/gfx/pal_packing.cpp
@@ -8,9 +8,11 @@
 
 #include "gfx/pal_packing.hpp"
 
+#include <algorithm>
 #include <assert.h>
 #include <bitset>
 #include <cinttypes>
+#include <deque>
 #include <numeric>
 #include <optional>
 #include <queue>
@@ -19,6 +21,8 @@
 #include <unordered_set>
 #include <vector>
 
+#include "defaultinitalloc.hpp"
+
 #include "gfx/main.hpp"
 #include "gfx/proto_palette.hpp"
 
@@ -356,32 +360,16 @@
 	options.verbosePrint(Options::VERB_LOG_ACT,
 	                     "Paginating palettes using \"overload-and-remove\" strategy...\n");
 
-	struct Iota {
-		using value_type = size_t;
-		using difference_type = size_t;
-		using pointer = value_type const *;
-		using reference = value_type const &;
-		using iterator_category = std::input_iterator_tag;
-
-		// Use aggregate init etc.
-		value_type i;
-
-		bool operator!=(Iota const &other) { return i != other.i; }
-		reference operator*() const { return i; }
-		pointer operator->() const { return &i; }
-		Iota operator++() {
-			++i;
-			return *this;
-		}
-		Iota operator++(int) {
-			Iota copy = *this;
-			++i;
-			return copy;
-		}
-	};
-
+	// Sort the proto-palettes by size, which improves the packing algorithm's efficiency
+	DefaultInitVec<size_t> sortedProtoPalIDs(protoPalettes.size());
+	sortedProtoPalIDs.clear();
+	for (size_t i = 0; i < protoPalettes.size(); ++i) {
+		sortedProtoPalIDs.insert(
+		    std::lower_bound(sortedProtoPalIDs.begin(), sortedProtoPalIDs.end(), i), i);
+	}
 	// Begin with all proto-palettes queued up for insertion
-	std::queue<ProtoPalAttrs> queue(std::deque<ProtoPalAttrs>(Iota{0}, Iota{protoPalettes.size()}));
+	std::queue<ProtoPalAttrs> queue(
+	    std::deque<ProtoPalAttrs>(sortedProtoPalIDs.begin(), sortedProtoPalIDs.end()));
 	// Begin with no pages
 	std::vector<AssignedProtos> assignments{};
 
--- a/src/gfx/process.cpp
+++ b/src/gfx/process.cpp
@@ -574,6 +574,7 @@
 		for (uint32_t x = 0; x < 8; ++x) {
 			row <<= 1;
 			uint8_t index = palette.indexOf(tile.pixel(x, y).cgbColor());
+			assert(index < palette.size()); // The color should be in the palette
 			if (index & 1) {
 				row |= 1;
 			}
@@ -947,12 +948,6 @@
 			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
-	std::sort(
-	    protoPalettes.begin(), protoPalettes.end(),
-	    [](ProtoPalette const &lhs, ProtoPalette const &rhs) { return lhs.size() < rhs.size(); });
 
 	auto [mappings, palettes] = options.palSpecType == Options::NO_SPEC
 	                                ? generatePalettes(protoPalettes, png)