#### Archived

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

# Why does this work?

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

## Recommended Posts

Here''s a macro from a book that I''m reading that is supposed to convert three int s (one for red, one for green, and one for blue) into a 16-bit word used to represent a color. I''m sure you''ve all seen this before. #define _RGB16BIT555(r,g,b) ((b%32) + ((g%32) << 5) + ((r%32) << 10)) I don''t understand why this should work. I mean, consider the following: _RGB16BIT555(0,0,33); and... _RGB16BIT555(0,0,65) Both 33%32 and 65%32 = 1. Wouldn''t this yield the same shade of blue, even though the user obviously wanted two different shades? I''m sure the answer to this is obvious and I''m just overloading something. ---signature--- People get ready. I''m ready to play.

##### Share on other sites
Each color component gets 5 bits. You''re example uses numbers that break that 5 bit boundry. You only get 32 shades of each component. (2^5=32)

##### Share on other sites
Thats from Tricks of the Windows game programming gurus!

and yes the maximum value you get on 5 bits is 11111b = 0x1F = 31
on the _RGB16BIT565 macro green gets one more bit so its maximum is 111111b = 0x3f = 63

##### Share on other sites
Yep! I knew someone had to have seen that before.

Anyway, I understand why each number is %32-ed. But I was under the understanding that this sort of macro should be used to convert the standard 256-levels into 32 levels in a logical manner, meaning a value of 32 would be less than 64, which would be less than 96. Using this macro, these would all yield the same exact shade.

Let me put it another way. Using graphics programs like Photoshop, we are all used to representing colors as such:

white = 255,255,255
green = 000,255,000

dark green = 000,064,000
darker green = 000,032,00

You see, the last two examples should yield 2 different shades of green. Using that macro, it wouldn't. If I did the following:

_RGB16BIT555(0,0,32);

I would expect a darker shade of blue than this:

_RGB16BIT(0,0,64);

And this would be the lightest shade of blue possible:

_RGB16BIT555(0,0,255);

And I'd be right about one thing -- the last one would equal the lightest shade possible because 255%32=31, which is the highest you can go on a 32-element scale of 0-31. However, this doesn't work the way it was intended when other values are entered. Why bother with the (%)? Why not just force the user to enter in a value between 0-31? It'd be easier to understand.

I mean, it's be easiest to enter a value between 0-255 because that's what we're all used to, but if the macro doesn't work for this purpose then what's the point? Shouldn't it be written like this?

#define _RGB16BIT555(r,g,b) ((((b+1)/8)-1) + ((((g+1)/8)-1) << 5) + ((((r+1)/8)-1) << 10))

Each color would be given a value between 0 and 31 (255+1=256; 256/8 = 32; 32-1=31; ). Most of this math can be done before the macro is called, and I can even write some simple comparative logic that decided if the value entered is closer to one multiple of 32 or the other.

ARRGH! I don't get it.

---signature---

Edited by - utwo007 on January 29, 2002 9:33:11 PM

##### Share on other sites
Isn''t ''%'' horribly slow, since it needs an idiv ? better do something like b&31. Though it will wrap around instead.

##### Share on other sites
maybe you can change it to:

#define _RGB16BIT555(r,g,b) (((b&0x1f)) + ((g&0x1f) << 5) + ((r&0x1f) << 10))

that way you just feed 0-31 values, and if you feed higher values the bits over 5 wont be taken into account

Edit: got green (g) twice, and no blue (b)

Edited by - kwizatz on January 29, 2002 10:33:31 PM

##### Share on other sites
Well, I can do it this way:

the color is 255,128,0 (orange).

// Macro for creating color USHORT

#define _RGB16555(r,g,b) ((b)+(g << 5)+(r << 10))

// This function assumes the user has already locked the
// surface, obtained a pointer to the video buffer, calculated
// the memory pitch, and passed all this information to it.

int red = 255;
int green = 128;
int blue = 255;

int newred = ((red+1) >> 3) - 1;
int newgreen = ((green+1) >> 3) - 1;
int newblue = ((blue+1) >> 3) - 1;

256/8 = 32. Perfect! Because we''re dealing with 0-255 and not 1-256, we must first add 1 to the color element''s value. Then, we can devide by 8 easily by shifting the number three digits. ( >> 3 will effectively devide by 2^3, or 8). Then, we subtract the 1 back from the result.

Let''s see how this''ll work for our example (orange). We need a red value of 255, the highest allowable. Let''s transulate that to 16-bit color, shall we?

255+1=256
256/8=32
32-1=31

Woohoo! Now lets try 128 for the green element:

128+1=129
129/8=16 //since it''s an int, the remainder is truncated
16-1=15

Damned good!

And blue''s a no-brainer, so we''ll just go ahead and run the macro. Now newred is 31, newgreen is 15, and newblue is 0:

SomePixel = _RGB16555(newred,newgreen,newblue);

Pretty cool, huh? Now I can use the standard 255,255,255 design and convert it to 16bit color information using NO devides, NO modulus, and NO multiplies! I guess I could just get used to a 31,31,31 way of thinking, but I''m too stubborn!

What do you think? It isn''t perfect. Since the result of int >> 3 is truncated, it''s always rounded down. That''s no good, because in reality, the number 128, when converted from 8-bit format to 5-bit format, is actually closer 16 than 15. I could use some simple comparative logic to decide whether a number is closer to one multiple of 8 or another. I dunno.

---signature---

##### Share on other sites
Whoever wrote that macro is horribly misguided; they're trying to implement either a clamp or a scale function using modulo arithmetic, either of which just doesn't work. If you need to clamp the color values to the range 0-32 with no wraparound, you can just use the bitwise and operator, as pointed out earlier.

To really convert between color depths you need to rescale the RGB values to the range 0-32 rather than simply clamping them. Let's say their range is 0-255 (8 bits per color component). Assuming unsigned values for r, g, b, a working implementation of the macro might look like this (it isn't optimal, but it's good enough unless you're doing some serious format conversions every single frame):

#define SCALE( val, maxNew ) (int)((float)(val) / 256.0f * (maxNew))
#define _RGB16BIT555(r,g,b) (SCALE( b, 32 ) | (SCALE( g, 32 ) << 5) | (SCALE( r, 32 ) << 10))

Note this also fixes another problem with the original: the parameters within a macro definition must be parenthesized in order to ensure you get intended results in all cases.

If this macro actually was from a Tricks of the [etc..] Gurus book, I'm not surprised. I was very disappointed with the quality of code in both those books.

--
Eric

Edited by - ekenslow on January 30, 2002 1:40:40 AM

##### Share on other sites
utwo007, why don't you just leave the number alone before you divide by 8? Why add one and then subtract one? If you left it, then

255 >> 3

should yield 31 (since its below 256, it'd be rounded down), and

128 >> 3

would yield the more accurate 16.

Just a thought.

[EDIT]
I just thought of another problem with what you proposed. What happens when you choose the color 0, or 1?

1+1=2
2/8=0 (an int gets truncated)
0-1=-1

-1 is not a valid color I'm afraid. My slightly revised way should take care of this.
[/EDIT]

--Buzzy

Edited by - buzzy_b on January 30, 2002 2:04:41 AM

##### Share on other sites
I''m reading the same book. The macro works...but I have no idea what''s happening. Im not to good with the whole macro and bit operation thing. Does anyone know of a good tutorial to help me out?

1. 1
2. 2
Rutin
21
3. 3
JoeJ
18
4. 4
gaxio
12
5. 5

• 14
• 40
• 23
• 13
• 13
• ### Forum Statistics

• Total Topics
631724
• Total Posts
3001896
×