shithub: rgbds

Download patch

ref: 3f5983358cc8f791d80912d928a4d65cb4c62212
parent: 7a7126f3b87d444039237d001fe8faa36d5f77e2
author: ISSOtm <[email protected]>
date: Sat May 21 11:34:44 EDT 2022

Add proper error message for bad manual palettes

--- a/include/gfx/main.hpp
+++ b/include/gfx/main.hpp
@@ -67,8 +67,21 @@
 
 extern Options options;
 
+/**
+ * Prints the error count, and exits with failure
+ */
+[[noreturn]] void giveUp();
+/**
+ * Prints a warning, and does not change the error count
+ */
 void warning(char const *fmt, ...);
+/**
+ * Prints an error, and increments the error count
+ */
 void error(char const *fmt, ...);
+/**
+ * Prints a fatal error, increments the error count, and gives up
+ */
 [[noreturn]] void fatal(char const *fmt, ...);
 
 struct Palette {
--- a/src/gfx/main.cpp
+++ b/src/gfx/main.cpp
@@ -37,6 +37,11 @@
 char const *externalPalSpec = nullptr;
 static uintmax_t nbErrors;
 
+[[noreturn]] void giveUp() {
+	fprintf(stderr, "Conversion aborted after %ju error%s\n", nbErrors, nbErrors == 1 ? "" : "s");
+	exit(1);
+}
+
 void warning(char const *fmt, ...) {
 	va_list ap;
 
@@ -72,8 +77,7 @@
 	if (nbErrors != std::numeric_limits<decltype(nbErrors)>::max())
 		nbErrors++;
 
-	fprintf(stderr, "Conversion aborted after %ju error%s\n", nbErrors, nbErrors == 1 ? "" : "s");
-	exit(1);
+	giveUp();
 }
 
 void Options::verbosePrint(uint8_t level, char const *fmt, ...) const {
@@ -718,9 +722,7 @@
 
 	// Do not do anything if option parsing went wrong
 	if (nbErrors) {
-		fprintf(stderr, "Conversion aborted after %ju error%s\n", nbErrors,
-		        nbErrors == 1 ? "" : "s");
-		return 1;
+		giveUp();
 	}
 
 	if (options.reverse()) {
@@ -730,9 +732,7 @@
 	}
 
 	if (nbErrors) {
-		fprintf(stderr, "Conversion aborted after %ju error%s\n", nbErrors,
-		        nbErrors == 1 ? "" : "s");
-		return 1;
+		giveUp();
 	}
 	return 0;
 }
--- a/src/gfx/process.cpp
+++ b/src/gfx/process.cpp
@@ -12,6 +12,7 @@
 #include <assert.h>
 #include <cinttypes>
 #include <climits>
+#include <cstdio>
 #include <errno.h>
 #include <fstream>
 #include <memory>
@@ -557,8 +558,6 @@
 		// Fill in the palette spec
 		options.palSpec.emplace_back(); // A single palette, with `#00000000`s (transparent)
 		assert(options.palSpec.size() == 1);
-		// TODO: abort if ignored colors are being used; do it now for a friendlier error
-		// message
 		if (embPalSize > options.maxOpaqueColors()) { // Ignore extraneous colors if they are unused
 			embPalSize = options.maxOpaqueColors();
 		}
@@ -571,13 +570,24 @@
 	// Convert the palette spec to actual palettes
 	std::vector<Palette> palettes(options.palSpec.size());
 	for (auto [spec, pal] : zip(options.palSpec, palettes)) {
-		for (size_t i = 0; i < options.nbColorsPerPal; ++i) {
+		for (size_t i = 0; i < options.nbColorsPerPal && spec[i].isOpaque(); ++i) {
 			pal[i] = spec[i].cgbColor();
 		}
 	}
 
+	auto listColors = [](auto const &list) {
+		static char buf[sizeof(", $XXXX, $XXXX, $XXXX, $XXXX")];
+		char *ptr = buf;
+		for (uint16_t cgbColor : list) {
+			sprintf(ptr, ", $%04x", cgbColor);
+			ptr += 7;
+		}
+		return &buf[2];
+	};
+
 	// Iterate through proto-palettes, and try mapping them to the specified palettes
 	DefaultInitVec<size_t> mappings(protoPalettes.size());
+	bool bad = false;
 	for (size_t i = 0; i < protoPalettes.size(); ++i) {
 		ProtoPalette const &protoPal = protoPalettes[i];
 		// Find the palette...
@@ -587,8 +597,21 @@
 				return std::find(pal.begin(), pal.end(), color) != pal.end();
 			});
 		});
-		assert(iter != palettes.end()); // TODO: produce a proper error message
-		mappings[i] = iter - palettes.begin();
+
+		if (iter == palettes.end()) {
+			assert(!protoPal.empty());
+			error("Could not fit tile colors [%s] in specified palettes", listColors(protoPal));
+			bad = true;
+		}
+		mappings[i] = iter - palettes.begin(); // Bogus value, but whatever
+	}
+	if (bad) {
+		fprintf(stderr, "note: The following palette%s specified:\n",
+		        palettes.size() == 1 ? " was" : "s were");
+		for (Palette const &pal : palettes) {
+			fprintf(stderr, "        [%s]\n", listColors(pal));
+		}
+		giveUp();
 	}
 
 	return {mappings, palettes};
--- /dev/null
+++ b/test/gfx/bad_manual_pals.err
@@ -1,0 +1,6 @@
+error: Could not fit tile colors [$6c8a, $7f55, $7fff] in specified palettes
+error: Could not fit tile colors [$6c8a, $7f55] in specified palettes
+note: The following palettes were specified:
+        [$7fff, $7f55]
+        [$7fff, $6c8a]
+Conversion aborted after 2 errors
--- /dev/null
+++ b/test/gfx/bad_manual_pals.flags
@@ -1,0 +1,1 @@
+-c #fff,#a9d4fe:#fff,#5721d9
binary files /dev/null b/test/gfx/bad_manual_pals.png differ