From c0ff3d92ad732d5de1a63bfb6627a37edb672889 Mon Sep 17 00:00:00 2001 From: Rangi Date: Mon, 13 Jul 2026 22:38:57 -0400 Subject: [PATCH] Fix reverse palette offsets when base palette ID wraps around to 0 --- src/gfx/reverse.cpp | 19 +++++++------------ test/gfx/reverse_base_wrap.2bpp | 1 + test/gfx/reverse_base_wrap.flags | 5 +++++ test/gfx/reverse_base_wrap.pal | Bin 0 -> 64 bytes test/gfx/reverse_base_wrap.palmap | 2 ++ test/gfx/reverse_base_wrap.tilemap | Bin 0 -> 8 bytes 6 files changed, 15 insertions(+), 12 deletions(-) create mode 100644 test/gfx/reverse_base_wrap.2bpp create mode 100644 test/gfx/reverse_base_wrap.flags create mode 100644 test/gfx/reverse_base_wrap.pal create mode 100644 test/gfx/reverse_base_wrap.palmap create mode 100644 test/gfx/reverse_base_wrap.tilemap diff --git a/src/gfx/reverse.cpp b/src/gfx/reverse.cpp index 897a4690..13ee60b5 100644 --- a/src/gfx/reverse.cpp +++ b/src/gfx/reverse.cpp @@ -293,19 +293,13 @@ void reverse() { // 1. Checking those during the main loop is harmful to optimization, and // 2. It clutters the code more, and it's not in great shape to begin with for (size_t index = 0; index < mapSize; ++index) { - uint8_t attr = (*attrmap)[index]; size_t tx = index % width, ty = index / width; + uint8_t attr = (*attrmap)[index]; + uint8_t palID = attr & 0b111; - if (uint8_t palID = attr & 0b111; palID < options.basePalID) { - error( - "Attribute map references palette #%" PRIu8 - " at (%zu, %zu), but the base palette ID is #%" PRIu8, - palID, - tx, - ty, - options.basePalID - ); - } else if (palID >= palettes.size() + options.basePalID) { + // The unsigned underflow for `palOfs` is intentional, since a nonzero + // base palette ID may overflow and continue with IDs from 0. + if (uint8_t palOfs = (palID - options.basePalID) & 0b111; palOfs >= palettes.size()) { error( "Attribute map references palette #%" PRIu8 " at (%zu, %zu), but there are only %zu palette%s", @@ -535,7 +529,8 @@ void reverse() { : index; // This should have been enforced by the earlier checking. assume(tileOfs < nbTiles + options.trim); - size_t palOfs = (palmap ? (*palmap)[index] : attribute & 0b111) - options.basePalID; + size_t palOfs = + ((palmap ? (*palmap)[index] : attribute & 0b111) - options.basePalID) & 0b111; assume(palOfs < palettes.size()); // Should be ensured on data read // We do not have data for tiles trimmed with `-x`, so assume they are "blank" diff --git a/test/gfx/reverse_base_wrap.2bpp b/test/gfx/reverse_base_wrap.2bpp new file mode 100644 index 00000000..cf3e1ff4 --- /dev/null +++ b/test/gfx/reverse_base_wrap.2bpp @@ -0,0 +1 @@ +ÃðÃðÃðÃðÃðÃðÃðÃð<<<<<<<<ðÃðÃðÃðÃðÃðÃðÃðÃ<<<<<<<<ÃÌÃÌÃÌÃÌÃÌÃÌÃÌÃÌ33333333ðÃðÃðÃðÃðÃðÃðÃðÃ<<<<<<<< \ No newline at end of file diff --git a/test/gfx/reverse_base_wrap.flags b/test/gfx/reverse_base_wrap.flags new file mode 100644 index 00000000..431b5aaf --- /dev/null +++ b/test/gfx/reverse_base_wrap.flags @@ -0,0 +1,5 @@ +-b 255 +-l 3 +-t reverse_base_wrap.tilemap +-q reverse_base_wrap.palmap +-p reverse_base_wrap.pal diff --git a/test/gfx/reverse_base_wrap.pal b/test/gfx/reverse_base_wrap.pal new file mode 100644 index 0000000000000000000000000000000000000000..17adc089d9ab0ecd73ab4573a865bfcff13b4eb9 GIT binary patch literal 64 zcmbo0rBN?z%)?Aq3%Kbeny~52A~?CC`cVhpI8k5 D$siUv literal 0 HcmV?d00001 diff --git a/test/gfx/reverse_base_wrap.palmap b/test/gfx/reverse_base_wrap.palmap new file mode 100644 index 00000000..acffa6ca --- /dev/null +++ b/test/gfx/reverse_base_wrap.palmap @@ -0,0 +1,2 @@ + +  \ No newline at end of file diff --git a/test/gfx/reverse_base_wrap.tilemap b/test/gfx/reverse_base_wrap.tilemap new file mode 100644 index 0000000000000000000000000000000000000000..4c8f6b7620089fdf6e73184bfa46d4b24c97d148 GIT binary patch literal 8 Pcmey*z{teR!pa5!2si;1 literal 0 HcmV?d00001