• 2D
  • constructing ImageTexture

Hi, I'm trying to do the following . Sorry for the long post! I want to be able to construct lots of NPCs with variations without having to draw every single frame, shade and animate them by hand.

Not sure if I'm taking the right approach here : Construct an ImageTexture or Texture based on low res (currently between 16 and 32 pixels) pngs (base color, 3 tone value map) and palette Resources . I load the images in variables, create a new Image and fill it with the data of the base Image, and then iterate over the base Image and value map Image. I then use get_pixel() to get the color data per pixel, check the alpha to only process the non-zero ones and then use get_pixel() to get the value and adjust the color based on the value map. Works fine, since I only check for the highlight color (white), or the shadow color (black).

There's a step between those and that's where the problem occurs : After checking the alpha of the base color I use match to see if it matches the color of the palette Resource I made. I have a default one and an alternative one for now. I color picked the colors of the sprite since one of the default ones was off I found :

# abstract resource
extends Resource

class_name PlayerColors

export(String) var scheme_name = "default"
export(Color) var hair_color = Color(70/255.0, 34/255.0, 74/255.0, 1.0)
export(Color) var skin_color = Color(202/255.0, 137/255.0, 101/255.0, 1.0)
export(Color) var mouth_color = Color(176/255.0, 48/255.0, 18/255.0, 1.0)
export(Color) var shirt_color = Color(51/255.0, 153/255.0, 113/255.0, 1.0)
export(Color) var pants_color = Color(80/255.0, 100/255.0, 201/255.0, 1.0)
export(Color) var sword_color = Color(88/255.0, 88/255.0, 103/255.0, 1.0)

I just named them based on the sprite for now. Turns out they never match. I print the values of the pixel data I got using get_pixel() and the one I get from colors_default which I created from the abstract resource above and then color picked off the base image in Godot. I print them to a txt file since 22x22 results in too much for the debugger to handle. They look identical to me: pants_color : 0.313726,0.392157,0.788235,1 <- picked off the png by loading the Resource in the Inspector base_px : 0.313726,0.392157,0.788235,1 <- from Image.get_pixel()

But according to Godot they don't match.

I have a working workaround: not use the color of the resource and just sample base colors. But I want to use the resources. I did find out using that workaround that Color(80/255.0, 100/255.0, 201/255.0, 1.0) and Color(80/255, 100/255, 201/255, 1) is not considere the same.

Is there a difference between how get_pixel() gets color data and how the color picked of the Inspector gets color data ? Is there a better workaround where I make them have the same format?

Post was stuck in moderation queue. I also edited it to add code formatting.

@ricod said: Hi, I'm trying to do the following . Sorry for the long post!

No problem.

Welcome to the forums @ricod!

I looked through the post and I think the issue is likely due to floating point precision issues. How are you checking to see if the colors are equal? If you are using ==, then the floating point percision could be causing a very small difference with the two colors, leading to it not evaluating correctly.

I'd recommend comparing the colors using code like this, if you are not already:

const EPSILON = 0.001

# somewhere else in the code:
if (color_one.r - color_two.r) <= EPSILON:
	if (color_one.g - color_two.g) <= EPSILON:
		if (color_one.b - color_two.b) <= EPSILON:
			print ("The colors are the same")

Or you can use the built-in is_equal_approx (documentation) function, which should give the same results, but because it is written in C++, it should be a little more performance friendly:

if (color_one.is_equal_approx(color_two):
	print ("The colors are the same")

Though I have personally never used the is_equal_approx function, because until looking it up today, I didn't know it existed! However, it seems like it is the function for the job.

That seems to be it! The is_equal_approx approach works like a charm. Thanks so much!

I should really look into GDNative, because image construction like this takes like half a minute for 2 frames on my machine, but don't think I'm there yet

To add a little bit

Or you can use the built-in is_equal_approx (documentation) function, which should give the same results @TwistedTwigleg , the EPSILON in is_equal_approx is 0.0001, and the judgment is more reasonable, this is the code

	static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) {
		// Check for exact equality first, required to handle "infinity" values.
		if (a == b) {
			return true;
		}
		// Then check for approximate equality.
		real_t tolerance = CMP_EPSILON * abs(a);
		if (tolerance < CMP_EPSILON) {
			tolerance = CMP_EPSILON;
		}
		return abs(a - b) < tolerance;
	}

@ricod said: That seems to be it! The is_equal_approx approach works like a charm. Thanks so much!

Awesome! Happy to help :smile:

@vmjcv said: To add a little bit

Or you can use the built-in is_equal_approx (documentation) function, which should give the same results @TwistedTwigleg , the EPSILON in is_equal_approx is 0.0001, and the judgment is more reasonable, this is the code

	static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) {
		// Check for exact equality first, required to handle "infinity" values.
		if (a == b) {
			return true;
		}
		// Then check for approximate equality.
		real_t tolerance = CMP_EPSILON * abs(a);
		if (tolerance < CMP_EPSILON) {
			tolerance = CMP_EPSILON;
		}
		return abs(a - b) < tolerance;
	}

Thanks @vmjcv! I knew the way I was writing it was not optimal, but I couldn't remember the better way right off. The code snippet you shared looks much nicer and likely performs better to boot!