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

Add OK HSV methods to Color API #76419

Closed
wants to merge 1 commit into from
Closed

Conversation

bonjorno7
Copy link
Contributor

@bonjorno7 bonjorno7 commented Apr 24, 2023

Fixes: godotengine/godot-proposals#6753

I noticed OK HSV was missing from from the API, so I added it.
I've also added some missing API for OK HSL to match.
I might try to implement an OK HSV color picker as well, but that will be its own PR.

Here's a demo project: Color Demo.zip
Color Demo

@fire
Copy link
Member

fire commented Apr 24, 2023

Thanks.

I think this is all gdscript bindings so there's nothing to show, but maybe we can find some test color values and a photo.

It looks good but waiting for the github actions to pass to be able to test.

@fire
Copy link
Member

fire commented Apr 25, 2023

patch.diff.txt

You have some errors in the documentation found by the github actions. Please read https://docs.godotengine.org/en/stable/contributing/workflow/pr_workflow.html

@bonjorno7
Copy link
Contributor Author

bonjorno7 commented Apr 25, 2023

You have some errors in the documentation found by the github actions. Please read https://docs.godotengine.org/en/stable/contributing/workflow/pr_workflow.html

Is there a way to replicate the failing test locally? I don't really understand the error message here.
Wait.. is the order wrong?? Is it failing because it's not in alphabetical order in the XML?

Also while making an example project I noticed there is no from_hsl method either, so I'd like to add that as well for completeness. Should that be a separate PR?
If it can be included in this PR, I'll have all 4 modes (HSV, HSL, OKHSV, OKHSL) in the example project; otherwise I'll leave out HSL as it wouldn't be testable with this PR.

@fire
Copy link
Member

fire commented Apr 25, 2023

Yeah, it's a good idea to add from_hsl. Smaller prs are faster to review.

@AThousandShips
Copy link
Member

The reason it's failing is that you need to put the methods in alphabetical order, I suggest building the code locally and using --doctool to make sure it generates the correct documentation (make sure you're not building a double-precision build, it affects documentation and you'd need to pay attention to what changes are relevant)

@bonjorno7
Copy link
Contributor Author

Alright I fixed the documentation now I think.

As for from_hsl, should I reuse set/get h/sand just add set/get l, or should I rename those to set_hsv_h etc and add set_hsl_h etc?

@fire
Copy link
Member

fire commented Apr 25, 2023

I would be explicit and use set_hsl_h . The documention seems to be named with the wrong casing.

@bonjorno7
Copy link
Contributor Author

I would be explicit and use set_hsl_h . The documention seems to be named with the wrong casing.

I prefer that as well.
Should I also rename the existing set_h/s/v to set_hsv_h/s/v?
That'd be a separate cleanup PR.

@fire
Copy link
Member

fire commented Apr 25, 2023

The 4.0 existing apis aren’t allowed to change without a deprecation notice as far as I know

@bonjorno7
Copy link
Contributor Author

bonjorno7 commented Apr 25, 2023

I see, then I'll just leave HSV alone when I add HSL, and let someone else figure this out in the future.
Unlike with OK HSV/L where the C++ functions are already there, I might have to do some actual math here, which I'm not very good at, so that PR could take a while.
Should be independent of this one though so it doesn't matter.

@bonjorno7
Copy link
Contributor Author

I find myself needing a way to convert a color from RGB to OK HSV as well, so I'll try to add that too.

@bonjorno7
Copy link
Contributor Author

I suppose I'll add ToOkHsv and ToOkHsl methods for C# next.

@bonjorno7
Copy link
Contributor Author

bonjorno7 commented Apr 26, 2023

I don't know whether any of the C# stuff works, because dotnet is not cooperating on my computer.
If it ends up being too difficult or out of scope, I don't mind reverting the C# specific changes.

Copy link
Member

@fire fire left a comment

Choose a reason for hiding this comment

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

I don’t use dot net so unable to review that section deeply. Reviewed the design. Pending need to do the test plan of running your color sample.

