Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sort Pokemon and trainer sprite palettes, with Makefile-specified exceptions #1137

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

Rangi42
Copy link
Member

@Rangi42 Rangi42 commented Aug 28, 2024

This avoids the need to define their order via indexed PNG palettes

It also avoids the need to use tools/palfix.py on custom sprites

Fixes #1136

Be sure to squash-merge this when/if doing so

…eptions

This avoids the need to define their order via indexed PNG palettes

It also avoids the need to use tools/palfix.py on custom sprites

Fixes pret#1136
@Rangi42
Copy link
Member Author

Rangi42 commented Aug 28, 2024

The algorithm here is slightly different than what was described in the issue:

Both front.2bpp and back.2bpp are created using the same normal.gbcpal input. The normal.gbcpal is generated by combining front.gbcpal and back.gbcpal. This means that front and back can each use a subset of the overall palette (e.g. Jigglypuff's back doesn't use its eye-blue color).

tools/gbcpal.c checks the colors by sorting them, filtering out duplicates, also filtering our black and white, and then allowing zero, one, or two colors. This allows for any valid sprite, including "all black and white" (fills in the middle colors as white and black also) or "all color, no black or white" (if we checked for "first color is white" or "last color is black", this would fail).

@Rangi42 Rangi42 requested a review from vulcandth August 28, 2024 17:11
Copy link
Member

@mid-kid mid-kid left a comment

Choose a reason for hiding this comment

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

I love this! It is clean and simple, and will be relatively unintrusive to current workflows.

...I just have a few nitpicks.

tools/gbcpal.c Show resolved Hide resolved
tools/gbcpal.c Outdated Show resolved Hide resolved
}

double luminance(struct Color color) {
return 0.299 * color.r * color.r + 0.587 * color.g * color.g + 0.114 * color.b * color.b;
Copy link
Member

Choose a reason for hiding this comment

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

Please break up this line, and while I believe these numbers, do you have any source/explanation for them? I've never looked into this, and I would've just naïvely summed the colors.

Copy link
Member

Choose a reason for hiding this comment

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

This is the standard conversion from RGB to Y (luminance), used by jpeg encoding and probably lots of other things.
I use the exact same coefficients here, for example.

Copy link
Member Author

Choose a reason for hiding this comment

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

What breakup do you have in mind? It's the same function I've used in a few Python helper scripts:

def luminance(c):
	r, g, b = c
	return 0.299 * r**2 + 0.587 * g**2 + 0.114 * b**2

Copy link
Member

Choose a reason for hiding this comment

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

Oh, actually I didn't notice at first that you are squaring each color component. That is not the standard luminance conversion used by jpeg etc. But it's probably the standard somewhere! I've just never seen it before. I'd be curious to hear the benefits.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've used it for many years, quoting from some source that defined luminance as the sqrt of sum of squares (i.e. a Euclidean distance) but omitting the sqrt when it's unnecessary (e.g. for comparisons).

Google leads to https://stackoverflow.com/questions/596216/formula-to-determine-perceived-brightness-of-rgb-color leads to https://alienryderflex.com/hsp.html which looks familiar (and IMO based on the StackOverflow illustrations is the best choice of the given options).

tools/gbcpal.c Outdated Show resolved Hide resolved
tools/gbcpal.c Outdated Show resolved Hide resolved
Comment on lines +123 to +144
uint16_t first, second;
if (num_colors == 0) {
// colors are white and black
first = 0x7fff;
second = 0x0000;
} else if (num_colors == 1) {
// colors are both the same one
first = pack_color(colors[0]);
second = first;
} else if (num_colors == 2) {
// colors are light and dark
first = pack_color(colors[0]);
second = pack_color(colors[1]);
if (reverse) {
// darker color is first
uint16_t tmp = first;
first = second;
second = tmp;
}
} else {
error_exit("%s: more than 2 colors besides black and white (%zu)\n", out_filename, num_colors);
}
Copy link
Member

Choose a reason for hiding this comment

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

I think the algorithm of white + reversed?(colors) + black * (1 + (max_colors - num_colors)) would make this cleaner, something like

if (num_colors > (MAX_COLORS - 2)) error;

uint16_t colors[MAX_COLORS];
int c = 0;
colors[c++] = 0x7fff;  // First color is white
for (int i = 0; i < num_colors; i++) colors[c++] = pack_color(colors[reverse ? num_colors - 1 - i : i]);  // Add the maximum of 2 custom colors
while (c < MAX_COLORS / 2) colors[c++] = 0x7fff;  // If not enough colors are present, fill up to half with white
while (c < MAX_COLORS) colors[c++] = 0;  // Fill the remainder with black

// Alternatively: fill the remaining colors from a predefined grayscale array, to make battle anims nicer?
for (c < MAX_COLORS; c++) colors[c] = pack_color((struct Color){32/4*(3-c), 32/4*(3-c), 32/4*(3-c)});

This is less verbose and I like the option of expanding this for more colors/maybe gen3 in the future?

Copy link
Member Author

Choose a reason for hiding this comment

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

I find this a lot harder to understand and grasp "when my input was such-and-such, what order will my colors be in?" I think the current verbose code is useful for being able to point users to it and show just how this new approach works.

Extending it to support 4bpp is a cool idea, but that would involve more rewriting than just this section, and it's a short enough file that I don't think we need to future-proof it like that already. (YAGNI; a gbapal.c tool will be its own thing, not much harder to write than this was.)

Copy link
Member Author

Choose a reason for hiding this comment

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

fill the remaining colors from a predefined grayscale array

I did consider this, but it would be error-prone. Imagine a front sprite that uses one or two colors, and a back sprite using zero, just black+white. Each one gets gbapal.c run on it, so the back sprite now has two gray colors... and then generating normal.gbcpal fails because there are too many combined colors.

Makefile Outdated
@@ -315,7 +350,8 @@ gfx/mobile/stadium2_n64.2bpp: tools/gfx += --trim-whitespace
tools/gfx $(tools/gfx) --depth 1 -o $@ $@)

%.gbcpal: %.png
$(RGBGFX) --colors embedded -p $@ $<
$(RGBGFX) -p $@ $<
tools/gbcpal $(tools/gbcpal) $@
Copy link
Member

@mid-kid mid-kid Aug 28, 2024

Choose a reason for hiding this comment

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

Make this tools/gbcpal $(tools/gbcpal) $@ || { rm -f $@; false }, to remove the file and stop on error (or use a differently named temporary file/separate rule...).

Copy link
Member Author

Choose a reason for hiding this comment

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

Can you please explain further what this would be protecting against? Note that if tools/gbcpal has an error, it would exit before the opening the file for writing with write_u8 at the very end.

Makefile Show resolved Hide resolved
@Rangi42 Rangi42 requested a review from mid-kid August 31, 2024 15:08
@Rangi42
Copy link
Member Author

Rangi42 commented Sep 7, 2024

@mid-kid Please leave an updated review/comments when you have time? (Also would welcome others' feedback on this.)

Copy link
Member

@dannye dannye left a comment

Choose a reason for hiding this comment

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

Seems like a good way to enforce that the front and back pics use essentially the same palette.

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

Successfully merging this pull request may close these issues.

Sort Pokemon and trainer sprite palettes from lightest to darkest, with Makefile-specified exceptions
3 participants