Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Support scalar color operator overloads  (Read 4160 times)

0 Members and 1 Guest are viewing this topic.

kavika13

  • Newbie
  • *
  • Posts: 3
    • View Profile
Support scalar color operator overloads
« on: August 18, 2016, 06:01:14 pm »
Posting in response to this feature request issue:

https://github.com/SFML/SFML/issues/1128

To kick off the thread again, here's my first post from there ->

For simplicity and brevity in working with colors, it may be useful to support scalar math operators.

Color darkGreen = Color::Green - 127;
Color darkGray = Color::Black + 63;
Color darkerColor = someComputedColor * 63;

The equivalents are already possible now, but are more verbose:

Color darkGreen = Color::Green - Color(127, 127, 127, 0);
Color darkGray = Color::Black + Color(63, 63, 63, 0);
Color darkerColor = someComputedColor * Color(63, 63, 63, 255);

Problems I see:

  • Accidental implicit conversions. I think this is already taken care of by providing operator uint32_t as a named member function instead of an overloaded operator. It is also taken care of by making the Color(uint32_t) constructor explicit.
  • The operator * might be confusing, since it scales down, not up. The existing operator * already does this, and anyone who is "multiplying" colors already has to understand this difference as it stands today. I'd change my mind if operator / was introduced, but I think that's a very confusing construct to begin with for someone who isn't super familiar with color math, so I think it should not go into the library anyway.
  • There might be anxiety on the user's side on whether the alpha channel is touched or not. This could be cleared up by documentation of the scalar operators. I think preserving the alpha channel in these operators is the more common case, and is the least surprising.

If there was interest, I'm perfectly happy and able to put in a pull request implementing these features. I'd prefer to ask for comments and/or a rejection before I spend time on it.

kavika13

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Support scalar color operator overloads
« Reply #1 on: August 18, 2016, 06:04:19 pm »
On the other thread, people have already commented that the multiply not affecting the alpha value would be confusing.

I personally think it would be confusing only for people who were familiar with shaders. If you want to affect all components, you can always step back to the more verbose Color * Color multiplication.

Thoughts?

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Support scalar color operator overloads
« Reply #2 on: August 18, 2016, 08:21:44 pm »
I don't think subtracting a single integer from a colour that stores four makes any sense. It's worse that it doesn't even affect all four, just a chosen three. It's not intuitive. Normally if you want a different colour, you would state the colour you want.

However, since alpha is a single value, this is the most obvious use for the this calculation. I'm not saying it should do this but sf::Color::Green - 20 looks more like the alpha should be reduced by that amount.

I don't understand why the so-called verbose version is bad.
Even if you do think it's ugly, you could always use a function for this.
// simple functions solution
sf::Color offsetGray(const sf::Uint8 value)
{
    return sf::Color(value, value, value, 0);
}

// simple and clear usage
const sf::Color darkGreen = sf::Color::Green - offsetGray(127);
const sf::Color palerBlue = sf::Color::Blue + offsetGray(64);;

In fact, you could simply just create a colour from a single value:
const sf::Color darkGreen = sf::Color::Green - sf::Color(0x7f7f7f00);
const sf::Color palerBlue = sf::Color::Blue + sf::Color(0x40404000);

You also mention in your issue that you think there could be a float-based colour class and an integer-based colour class. That's obviously too confusing and there isn't really much need for it in SFML since you can build your own and convert to SFML colour when you actually use it with SFML. In fact, that's exactly what I did ;)

As for the scaling operator, you can simply add this yourself if you must have it; you don't need to modify SFML:
sf::Color operator*(const sf::Color color, const float scalar)
{
        return sf::Color(static_cast<sf::Uint8>(color.r * scalar), static_cast<sf::Uint8>(color.g * scalar), static_cast<sf::Uint8>(color.b * scalar), color.a);
}
or
sf::Color operator*(const sf::Color color, const sf::Uint8 value)
{
        const float scalar = value / 255.f;
        return sf::Color(static_cast<sf::Uint8>(color.r * scalar), static_cast<sf::Uint8>(color.g * scalar), static_cast<sf::Uint8>(color.b * scalar), color.a);
}

You can, of course, also add the addition and subtract operators if you don't like my other simple method :p :
sf::Color operator+(const sf::Color color, const sf::Uint8 value)
{
        return sf::Color(color.r + value, color.g + value, color.b + value, color.a);
}
sf::Color operator-(const sf::Color color, const sf::Uint8 value)
{
        return sf::Color(color.r - value, color.g - value, color.b - value, color.a);
}
Again, in your own code without SFML being modified.

You may also want to consider the possibility of having some form of linear interpolation between colours. Pretty useful for "mixing" colours.
« Last Edit: August 18, 2016, 09:01:55 pm by Hapax »
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
AW: Support scalar color operator overloads
« Reply #3 on: August 18, 2016, 11:42:14 pm »
For me Hapax basically said everything. :D

The main take away point for me is, that ambiguous APIs and especially ambiguous operator overloads shouldn't be used.
Additional operator overloads can always be addes on the user side and if one can't live without a (arguably) "simpler" API, then custom functions can help a lot.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

kavika13

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Support scalar color operator overloads
« Reply #4 on: August 19, 2016, 02:00:04 am »
Lol, I guess I'm the crazy one. I just polled 5 of my programmer friends of various levels of graphics experience, and they had the same hangups as you guys.

I think doing math like this has several common uses cases (even for newbs) if the alpha is masked out on these operators (see the other thread for that list if you are interested).

I don't think affecting alpha and colors at the same time is useful, even if it is "intuitive". If you can come up with use cases, I'm still interested, in case I get the urge to write my own float color class as an extension.

I think affecting alpha only has a very obvious set of use cases, but I personally would be more surprised by that (and so far my polls show that to be a unique interpretation).

I agree, too ambiguous to add, even if I personally would expect the class to do this due to use-case enablement. I really don’t want it to be a POLA argument, but it’s hard to recommend a change that causes support requests, even if it makes common use cases marginally more convenient.

Cool, thanks for the consideration!

(I won't call this dead til you guys do, but I think the responses I've gotten so far on the surprise factor are pretty conclusive in my opinion)
« Last Edit: August 19, 2016, 02:34:57 am by kavika13 »

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re: Support scalar color operator overloads
« Reply #5 on: August 19, 2016, 03:10:05 am »
A cool alternative that could technically make all parties happy would be to simply add swizzling to sf::Color (and sf::Vector#<T>)!

(I'm not serious, just to be clear. As cool it would be, I don't find it worth the effort. Though, it has been done.)

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Support scalar color operator overloads
« Reply #6 on: August 19, 2016, 02:12:40 pm »
I don't think affecting alpha and colors at the same time is useful
I think that is the problem.
The colour as a whole and the alpha are often used separately. This is not how sf::Color is; it stores four components and acts on them equally. An sf::Color is, therefore, the colour and the alpha as one (RGBA) and any operation on it should affect it all. Otherwise, it would be like subtracting 1.8 from 2.5 and it only affected the integer part (resulting in 1.5). You can manipulate the components separately but the colour components and the alpha components are treated equally.

The only intuitive "solution" :-X would be for a colour class that contained the actual colour as one part as the alpha as another:
sf::Color color;
color.color.r = red;
color.color.g = green;
color.color.b = blue;
color.alpha = alpha;
sf::Color orange(sf::Color::Color(255, 128, 0), 255); // resulting in something like this?
Then you could perform operation on the color-color that wouldn't affect the alpha.

Yes, color-color is very confusing :D

I'm fine with the way it is...  :P
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*