I thought the dot net was generated by script?

@bonjorno7
Copy link
Contributor Author

Alright after much fiddling I have C# working on my end, and thankfully the API seems to behave as it should.
Various things relating to dotnet are generated, but there is manual work, as you can see here and here.
Anyway, if you're happy with the GDScript changes, you will most likely be happy with the C# changes too.

@fire
Copy link
Member

fire commented Apr 26, 2023

Looks good, but can you merge the commits? "Squash"?

@bonjorno7
Copy link
Contributor Author

bonjorno7 commented Apr 26, 2023

Done, I squashed the changes into one commit with a consise summary of changes.

@fire
Copy link
Member

fire commented Apr 27, 2023

The color picked zip you loaded doesn't match your photo. It can't load colors. So I can't test that.

I think the pr is great, but I wanted to try your demo.

@bonjorno7
Copy link
Contributor Author

bonjorno7 commented Apr 28, 2023

I've updated the demo now, it's starting to look a bit more polished.
The controls are left click the background to rotate camera, left click drag a point to move it, right click drag to zoom in and out, scroll to offset hue (not applicable to RGB viewing mode).
Various menu options are grayed out, because they are not implemented yet.

Copy link
Member

@fire fire left a comment

Choose a reason for hiding this comment

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

It seems like you got the demo working to how you like it.

Looks good to me.

@bonjorno7
Copy link
Contributor Author

Does anything else need to be done before it can be merged?

@bonjorno7
Copy link
Contributor Author

bonjorno7 commented May 9, 2023

Something that I did for HSL but forgot to do for OK HSV and OK HSL is return 0 for hue when saturation is 0, so I'll add that.
It's turning out to be surprisingly tricky; will continue tomorrow.

@Zireael07
Copy link
Contributor

I'm not an artist, so I'm more than a bit confused. You said HSV and HSL account for human perception, what's the reason there's two of them?

@AThousandShips
Copy link
Member

They are two different ways to represent the same idea I believe

@AThousandShips
Copy link
Member

"The HSL representation models the way different paints mix together to create color in the real world"
"Meanwhile, the HSV representation models how colors appear under light. The difference between HSL and HSV is that a color with maximum lightness in HSL is pure white, but a color with maximum value/brightness in HSV is analogous to shining a white light on a colored object (e.g. shining a bright white light on a red object causes the object to still appear red, just brighter and more intense, while shining a dim light on a red object causes the object to appear darker and less bright)."

@AThousandShips
Copy link
Member

(now we've both learned about these things! I didn't know before)

@Zireael07
Copy link
Contributor

Oh. In that case bonjorno is kinda right that having one and not the other is... weird.

@AThousandShips
Copy link
Member

AThousandShips commented May 10, 2023

One could argue that one is more suited to computer graphics than the other, but that would be HSV not HSL by the way I'm understanding the different ideas, though I guess HSL could be more suited for working with UI

@bonjorno7
Copy link
Contributor Author

bonjorno7 commented May 10, 2023

I'm not an artist, so I'm more than a bit confused. You said HSV and HSL account for human perception, what's the reason there's two of them?

It's the OK part that accounts for human perception; the difference between HSV/HSL and OK HSV/HSL.
I recommend taking a look at this post: https://bottosson.github.io/posts/colorpicker/

The difference between (OK) HSV and (OK) HSL is light vs paint, but you already knew that.

@bonjorno7
Copy link
Contributor Author

Here's how I see it:

HSV HSL
Standard Mario Luigi
OK Wario Waluigi

This commit adds functionality for converting to and from OK HSL and OK HSV color spaces.
For GDScript it adds a function to convert from OK HSV, and members for converting to OK HSV and OK HSL.
For C# it adds a function to convert from OK HSV, and functions for converting to OK HSV and OK HSL.
The conversion isn't always as efficient as it could be, but it's good enough.
@bonjorno7
Copy link
Contributor Author

