Skip to main content
GameDev.net gamedev.net
🔒 Locked

Colour class/struct

Started by XTAL256 Mar 11, 2008 at 2:45 AM 9 replies 1k views
Original Post
XTAL256
XTAL256
What is the best way to go about making a Colour class. I am thinking of three different ways: * Store r,g,b,a as separate byte fields and, if needed, pack all 3 into an int * Store as int; a=[31-24], r=[23-16], g=[15-8], b=[7-0] and use masking/shifting to extract bits. * Use bit-fields I think the last would be the best (fastest) wouldn't it? Say i had this:

unsigned {
    a : 8
    r : 8
    g : 8
    b : 8
}


What order is that in, is 'a' [31-24] or [7-0]? thanks
[Window Detective] - Windows UI spy utility for programmers
MaR_dev
MaR_dev
What about nameless union?

union {  struct {    uint8 r;    uint8 g;    uint8 b;  }  uint8 c[3];}//or evenunion {  struct {    uint8 r;    uint8 g;    uint8 b;  }  uint8 c[3];  uint32 rgb;}


EDIT: oh sorry copy&paste bug uint32 rgb[3] :o)

[Edited by - MaR_dev on March 11, 2008 7:54:10 AM]
samoth
samoth
Bitfields and shifting/masking are slower and undesirable (especially the latter) if you want portability.

I'd make it an union of uint8_t and uint32_t as MaR_dev proposed.
You would use the uint32_t field for being able to do a fast copy, fast zero assignment, and a fast propagate (but not for anything else), and the uint8_t fields for everything else.

Folk says that accessing unaligned bytes is slow and bad, but at least on X86, it is not nearly as terrible as people believe. Since instructions are variable length, that's not surprising, either.
In fact, unaligned bytes will even be faster if the data set is large enough (due to cache and paging).
XTAL256
XTAL256
@MaR_dev: Yes, that's a good idea. What is 'uint32 rgb[3]'? It looks like a 32-bit representation of each field but the way you've named it, it looks like it is red,green,blue all in one int.

After posting i read up on bit fields and it seems that the code generated by most compilers is not optimal and the order is not the same on all compilers. But if i store each as a byte then the computer will have to load each separately into a 32bit register which will waste space. I think the best choice is to use a way that will be quickest to use with OpenGL (which is what i am using). Let take a look at gl.h, i could use glColor4ub for bytes and glColor4bv if i use the array variable in your union.

EDIT: thanks samoth, you must have posted that just before me 'cos i didn't see it when i clicked reply.
[Window Detective] - Windows UI spy utility for programmers
eq
eq
Why limit the color to 256 values per component?
What about HDR representations etc?

I'd use a floating point representation or something, this also makes the math operations on the color type a lot simpler and the compiler could generate fast SSE code for you under the right circumstances.

For instance try doing this fast and accurate using your representation:

Color a = xxxx;
Color b = xxxx;

a.addAndClamp(b); // a + b for each component then clamp to max

In SSE this would require two instruction:

addps xmm0, xmm1
minps xmm0, QWORD PTR [constantOnePtr]

jpetrie
jpetrie
Use four floats, and stop worrying about performance loss from a simple struct. If your color manipulation operations suddenly become a huge bottleneck, then we can talk. Otherwise you're wasting your time: pick the representation that allows you to achieve the semantics you need to achieve with minimal fuss.

This is almost always four floats, four bytes, or a single 32-bit value. None of this screwing around with bitfields and potential undefined behavior (certain anonymous aggregate types are not legal according to the C or C++ standards, depending).
XTAL256
XTAL256
Aaargh, now i don't know what to use! I'm not that worried about performance, i just would like to know the best way. I could probably be using this time to worry about something else :D
OpenGL represent colour internally using floats doesn't it, because it doesn't depend on the number of bits per pixel.

@eq: how do i use SSE? Does the compiler automatically generate SSE code? I would have thought floats would be slower but i guess it wouldn't be noticeable if it were.

Ok, i will use float values for r,g,b and provide a constructor to use byte values (since i am more use to using values in the range [0-255]). That way i can easily say Colour(255, 128, 0) for orange yet it won't be restricted to 256 values.
[Window Detective] - Windows UI spy utility for programmers
jpetrie
jpetrie
There is no one best way. There is also nothing wrong with having more than one color class; one for byte-based values and one for float-based values, for example. Just pick what works now and worry about anything else later. Trust me.
dmatter
dmatter
To gain some amount of flexibility in choosing the data type you could use typedefs to 'wrap' several colour classes and/or templates:

template <typename T>class Colour4{    T r, g, b, a;};// Explicitly typed (Convenience typedefs)typedef Colour4<float> Colour4f;typedef Colour4<uint8_t> Colour4b;//....// For general use (You can change the type later on)typedef Colour4f Colour;


You might prefer the typedefs to indicate the use of the colour, e.g. HDRColour, GreyScaleColour (bit of a contradiction I know), and so on.

Provided that the interface stays consistent then you can chop and change the underlying data type and the implementation at any time. The typedefs provide a form of static polymorphism.

Apart from anything, this gives you the piece of mind that if the colour class you chose turns out to be slow then it's trivial to change a typedef and recompile, all with minimal fuss.
CProgrammer
CProgrammer
I have to agree with JPetrie.
It is usually not desirable to use special constructs such as the ones mentioned here. There are exceptions but this is not one of them since things work perfectly fine with typical constructs. Just define 4 floats or ints in a struct or class and voila you have your color. The fact that you may end up using more memory or that you may loose some performance when converting between types etc. is unlikely to be relevant. What truly matters in PC Software Development is code readability, reusability, maintainability, scalability, compatibility.
If you are working on some low performance microcontroller then you may have to consider this, although it is still unlikely.
XTAL256
XTAL256
Quote:
Original post by CProgrammer
...What truly matters in PC Software Development is code readability, reusability, maintainability, scalability, compatibility.

Well, that is also what i want. Notice i used the word "best" in my first post, indicating that fasted wasn't my only concern.
Besides, i am over this. I already made the decision to use floats since that is what OpenGL uses, and i can easily change to int, etc if need be but that won't be very often.
thanks for all your help.
[Window Detective] - Windows UI spy utility for programmers

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.