Topic : Palettes and Pixels in DirectDraw
Author : Joseph Farrell
Page : << Previous 5
Go to page :

color of blue for every possible color on the screen. In fact, a lookup table is exactly how I do the effect. I'll show you exactly what I mean.

void Init_CLUT(void)
{
int x, y, bright;
UCHAR r, g, b;

// calculate textbox transparency CLUT
for (x=0; x<65536; x++)
{
// transform RGB data
if (color_depth == 15)
{
r = (UCHAR)((x & 0x7C00) >> 10);
g = (UCHAR)((x & 0x03E0) >> 5);
b = (UCHAR)(x & 0x001F);
}
else  // color_depth must be 16
{
r = (UCHAR)((x & 0xF800) >> 11);
g = (UCHAR)((x & 0x07E0) >> 6);   // shifting 6 bits instead of 5 to put green
b = (UCHAR)(x & 0x001F);          // on a 0-31 scale instead of 0-63
}

// find brightness as a weighted average
y = (int)r + (int)g + (int)b;
bright = (int)((float)r * ((float)r/(float)y) +
(float)g * ((float)g/(float)y) +
(float)b * ((float)b/(float)y) + .5f);

// write CLUT entry as 1 + one half of brightness
clut[x] = (USHORT)(1 + (bright>>1));
}
}

This is the code from Terran that creates the lookup table with which the text boxes are generated. There are typecasts everywhere just for safety, and it could be sped up quite a bit, but I didn't bother because it's only called once, in the very beginning of the game. First, the values for red, green, and blue are extracted. Since this is in 16-bit color, notice that I have a variable called color_depth that takes into account whether the pixel format is 565 or 555. Then, the brightness of the pixel is calculated using this formula:

y = r + g + b;
brightness = r*(r/y) + g*(g/y) + b*(b/y);

It's just another weighted average. I'm not sure if that's really how the brightness of a color is defined, but it seems logical and it produces a nice effect. Anyway, at the end of the equation I've added .5, because when you cast a float to an int, the decimal is truncated. Adding .5 turns that truncation into rounding. Finally, I divide the brightness in half and add one. The division is so the text boxes don't get too bright, and the one is so the box is never totally black. Since the low bits of a 16-bit color descriptor are for blue, I can just set the color by setting the value of blue, instead of having to use a macro. Make sense? Finally, before I wrap this up, I'll also show you how I create a text box:

int Text_Box(USHORT *ptr, int pitch, LPRECT box)
{
int x, y, jump;
RECT ibox;

// leave room for the border
SetRect(&ibox, box->left+3, box->top+3, box->right-3, box->bottom-3);

// update surface pointer and jump distance
ptr += (ibox.top * pitch + ibox.left);
jump = pitch - (ibox.right - ibox.left);

// use CLUT to apply transparency
for (y=ibox.top; y<ibox.bottom; y++)
{
for (x=ibox.left; x<ibox.right; x++, ptr++)
*ptr = clut[*ptr];
ptr += jump;
}
return(TRUE);
}

Now that it's just a lookup table, this looks a lot like the code for fading. The only difference is that the lookup table holds different values. And it's only one column instead of 20. :) The declaration for the lookup table, by the way, looks like this:

USHORT clut[65536];

With that, you should be able to produce some rather interesting effects. To get you started, check out the sample code that comes with this article. It's available on the Downloads section of this site. You might try modifying it so that it fills the screen with pixels, then plots a transparent box over the top of them.

Closing
That does it for pixel-based graphics. Next time around, we'll be working with bitmaps! Believe it or not, working with bitmaps is easier than all this pixel stuff. Seems a little backwards, doesn't it? You'll find out. In the meantime, send me any questions you might have and I'll be happy to help you out. My E-mail address is ironblayde@aeon-software.com, and my ICQ UIN is 53210499. Oh, one other thing... the next article will be the last one covering general DirectX techniques. After that, we'll get into specific applications that you can use for developing an RPG. More details to follow. :) Later!

Page : << Previous 5