1.
setRadians and getRadians functions for angles in sf::Transformable. It would be backwards compatible, would not break the API, would let everyone use degrees OR radians, whichever they wish.
Yes, I know there is this thread, but it seems that it degraded into pointless argument about what is more 'friendly'...
http://en.sfml-dev.org/forums/index.php?topic=205.0
But yeah, sure - radians are less friendly and SFML is not hardcore-math-knowing-programmer's library. Only more reason for this change - it's very OK that 'default' unit is degrees and radians have to be explicitly present by name in functions that use them.
Yes, public API can do that but it's (literally) few lines of SFML code to save anyone working with radians from few lines of their own code, having to include the header with that code and then calling that single function differently than all other functions on all SFML transformables. It'll allow consistency in common user code. Radians are less common and friendly than angles but still common. This isn't as obscure and user specific as something like asking for allowing sin+cos for rotation would be.
It's a dumb change code wise, it won't break anything that now works with SFML and it'll make radians work out of the box.
2.
Small backwards compatible convenience change to sf::Vector2 constructor, instead of what we have now for casting from different SFML vector types (https://github.com/SFML/SFML/blob/master/include/SFML/System/Vector2.inl#L47) we could have this:
template <typename T>
template <typename U>
inline Vector2<T>::Vector2(const U& vector) :
x(static_cast<T>(vector.x)),
y(static_cast<T>(vector.y))
{
}
which just requires x and y fields in the class, not that it's SFML own class with another type, so vector from another library (say Box2D...) can be passed and work out of the box. This constructor is explicit anyway so it's pretty OK to do that IMO. It really makes sense that vector can be constructed out of something that has x and y in it (in particular - another vector with x and y in it).
3. Color should really have implicit constructor from sf::Uint32 (and possibly operator= too).
It's a bit annoying that I have to write that function myself and use it instead of just doing sf::Color(0xff0000ff) (or even passing number directly to function needing a color). Color and sf::Uint32 actually have same memory layout even, so you could memcpy from one to another so it's really funny there is no function to do that.
There is even implicit constructor from single UTF32 character to sf::String for convenience (which once bit someone in the ass) so why no that too?
HTML, GIMP, Ogre and probably many other use hex numbers like that already. Irrlicht has that kind of constructor so you can pass number to some of its' functions that need a color (some need float 0..1 colors, can't pass the number there).
It's really not at all obscure or unknown and it's really unlikely someone will pass a number instead of color accidentally and wonder what went wrong.
3. This is strange because I've never even previously considered this but, now you mention it, it's something I've been missing for quite some time. Photoshop also uses hex numbers for colours; I thought I'd mention that one since you missed it off your list ;) I must say, though, it would require still being able to assign the colours without the alpha part, and I'm not sure how that would be done here.
Notice that FRex proposed an overload for sf::Uint32 which has 8 hex digits, 0xRRGGBBAA (R = Red, G = Green, B = Blue, A = Alpha).
I guess it could make things a tiny bit easier as oposed to using:
sf::Color c(0xff, 0x00, 0xee, 0xaa);
Notice that FRex proposed an overload for sf::Uint32 which has 8 hex digits, 0xRRGGBBAA (R = Red, G = Green, B = Blue, A = Alpha).
I guess it could make things a tiny bit easier as oposed to using:
sf::Color c(0xff, 0x00, 0xee, 0xaa);
I noticed it was for 8 hex digits, and you're right that it would make it easier to use than specifying the four components separately. However, it wouldn't allow to specify only the colour components.
That said, I'd be all for the four components in one number. I'd have no trouble getting into an automatic habit of typing an extra two fs for a standard (fully opaque) colour :)
1. Bloated API. I don't think anybody will care about writing these two lines of code if they really need this feature
inline float deg(float rad) {return ...}
inline float rad(float deg) {return ...}
2. I haven't got any strong argument against it, but it feels like a hack, not a clean feature. It would only work for half of the other vector classes that exist in the wild, and may even produce hard to understand errors with some of them. Example: in Qt, vectors have x and y members but they are functions; I let you deduce what kind of error the compiler would output in this case.
3. Looks ok.
dedicated type for angles[/url], similar to sf::Time
I agree with this if only to keep consistency within SFML. sf::Time can seem a little extra work sometimes but I like the forced type thing to help reduce errors.
As for not including degrees to radians functions because they're short and easy, think about the sf::Time functions. Divided by 1000? Thanks :P
3. I wonder whether a constructor itself is the most expressive way... an alternative is a static function (named constructor idiom). What about reverse conversion (from colors to integers)?
redColor = sf::Color(#ff0000ff);
redInt = redColor.asInteger();
Possibles?
Indeed #3 would be a nice feature especially for people that are used to web development.
On another subject, it would also be great to add a setAlpha function to SFML graphic entities so one would avoid writing code like this :
sf::Uint8 alpha = 100;
const sf::Color& c = text.getColor();// text is an sf::Text
text.setColor(sf::Color(c.r, c.g, c.b, alpha));
Or maybe there is another straightforward way of writing this code that I'm not aware of?
sf::Color newColor = text.getColor();
newColor.a = newAlpha;
text.setColor(newColor);
Looks a little cleaner to me.
Or maybe there is another straightforward way of writing this code that I'm not aware of?
Global function:
template <typename T>
void setAlpha(T& object, sf::Uint8 alpha)
{
sf::Color color = object.getColor();
color.a = alpha;
object.setColor(color);
}
Works now with any class providing access to color, not just sf::Text.
May be it will be interesting to implement sf::Angle class with methods, returning Deg value, Rad value and sf::Vector2f value. for example
inline sf::Vector2f sf::Angle::toVector(float len = 1.0f) {
return sf::Vector2f(cos(m_angle), sin(m_angle)) * len;
};
But it will be a class with only 1 member (m_angle), so it's better to make it just a functions. And I think everyone can implement what he wants. And now I don't even know why I've written this reply :D
Even if someone uses r,g,b,a it can still result in a different byte order depending on the endianness:
union {
Uint32 rgba;
sf::Color sfcolor;
} mycolor;
mycolor mc;
mc.sfcolor=sf::Color::Green;
sf::Color color(mycolor.rgba);
if(color==sf::Color::Blue)
std::cout << "argh" << endl;
It can result in a different byte order in memory, but we don't care. RGBA usually refers to the "logical" byte order (R is the MSB, then G, then B, and A is the LSB).
sf::Uint32 color = 0x11223344;
sf::Uint8 r = (color >> 24) & 0xFF; // 0x11
sf::Uint8 g = (color >> 16) & 0xFF; // 0x22
sf::Uint8 b = (color >> 8) & 0xFF; // 0x33
sf::Uint8 a = (color >> 0) & 0xFF; // 0x44
... which doesn't depend on the machine's endianness.
You declared unnamed global union named mycolor, not a new union type called mycolor.
This is one of the reasons it won't compile.
A new union type named mycolor would be:
union mycolor{
Uint32 rgba;
sf::Color sfcolor;
};
Also, this is quite an artificial problem, no wants to put sf::Color and sf::Uint32 into an union like you shown, we only intend to add the new constructor.
And actually, an union containing sf::Color will not compile, in C++98 it has a constructor which is forbidden, in C++11 (which relaxed the rules) it has non trivial constructor so it won't compile either.
IF you mean that this byte packing doesn't work on big endian then you are not right either, look:
#include <cstdio>
#define rf 0xff000000
#define gf 0x00ff0000
#define bf 0x0000ff00
#define af 0x000000ff
typedef unsigned char u8;
typedef unsigned u32;
class Color
{
public:
Color(u8 r, u8 g, u8 b, u8 a = 255):
r(r), g(g), b(b), a(a) {}
Color(u32 col):
r((col & rf) >> 24), g((col & gf) >> 16), b((col & bf) >> 8), a(col & af) {}
u8 r, g, b, a;
};
int lilend()
{
int i = 1;
return (*(char *)&i) == 1;
}
void printcol(Color c)
{
std::printf("r = %x, g = %x, b = %x, a = %x\n", c.r, c.g, c.b, c.a);
}
int main()
{
std::printf("endian lil = %d\n", lilend());
std::printf("sizeof u32 = %d sizeof u8 = %d\n", sizeof(u32), sizeof(u8));
Color c(0x00ff00ff);
std::printf("next line is 0, ff, 0, ff\n");
printcol(c);
c.r = 255;
c.g = 0;
std::printf("next line is ff, 0, 0, ff\n");
printcol(c);
}
I ran this code on few machines (since I can't get full SFML there, we use equivalent code like one we intend to use in sf::Color).
This is from an old machine running 32 bit (at least I think so because size of pointer is 4) Sun-OS 5.10 on big endian CPU (it's sparc I think, not sure now, but definitely big endian...).
endian lil = 0
sizeof u32 = 4 sizeof u8 = 1
next line is 0, ff, 0, ff
r = 0, g = ff, b = 0, a = ff
next line is ff, 0, 0, ff
r = ff, g = 0, b = 0, a = ff
This is from my local machine, which is obviously standard Intel CPU, 64 bit capable but running 32 bit Fedora 20 with little endian.
endian lil = 1
sizeof u32 = 4 sizeof u8 = 1
next line is 0, ff, 0, ff
r = 0, g = ff, b = 0, a = ff
next line is ff, 0, 0, ff
r = ff, g = 0, b = 0, a = ff
I by mistake ran it on a multicore FreeBSD on AMD64 (also little endian) and result was same as on my machine.
As you see, endian and bitness doesn't affect this kind of thing, the constructor itself works as intended, we can use the color normally, etc. and unions are non issue, since sf::Color can't be put in one anyway.