Basic TransparencyOverlaying a transparent image on an opaque one is not something you can use a lookup table for, because it would have to have 65,536 entries in both dimensions. It's going to be awhile before the average computer has the 8.6 GB of RAM it takes to hold that monster. :) So you'll have to do all the calculations for each pixel. I'll give you the basic idea. Suppose you want to place image A on top of image B, and image A is to have a transparency percentage of pct, which is a floating-point number between 0 and 1, where 0 is fully transparent (invisible) and 1 is fully opaque. Then, let's call a pixel in image A pixelA, and its counterpart in image B we'll call pixelB. You would apply the following equation: color = (pixelA * pct) + (pixelB * (1-pct)); Basically, this is just a weighted average of the two pixel colors. By multiplying the colors, I mean to multiply the intensities for red, green, and blue. So you're actually looking at six floating-point multiplications per pixel. You can use some small lookup tables to lighten the workload a little. Experiment with it! The other thing you might want to do is to create a window of a solid color that's partially transparent. If you've seen a demo or screenshots of my upcoming RPG, Terran, you know what I mean. An effect like that can be done entirely with a lookup table, because in Terran's case, I just needed to provide a 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 b = (UCHAR)(x & 0x001F); // green 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 here. You might try modifying it so that it fills the screen with pixels, then plots a transparent box over the top of them. ClosingThat 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! Copyright © 2000 by Joseph D. Farrell. All rights reserved. |