Problem with my script (For loop corrupts colors?)

I’m not even sure how to word it. I feel like I’m fighting a hydra. Chop one head off, two more appear. I’ve been inching my way to making my new function work as intended after hours of changing and tweaking stuff.

Here’s my biggest problem child:

local function paletteLightCalc()
	local paletteLight = {}
	local copyColorAmount = MAC
	local secondRound = 0
	local black = Color{ r=0, g=0, b=0, a=255 }
	local white = Color{ r=255, g=255, b=255, a=255 }
	
	-- If it has a center, remove and mark it
	if copyColorAmount %2 == 1 then
		copyColorAmount = copyColorAmount -1
		hasCenter = true
	end
	
	-- Halve the number and prepare the second round
	copyColorAmount = copyColorAmount/2
	secondRound = copyColorAmount
	
	-- Let's get the actual table now
	-- Starting with black to normal
	for i = 1, copyColorAmount do
		local tempColor = CM
		print(tempColor.lightness)
		tempColor.lightness = inQuad(tempColor.lightness, black.lightness, black.lightness-tempColor.lightness, CT[i])
		print(tempColor.lightness)
		table.insert(paletteLight, Color(tempColor))
	end
	-- If it has a center, just add the main color in the middle
	if hasCenter == true then
		table.insert(paletteLight, CM)
		secondRound = secondRound + 1
	end
	-- Lastly, normal to white
	for y = 1, copyColorAmount do
		local tempColor = CM
		tempColor.lightness = inQuad(tempColor.lightness, white.lightness, white.lightness - tempColor.lightness, CT[y+secondRound])
		table.insert(paletteLight, tempColor)
	end
	-- -- DEBUG
	-- for k,v in pairs(paletteLight) do
	-- print(v)  
	-- end
	-- -- DEBUG END
	return paletteLight
end

Full script here:

The for loop doesn’t reset the tempColor.
In the first line of my first for loop, I’m setting the tempColor to CM (Color Main/Main Color app.fgColor on startup)
But from all I can tell, it doesn’t get reset. In fact, after it runs, the main color gets somehow corrupted, even though I’m not doing anything to it directly, only to a copy of it.
It progressively gets worse aswell.
I first thought that I’ve somehow introduced a whole set bugs, but I’m now almost positive that all of them come from this.

I’m printing the lightness value of the tempColor before and after every calculation and get this:
Console
Noteworthy, if I am reading CM instead, I’m getting the same numbers

Also, the easing function seems fairly broken. I’ve had to make tweaks to it so it would run in the first place (replacing math.pow with ^)

I’ve rewritten this topic partially a couple of times already because I’ve made changes, tested more, etc. My mental checklist of important things to mention here is a mess now, so forgive me if I forgot something crucial.

Thank you as always for your help!

I’ll be honest with you - I’m not entirely sure at this point what this code is supposed to be doing but I have one note.

Assigning a color, and I mean an instance of the Color type, to a variable doesn’t copy it. It’s an object, a reference type so it still points to the original and any modification of the supposed copy will modify the original.

In order to actually create a copy you should do something like this:

local tempColor = Color(CM.rgbaPixel)

This will create a new instance of the Color type with the exact same value as the original.

2 Likes

I don’t know how I got this far without realizing this! Thanks a lot for pointing this out to me!!

I’ve implemented your fix and now things don’t get messed up anymore! There still seems to be some issues with the easing functions, but I’m now much more confident that with enough tinkering, I can fix this!

The whole function needs a lot of cleanup, I’m still very much just learning by doing. So I can see why it’s not very clear what I’m doing there. To sum it up, I’m trying to replace lookup tables for calculations by implying values based on the user set amount of desired colors in the gradient. So I’m asking how many colors in the gradient does the user want? 15. Is it an even number or not? No, then remove one and halve it. Basically, there will be a gradient of 7 colors from dark to normal on the left, the base color in the middle and from the normal color to white on the right. I’m also using a calculation table I’ve generated to guide the intensity of… Ahhh. I don’t know, I feel like I’m not making things much clearer by explaining it like this. I’ve always had trouble explaining my reasoning behind calculations.

But I promise, it will be worth it! If you are a perfectionist like me! Or crazy! =)

Thanks again!!!

Hey, uhm… Are you sure that Color(CM.rgbaPixel) is going to give me the exact same color? I’ve just verified that it just gives me… well, nothing. The color I’m getting has everything set to 0.

1 Like

I was just gonna say… I agree with the general point about making sure to copy by value, not to pass by reference. I have a slight nitpick, though. Particularly for complex projects, I’d recommend against copying via rgbaPixel. The reason why is that constructing a Color from hex code does not work like one might expect it to.

If you want your dialog to work with sprites that use different color modes, or to work as the user switches between sprites… Idk, they say all advice is autobiographical, and these details are what tripped me up before.

So much so that I avoid Color unless I absolutely have to use it.

The second reason in addition to the reference vs. value distinction is that, internally, Colors combine multiple representations of color into one. Their behavior can change depending on which state they are in. I don’t think a Lua scripter has any window onto the current representation state of a Color.

Extra statefulness means extra confusion when debugging.

The third reason is that Color has poor validation for out of bounds inputs. If a color goes out of gamut, it becomes unclear whether saturation or modular arithmetic is used to determine the color’s hexadecimal equivalent, or the equivalence of one color to another.

For HSL to RGB conversions, I’d recommend looking at a Stack Overflow thread like this one. (I’d also recommend against using HSL… but that’s a rant for another time.)

Sorry about the pedantry.

Cheers,

Jeremy

2 Likes

As with last time, it’s easier for me to offer general advice rather than specifics. Another tool that maybe will help you is an online graphing calculator. Desmos is one, Theta Math is another. There could be others.

Here is an example I made with Desmos that illustrates a small part of the calculations related to your script:

It’s a little finicky about which letters you can use and how to name functions, but I hope you get the gist.

Best,
Jeremy

1 Like

Hey! I planned to go over everything and then make a response once I have results. But this will take a while.
I’m still thinking that for my purposes, using HSL is going to be okay, considering that I’ll only see myself using it in this very instance because it does exactly what I want it to. However, I’ll read up more on the matter, and maybe I’ll switch approaches again if a nicer solution reveals itself in that research.

And I worried, I’ll have to do the easing functions from scratch. But as of right now, they don’t do what I want, and I might aswell just learn the math behind them and come up with a better tailored solution to my problem. No matter how I look at it, learning to use Desmos is probably going to be a valuable skill moving forward anyways.

Thank you for all the advice!