Skip to content

Fix rgbgfx -Z palette overgeneration on merged color sets#1912

Open
vulcandth wants to merge 3 commits intogbdev:masterfrom
vulcandth:color-sets
Open

Fix rgbgfx -Z palette overgeneration on merged color sets#1912
vulcandth wants to merge 3 commits intogbdev:masterfrom
vulcandth:color-sets

Conversation

@vulcandth
Copy link
Copy Markdown

Fix rgbgfx -Z palette overgeneration on merged color sets

Closes #1887.

Summary

This fixes the RGBGFX bug where automatic palette generation could produce more palettes under -Z than without it for the same image.

The issue-reproducer Gloom image now generates 3 palettes with and without -Z, matching the intended behavior.

Root Cause

The remaining bug was not in ColorSet::compare; that part of the color-sets branch was already correct.

The problem was in color-set generation after a strict superset was found.
When a tile introduced a color set that was a strict superset of an existing one, RGBGFX only overrode the first matching subset and then stopped. Any other existing strict subsets were left behind as redundant color sets.

That made the final set of color sets depend on tile traversal order. In the Gloom -Z case, those redundant subset classes survived long enough to force a fourth palette later in the packing step.

Changes

  • Collapse all existing strict-subset color sets when inserting a new strict superset.
  • Remap earlier attrmap entries to the surviving color-set ID as redundant subsets are removed.
  • Move the temporary tile/color-set debug logging behind VERB_DEBUG and off stdout, which also fixes the known write_stdout regression caused by the debug instrumentation.
  • Add a Gloom-based test/gfx regression fixture for the -Z reproduction.

Testing

  • Ran the direct reproduction with verbose output and confirmed that rgbgfx -P -Z on the Gloom fixture now builds 3 color sets and 3 palettes instead of 4 palettes.
  • Ran focused regression checks for the existing base_ids gfx case and the write_stdout path.
  • Ran the full test/gfx suite: All 235 tests passed!

@Rangi42 Rangi42 added bug Unexpected behavior / crashes; to be fixed ASAP! rgbgfx This affects RGBGFX refactoring This PR is intended to clean up code more than change functionality labels Apr 3, 2026
@Rangi42 Rangi42 added this to the 1.0.2 milestone Apr 3, 2026
@Rangi42 Rangi42 self-requested a review April 3, 2026 21:33
@Rangi42 Rangi42 self-assigned this Apr 3, 2026
Comment on lines +54 to +65
if (*self_item < *other_item) {
// *self_item is not in other, so self cannot be a strict subset of other
self_has_unique = true;
++self_item;
} else if (*self_item > *other_item) {
// *other_item is not in self, so self cannot be a strict superset of other
other_has_unique = true;
++other_item;
} else {
// *self_item == *other_item, so continue comparing
++self_item;
++other_item;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well use a spaceship at this point, since we use C++20, huh?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some older system doesn't support <=>: #1228 (comment)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This unfortunately doesn't record which old system that would be. And since two years have passed, we can give it a new try, I think. But I don't care much, anyway.

Copy link
Copy Markdown
Member

@ISSOtm ISSOtm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic added in that third commit looks correct, but I'm feeling wary of it.

Comment on lines +1054 to +1065
for (size_t i = 0; i + 1 < attrmap.size(); ++i) {
AttrmapEntry &entry = attrmap[i];
if (entry.colorSetID == AttrmapEntry::transparent
|| entry.colorSetID == AttrmapEntry::background) {
continue;
}
if (entry.colorSetID == m) {
entry.colorSetID = n;
} else if (entry.colorSetID > m) {
--entry.colorSetID;
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little wary of this attrmap rescanning, as I fear it could blow up in some cases. rsgbgfx handles this image correctly even without this logic, so I feel it's preferable to avoid it if possible.

for (size_t m = n + 1; m < colorSets.size();) {
if (colorSet.compare(colorSets[m]) != ColorSet::STRICT_SUPERSET) {
++m;
continue;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather make the rest of the loop a else, for clarity.

@Rangi42 Rangi42 removed their assignment Apr 3, 2026
Comment on lines +1046 to +1047
// Remove any other color sets that we are also a strict superset of
// (example: we have [(0, 1), (0, 2)] and are inserting (0, 1, 2))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic is deeply indented and fairly self-contained, so I'd extract it into a static helper function.

// Override the previous color set that this one is a strict superset of

if (checkVerbosity(VERB_DEBUG)) {
fprintf(stderr, "- tile (%" PRIu32 ", %" PRIu32 ") overrides color set #%zu: [", tile.x, tile.y, n);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're keeping these debug logs, may as well format them more like the rest.

Suggested change
fprintf(stderr, "- tile (%" PRIu32 ", %" PRIu32 ") overrides color set #%zu: [", tile.x, tile.y, n);
fprintf(stderr, "- Tile (%" PRIu32 ", %" PRIu32 ") overrides color set #%zu: [", tile.x, tile.y, n);

}

if (checkVerbosity(VERB_DEBUG)) {
fprintf(stderr, "- tile (%" PRIu32 ", %" PRIu32 ") adds color set #%zu: [", tile.x, tile.y, colorSets.size());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fprintf(stderr, "- tile (%" PRIu32 ", %" PRIu32 ") adds color set #%zu: [", tile.x, tile.y, colorSets.size());
fprintf(stderr, "- Tile (%" PRIu32 ", %" PRIu32 ") adds color set #%zu: [", tile.x, tile.y, colorSets.size());

@@ -0,0 +1 @@
-Z No newline at end of file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image
Suggested change
-Z
-Z

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The individual tiles of this could have their pixels scrambled without changing the colors of each tile or the overall size, so we don't have a poketcg image sitting in the repo.

@Rangi42
Copy link
Copy Markdown
Contributor

Rangi42 commented Apr 4, 2026

make format will run clang-format and fix the failing "Code format checking" CI step.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Unexpected behavior / crashes; to be fixed ASAP! refactoring This PR is intended to clean up code more than change functionality rgbgfx This affects RGBGFX

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RGBGFX produces different sized palettes with -Z flag

3 participants