-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Added a new constructor that takes single Uint32 to Color #722
Conversation
It would be safer to make this constructor explicit. And why not add the Color -> Uint32 conversion as well (let's call it This will be similar to what's done in |
Yep, I agree to everything. ;) @FRex |
No, no - the whole point was to NOT make it explicit to allow using unsigned as if it itself is a color (setColor(0xff00ffff)) instead of having to bother typing anything more than that. Making it explicit makes this feature redundant becuase you could have written your own conversion function (or 10) already and named it however you liked. There is little risk making it implicit because it's very unlikely someone will pass unsigned accidentally to function expecting a color without knowing what they are doing. As for why IpAdress does it this way - I don't know and I don't care, especially since hex adress representation is very rare (IMO..), way more rare than the normal 4-octets-in-decimal one, there are tons of insonsistency about this (implicit constructors) already anyway - single char or unsigned can be turned into 1 length sf::String implicitly (kind of weird) and const char * and std::string can be turned into IpAdress implicitely (I guess because it's more common to use names or dot separated octets that it is to use hex). |
Hm... may I suggest using ARGB rather than RGBA for the color format? Or is that some consistency thing (e.g. with SFML's texture format, didn't check that right now). This would allow passing 24 bit colors (without an alpha channel) as well, since colors with 0 alpha don't make any real sense (unless hiding some mask for post processing but those wouldn't be used with This would make this far more useful for people being used to classic HTML/CSS colors not defining an alpha channel:
|
Even if rarely used, turning alpha = 0 to alpha = 0xFF looks like a dangerous ugly confusing thing 😕 And no, I don't want to change the order or components anyway. |
This disallows the alpha of 0 completely, so it's rather bad, considering this is (in theory...) a 1:1 shortcut to the usual constructor (same order, same values, etc. just minus the alpha = 255 default argument). CSS (Color Module 4 introduces 8 digit hex to specify alpha, among other things, so far we just had 6 hex digit RGB colors with no alpha possible, the new 8 hex digit ones are in RGBA order too, BTW) can do this because they control the parser, we don't know if we got 6 digits or if we got 8 and the first two were 0s. If it really is a big issue to write 8 digits and not lose count you can make convention to type last two fs in caps if you don't care for them: red = 0xff0000FF or similar. It kind of sucks still and it's so bad that C++14 actually allows using ' to split number literals to make them more readable. 6 hex digits is not super more readable than 8 either. Also your "halfred" is a bit wrong, 0x70 is 112, I'd expect "half" of range of 0..255 to mean something like 127 (0x7f). ;) Also, why wouldn't postprocessing constant with 0 alpha be used with sf::Color? sf::Shader has overload that takes sf::Color so you could (and probably should, instead of normalizing it to 4 floats yourself) use your hex color with 0 alpha there instead of having to type sf:Color(r, g, b, 0) if you want, since this is the purpose of this "feature". |
I would definitely make the conversion explicit. When you can pass any number (not just integers with 0x prefix) as a color, there are a lot of places where bugs can easily be introduced. void DrawCircles(int howMany, const sf::Color& color);
// Caller doesn't remember signature
DrawCircles(0xaabbccdd, 4); // silent bug (not even a warning) Even worse: sf::Shader shader;
shader.setParameter("color", 0xaabbccdd); // guess which overload is called |
I'd also vote for the explicit constructor. Although in case of the shader parameter you could still just forget about it (and you wouldn't receive a warning or error). |
The first "example" is very meh. |
Well... if you are really paranoid about setParameter, templated versions with 1, 2, 3 and 4 parameters could be added that are made to fail compiling on purpose (via C++03 static assert or a private method). This will make sure that no implicit conversions can be performed when calling setParameter. I did this with GLS although using = delete. This might also solve an issue we had with #538. |
Well, I have already wasted a lot of time debugging similar mistakes (sometimes introduced by other people, over longer time, and not rarely in the depths of code where no one would suspect them), so I began to appreciate APIs that are a bit less convenient but more type-safe ;)
The |
What's the status of this PR/discussion? |
I'd say that we should make this constructor explicit for now, we can always make it implicit in the future if it really bothers users. Forget about the counterpart ( |
I'm also in favor of an explicit constructor, because hiding |
I'm also in favor of explicit conversions rather than silent ones. An explicit constructor is more consistent with the current API but a (good) alternative would be a factory function. Personally I would include @eXpl0it3r using brace initialisation doesn't work with explicit constructors. http://ideone.com/cVRjvq ;-) |
@mantognini Ah right! 😄 I'm not sure how many people will actually use this for serialization, because having some numbers written in a non-hex representation feels kind of odd ( I personally see this feature only as a convenience when writing code, but maybe I'm short sighted. |
@eXpl0it3r But readability of the output was not my main point. If we have a config file (that no human will ever read), and we are able to load color from a single integer with one call to the API, then it strange that we are not able to do the opposite operation with one call of the API. |
It HAS to be explicit because of the overloads in sf::Shader, no question about it. |
This serialization "issue" is less obvious than with But yes, we can add it for consistency.
Since there's no |
@LaurentGomila Wrong - I just merged this feature to latest master and recompiled my SFML. #include <SFML/Graphics.hpp>
int main()
{
sf::Color hehe2(0xff0000ff); //just to verify we DO have that feature
sf::Shader shader;
shader.setParameter("hehe", 0xff0000ff); //what does this call?
} They just doesn't care for implicit constructors when there is a single built-in conversion available. |
He he... Thanks for confirming that you were right about this. So this is indeed a strong argument against the implicit constructor -- until we possibly change the sf::Shader API. |
Believe me, I'd love to be wrong about this and defend implicity of that constructor (with coarse langauge if necessary) but I'm sadly right. P.S. I did that exact check vs. sf::Shader::setParameter months ago, when I originally have given up the idea of implict constructor. Who do you think I am? ;) P.P.S. Addding (or not) the symetric getter is another thing which can be discussed, decided and implemented separately from this IMO. |
Yes, my point exactly (but better explained!). @FRex, why rushing that fast? It's not like SFML 2.3 is due tomorrow. ;) Unless someone has an argument against |
@mantognini Because I find it stupid how long it takes for minute things like this, it's over 3 months at this point (the idea originally appeared on forum in September) and already lost my interest once because of that, if exploiter didn't bump this I'd not care in the least. |
This is mostly because we were busy finalizing many non-code things for the SFML 2.2 release... Now you can expect things to go slightly faster ;) |
af31142
to
ef144d6
Compare
I rebased onto master and implemented |
//////////////////////////////////////////////////////////// | ||
Uint32 Color::toInteger() | ||
{ | ||
return r << 24 | g << 16 | b << 8 | a; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather write it as (r << 24) | (g << 16) | (b << 8) | a
to make compilers happy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not 100% sure right now, but does this even work without casting, considering the components are Uint8
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated!
I haven't gotten any warnings with -Wall -Wextra
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just tried it, there's an implicit conversion happening.
unsigned char a = 5;
std::cout << (a << 8) << std::endl;
Result is indeed 1280.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rules are rather confusing with << operators: the return type is the (promoted) left operand's type which is promoted to int here because of the right operand being int. So, from my understanding of the standard it's safe as is.
But it's quite tricky and maybe I'm wrong and the compiler should emit a warning.. 😁
ef144d6
to
512625c
Compare
👍 |
/// \param color Number containing the RGBA components (in that order) | ||
/// | ||
//////////////////////////////////////////////////////////// | ||
Color(Uint32 color); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be explicit
.
And maybe another name for the parameter? "integer" would be consistent with toInteger
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right forgot to adapt that.
512625c
to
22a6cd4
Compare
Added |
About the |
I'm with @mantognini, the name "color" is more expressive. "integer" describes the type and is similar to Hungarian notation. ;-) Just imagine the case for all elements: Color( Uint32 integer0, Uint32 integer1, Uint32 integer2, Uint32 integer3 );
Color( Uint32 r, Uint32 g, Uint32 b, Uint32 a ); Which one is more expressive? :P |
So what about |
|
Same. 👍 |
22a6cd4
to
5321a7c
Compare
Reverted to the |
This PR has been added to my merge list, meaning it will be merged soon, unless someone raises any concerns. |
@@ -62,6 +62,22 @@ class SFML_GRAPHICS_API Color | |||
Color(Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha = 255); | |||
|
|||
//////////////////////////////////////////////////////////// | |||
/// \brief Construct the color from 32 bit unsigned integer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be really nitpicking but shouldn't it be 32-bit
(with a dash)? Do we care?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
5321a7c
to
1f2bc14
Compare
Added a new constructor that takes single Uint32 to Color