• Advertisement

Archived

This topic is now archived and is closed to further replies.

Union tricks?

This topic is 5709 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

A while back, I thought it might be handy to represent a ARGB Color as a BYTE[4], a DWORD, and A/R/G/B. I built his union:
  
typedef union _Color
{
    struct { float a, r, g, b; }argb;
    DWORD dwColor;
    BYTE ColorArray[4];
}Color;
  
It did come in pretty handy, but there''s one little nagging thing. Accessing the components means I have to go thru the struct, i.e. SomeColor.argb.a = //something Is there anyway to remove the struct from it or somehow make it invisible? I don''t want a, r, g, and b to occupy the same memspace; they should be a struct. I want to do something like omeColor.g which is a little shorter and cleaner. Is there anyway to do this?

Share this post


Link to post
Share on other sites
Advertisement
1. While DWORD and BYTE[4] map to each other nicely, a struct of four floats does not match the others. Are you sure that''s what you want?

2. Nested structs and unions and unions can be anonymous in which case their members appear in the enclosing namespace. i.e. just leave the "argb" off your your struct and you can do "SomeColor.g".

3. Another way to do it is to use a macro. i.e. "#define color_g argb.g" and then "SomeColor.color_g". Sockets code does this sort of thing a lot.

-Mike

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by Promit
Is there anyway to remove the struct from it or somehow make it invisible? I don''t want a, r, g, and b to occupy the same memspace; they should be a struct. I want to do something like omeColor.g which is a little shorter and cleaner. Is there anyway to do this?

Yes, there is! (at least in C++)

  
union Color {
struct {
float a, r, g, b;
}; // use an unnamed struct!

DWORD dwColor;
BYTE ColorArray[4];
};


Example usage:

  
void func()
{
Color color;
color.a = 1.0f; // ok!

color.dwColor = 0x00F00F00; // also ok!

}


Do keep in mind what Anon Mike said - Changing ColorArray[4] won''t change "b" - it will change the last byte of "a"...(because each of the floats is 4 bytes, and the sum total of ColorArray is 4 bytes...)

Cheers...

Share this post


Link to post
Share on other sites
quote:
Fruny
The ability to use the members of an unnamed nested union is standard.
It is not so for unnamed nested structs.
The Standard mandates that you would not be able to access the struct.



That's kinda lame... we should submit it as a defect for correction in C++0x.