Conversion to OK HSV/L now behaves correctly with grayscale values.
The issues were:

  • Hue was essentially random.
  • Saturation was low but not zero.
  • Value was NaN for some edge cases (Lightness works fine so I use that as a fallback).

@QbieShay
Copy link
Contributor

It explains the need to have them in your application, but not the need to have them as a part of the Godot core Color class.

What about a color utility class with all the conversion? that way it can be outside of core and still provided in the engine.

Comment on lines +329 to +330
ok_color new_ok_color;
ok_color::RGB rgb = new_ok_color.okhsv_to_srgb(hsv);
Copy link
Member

Choose a reason for hiding this comment

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

@fire Why is ok_color a class? 🤔

class ok_color

You've added it like this in #59786 even though in the original source (from this post) it is as namespace.

Suggestion: change ok_color back to be a namespace so the code in here (and similar code in other places) could be changed like:

Suggested change
ok_color new_ok_color;
ok_color::RGB rgb = new_ok_color.okhsv_to_srgb(hsv);
ok_color::RGB rgb = ok_color::okhsv_to_srgb(hsv);

Needing to create an instance like new_ok_color just to be able to call a method not operating on that instance makes no sense to me.
Alternatively (if for some reason class is preferred over namespace) such methods could be changed to be static.

Copy link
Contributor Author

@bonjorno7 bonjorno7 May 10, 2023

Choose a reason for hiding this comment

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

OK HSL conversion was already part of the engine before I came along.
I don't know why it's a class instead of a namespace, I just followed the conventions in the existing code.
I can change it if you'd like, but I'd have to change it in more places too then.
Edit: Oh you weren't talking to me. Perhaps this should be a separate cleanup then.

Copy link
Member

Choose a reason for hiding this comment

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

@bonjorno7 Indeed might be out of scope of this PR. Just catched my eye, hence the comment. 🙃

@bonjorno7
Copy link
Contributor Author

What about a color utility class with all the conversion? that way it can be outside of core and still provided in the engine.

OK HSL conversion is already part of core, so I don't think it makes much sense to give OK HSV its own class.

@bonjorno7
Copy link
Contributor Author

I hope my simple addition to a previously almost complete API doesn't spark a heated debate, ending in its untimely demise.

@QbieShay
Copy link
Contributor

QbieShay commented May 10, 2023

It's not about demise, I think there's pretty much consensus on the fact that we want this, but not exactly where. Core is a very delicate set of classes. When i say core i don't mean the engine as a whole, i specifically mean the core/ folder

@bonjorno7
Copy link
Contributor Author

bonjorno7 commented May 10, 2023

It's not about demise, I think there's pretty much consensus on the fact that we want this, but not exactly where. Core is a very delicate set of classes. When i say core i don't mean the engine as a whole, i specifically mean the core/ folder

I'd be fine having OK HSV and OK HSL in its own converter utility class or global scope functions, but then we should remove OK HSL from the core Color class too.
Having OK HSL in core but putting OK HSV elsewhere would make no sense.
Color already has a ton of conversation methods which I would argue should be moved too then, quite an undertaking.
I think the simplest option is to just add it in core, and worry about moving conversion code out of core in another PR.
Preferably in that order, because it could be quite a bit of work.

@clayjohn
Copy link
Member

It just doesn't make sense to support HSV, HSL, and OK HSL, but not OK HSV. I'm simply making this part of the API complete. The functionality is already mostly there, I'm just adding the missing pieces and exposing it to the API. OK HSV is not "yet another color space" to me; I think it's just as important as the others, and can't be substituted. Having OK HSL but not OK HSV is like having Luigi but skipping Mario.

I feel the need to clarify my above as I don't want to sound like I am being needlessly dismissive. I'm sorry if I sounded that way.

We have to be super careful about what we merge into the core section of Godot. The core is intended to be the lean mean center of the engine. A place to collect the datatypes and functionality that are used throughout the engine and by many of our users. It is not the place to aggregate helpful utility functions that will save users from writing code themselves. Although sometimes if a function is used often enough, it will be included in core for just that reason (see the math namespace for examples of that).