[edited by - Magmai Kai Holmlor on June 28, 2002 8:54:09 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by Fruny
The ability to use the members of an unnamed nested union is standard.
It is not so for unnamed nested structs.
The Standard mandates that you would not be able to access the struct.

Hypocrites.

(it does work in everyone''s favorite not-so-standard C++ compiler, though. (MSVC) )


Share this post


Link to post
Share on other sites
quote:
Original post by Promit
struct { float a, r, g, b; }argb;


Yeah, shouldn''t this be

struct { unsigned char b, g, r, a; }argb;

? Remember, LSB is stored first.

Share this post


Link to post
Share on other sites
quote:
Original post by Anon Mike
1. While DWORD and BYTE[4] map to each other nicely, a struct of four floats does not match the others. Are you sure that''s what you want?



Oops. I wrote the above union/struct off the top of my head and I wasn''t really thinking about it. You''re right, they should be unsigned char, not float.

Lastly, this structure is built for Direct3D. The correct color storage order is ARGB. RGBA would be if I was working in OpenGL, and I don''t know when you might use BGRA.

Hell, as long as MSVC supports it. I never intend to use anything other than MSVC under Win32 anyway. If I was using OpenGL I might care...

____________________________________________________________
Direct3D vs. OpenGL

Share this post


Link to post
Share on other sites
Note to get the correct r,g,b,a components you should have them in the following order

struct SOMECOLOUR
{
union
{
struct{u32 ARGB;}; // directx ARGB
struct{u8 b,g,r,a;}; // correct order for intel endian
};
};

[as indirectX mentioned ;]

[edited by - mark duffill on July 1, 2002 10:34:06 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
yes, it is dependant on endianess (as I found out the hard way as a newb). On x86 (windows) the order should be: b,g,r,a. Also remember that you can overload operators, so you might want to overload the array access and multiplication operators.

Share this post


Link to post
Share on other sites
quote:
Original edit by MKH
That's kinda lame... we should submit it as a defect for correction in C++0x.



NOTE: disabling extensions in VC7 throws an error C2467: illegal declaration of anonymous 'struct'... So much for that code.

There have been talks (and at least one formal request, IIRC), to extend using-declarations to enable delegation (which is more or less what they're trying to do here), forwarding the declaration to the 'outer' interface.

IIRC, one argument (for functions at least) is that forwarding functions are 'perfectly adequate' and there is no need to support delegation.

Under that syntax, you would do :
WARNING, THIS IS NOT C++ (YET ?)  
union
{
struct { char a,b,c,d; } foo;
using foo { char a,b,c,d; }; // Or maybe as 4 declarations ?

float d;
} u;


Link to the relevant proposal.

Documents [ GDNet | MSDN | STL | OpenGL | Formats | RTFM | Asking Smart Questions ]
C++ Stuff [ MinGW | Loki | SDL | Boost. | STLport | FLTK | ACCU Recommended Books ]


[edited by - Fruny on July 1, 2002 3:05:44 PM]

Share this post


Link to post
Share on other sites
No, the struct and array should have floats, and the DWORD member should be gone. You see, using anything but floats for color components is stupid and shortsighted; very soon, floating-point frame buffers will be the norm and your app should not still be limited to 256 shades per channel. Besides, it''s more convenient to do calculations with a 0.0 to 1.0 float than a 0 to 255 byte.

Share this post


Link to post
Share on other sites
He missed the point, but he''s quite right.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
program for the now! I mean if he was programming a commericial game he might want to think about these things, but seriously.. his game is only every going to be played on his comp, maybe his friend''s too. Using a byte per channel is quite simply how things are done right now. Plus he''ll end up with a bunch of other problems, since he has to convert to bytes anyway to actually call any API stuff. Distracting newbies with purely theoretical concerns doesn''t help them. I know it messed me up.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
union{
struct {char r,g,b,a;};
struct {char a,b,g,r;};
};

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
union{
struct {char r,g,b,a;};
struct {char a,b,g,r;};
};



That won''t work, even assuming the compiler supports the anonymous structs inside the union. you''ve simply declared the same 4 elements in different order-you''ll get identifier redefinition.

Second, I just want to say that this is not cross-platform code. It''s just occasionally handy to reference the color in different ways. The order is ARGB and will stay that way. It''s for Win32, DirectX, x86 architecture targets, and nothing more.

And to merlin: Somehow, I don''t think floating point per channel frame buffers will be the norm. 1 Byte per channel provides 24 bits + alpha channel, or around 16.7 million colors. I don''t think it''s worth quadrupling the mem usage to simply make a cleaner memory representation. The visual gain will be nothing.

Share this post


Link to post
Share on other sites
I was making another point, really; I didn''t simply miss the original one.

If you were to stick your head out the window and smell the wind, you''d notice that Matrox just released a card support 10 bits per channel. Rumor has it that DirectX 9 will require 128-bit component support for full compliance. Other rumor indicates that the 2 biggest consumer graphics card manufacturers are busily working on compliant GPUs. High-end workstations have had this sort of thing for years, and it seems that PCs will too in the not-so-distant future. Certainly, an increase in internal percision is important when you do fancy blending operations. Whether or not the colors will stay at x-bit remains to be seen (though, eventually, there will be no difference). For instance, internally the N64 handles everything at 32-bit but renders at 21-bit. Go figure. Anyway, for everyone who will quote to me the scores of papers saying that 16.8 million colors is more than enough for the human eye, I have one word: bullshit. Try the gradient test. In these days of high resolutions, 1024 pixels horizontally is the lowest common demoninator, so to speak. Now, try drawing a gradient of two dissimilar colors (or maybe just try black to white, black to red, etc.) across that width. What happens? Well, we get banding. What does that mean? Not enough colors.

Share this post


Link to post
Share on other sites
Or it could mean your monitor''s gamma sux0rs. 3 bits of color is all anyone ever needed.

(ducks)

Share this post


Link to post
Share on other sites
No, just the dim half of the EGA colors (3-bits = 8). The bright colors were obnoxious.

I remember how ecstatic I was when I got my first EGA card and got to see King''s Quest in 4-bit color instead of monochrome.

Share this post


Link to post
Share on other sites

  • Advertisement