It is necessary for the project to be super strict about what we add to the core as once we add something we rarely remove it. So over time the core has a tendency to grow, become more complex, and become more sluggish. Each individual change may be totally acceptable and helpful. But over time we risk suffering from death by a thousand cuts. Accordingly, over time we unfortunately have to become even more strict with what we allow into the core.

This PR to me seems like it is exposing another color space because it would be nice to complete the set of HSV, HSL, OKHSL, OKHSV. To me, that isn't enough justification for adding something to the core. OKHSL was added because it was needed for the color picker. OKHSL is a much nicer color space for color pickers. That being said, in my opinion, it was a mistake to add the OKHSL functions into the core Color class. We needed the color space for the color picker, we didn't need to add functions to core in order to do that. But we have added it, so we have to maintain it. That being said, just because we mistakenly added something into core earlier doesn't mean we should continue to do so, the floodgates have not opened up.

One of the things we as maintainers fear is that if we merge one new feature, a flood of similar but slightly different features will follow. That can quickly take a class that was lean and make it bloated. In my opinion, we are at risk of that happening here.

When faced with new features that would be nice to have, we should instead ask where they would make the most sense for users outside of core and evaluate those options before adding things to core. For example, your stated need is for making a color picker app. Accordingly, these conversion functions could likely be added as part of the ColorPickerAPI (ideally OKHSL would have been exposed there initially as well). Or alternatively, we could expose a ColorUtils class as QbieShay suggested above. That would allow us to be more free with what we add as the ColorUtils class will only be included in the files that need it and not in thousands of files throughout the engine. Additionally, moving to another class also makes it easier for us to add new color spaces according to user demand (like CieLab and others).

So what I meant to do above is open a discussion about the need for this feature and how we may be able to meet that need in another way that also respects the needs of the Godot Project. But I think I came off us dismissive instead, so my apologies for that.

@Zireael07
Copy link
Contributor

Zireael07 commented May 11, 2023

Or alternatively, we could expose a ColorUtils class as QbieShay suggested above.

This is probably the golden ticket here (both for this and the HSL that you reverted)

But I think I came off us dismissive instead, so my apologies for that.

Unfortunately yes you did

@bonjorno7
Copy link
Contributor Author

I'll get started on a utility class then.
Should it have only OK HSV, or should I add the other color spaces too?
It would make sense to me to make it feature complete, in anticipation of the removal of those color spaces from core.

@QbieShay
Copy link
Contributor

Hey @bonjorno7 , before starting to code it's better to add a feature proposal so we can discuss it there. If you can link it here, then everyone that participated here will have a link to it and we can discuss exactly what we want in there.

My uninformed take is that we could make methods for the current conversion methods and perhaps also move the color constants there. I'd make a static class called ColorLibrary or something similar.

However, take my suggestion with a grain of salt, I'm not as informed as clay or other contributors on what's the best implementation and the best way to split the class so it's best to get their input first and consider it above mine ^^

@bonjorno7
Copy link
Contributor Author

bonjorno7 commented May 11, 2023

@QbieShay what category should this discussion go in?
There's 2D, 3D, Editor, Engine Core, General Discussions, GUI, Platforms, and Scripting.
I'm torn between Engine Core and Scripting.
Alternatively I could hijack godotengine/godot-proposals#6753 and make it a discussion maybe.

@bonjorno7
Copy link
Contributor Author

Welp here it is anyway: #76976
Still WIP as I don't know what exactly needs to be done yet.

@QbieShay
Copy link
Contributor

Thank you @bonjorno7 for taking this feedback graciously. I will write up my ideas there and hopefully we will obtain a satisfactory solution for everyone.

@bonjorno7
Copy link
Contributor Author

Superceded by #76976

@bonjorno7 bonjorno7 closed this May 12, 2023
@YuriSizov YuriSizov removed this from the 4.x milestone Jul 24, 2023
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.

Add more color space conversions