Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
78 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Contents
 Loading Bitmaps
 Using the Blitter
 Color Keys
 IDirectDrawClipper
 Interface


 Get the source
 Printable version
 Discuss this article
 in the forums



The Series
 Beginning Windows
 Programming

 Using Resources
 in Win32 Programs

 Tracking Your
 Window/Using GDI

 Introduction
 to DirectX

 Palettes and Pixels
 in DirectDraw

 Bitmapped Graphics
 in DirectDraw

 Developing the
 Game Structure

 Basic Tile Engines
 Adding Characters
 Tips and Tricks

Color Keys

A color key is a method of blitting one image onto another whereby not all of the pixels are copied. For instance, let's say you have a character sprite you want to blit onto a background image. Chances are that your hero isn't shaped precisely like a rectangle (unless your game is a celebration of "modern art"), so copying the RECT that encloses him is going to produce some unwanted effects. Take a look at this example picture from Terran to see what I mean:

No Color Keying

Now this isn't really the way the game is drawn. In reality, the characters are blitted to the display before the background has finished being drawn, so that things like the tops of trees can obscure the player if he's standing behind them. But that's unimportant for our purposes here; we'll get to it in the next article. The important point is that without color keying, all of your non-rectangular images like this character would have boxes around them.

To solve this problem, we use a source color key. The source color key tells the blitter which colors not to copy. A color key consists of two values: a lower color value, and an upper color value. When the color key is applied to a blit, any colors lying between the two values, including the values themselves, are not copied. There's a structure in DirectX that goes along with this, called DDCOLORKEY. Take a look:

typedef struct _DDCOLORKEY{
  DWORD dwColorSpaceLowValue; 
  DWORD dwColorSpaceHighValue;
} DDCOLORKEY, FAR* LPDDCOLORKEY;

I just told you what the members are so there's no need to go over them further. Let me show you what the above blit would look like with a color key activated. In Terran, I use color keys with the low and high values both set to black. Thus, black is the only color that doesn't get copied. When this color key is applied to the blit, this is the result:

Source Color Keying

Much better, hey? That's the look we're going for! Now before I show you how to create and use a color key, I want to briefly mention destination color keys, although they're not often used. Whereas source color keys define which colors are not copied, destination color keys define which colors can't be written to. Sound weird? It is. :) Destination color keying would be used if you wanted to blit one image to a position where it looks like it's underneath another. Suppose that for some odd reason, you wanted to draw text boxes on your blank back buffer, and then copy the background image afterwards, but you still wanted the text boxes to appear on top of the map. What you could do is set a destination color key to include every color except black. Thus, the only areas on the back buffer that can be written to are those pixels which are currently black. Take a look at this illustration to see what I mean:

Destination Color Keying

Like I said, I'm not sure why you'd want to do that, but there it is. Maybe you can think up a good use for it. If you do, be sure to let me know. :) Now that you know what color keys are, let's see how you use them.

Setting Color Keys

There are two ways to use a color key in DirectDraw. First, you can attach one (or two, if you're using source and destination) to a surface, and then specify the DDBLT_KEYSRC, DDBLT_KEYDEST, DDBLTFAST_SRCCOLORKEY, or DDBLTFAST_DESTCOLORKEY flag when blitting, depending on which blit function and what type of color key you're using. Second, you can create a color key and pass it to the blit operation through the DDBLTFX structure. The first method is recommended if you're going to be using a color key over and over, whereas the second method is ideal if you only want to use a certain color key once.

You can either attach a color key to a surface that has been created, or you can create the color key at the same time you create the surface. I'll show you how to do both. Let's assume you're working in a 16-bit display mode, with a 565 pixel format, and you want a source color key on your back buffer that includes black only. If your back buffer has already been created, you simply create a DDCOLORKEY structure like we saw before, and pass it to IDirectDrawSurface7::SetColorKey(), shown below:

HRESULT SetColorKey(
  DWORD dwFlags,
  LPDDCOLORKEY lpDDColorKey
);

Remember to test the return value of this function with the FAILED() macro when you call it, to make sure everything happens the way you want it to. The parameters are straightforward:

DWORD dwFlags: One or more of a series of simple flags describing the color key. There are only three you'll use:

DDCKEY_COLORSPACESpecifies that the color key describes a range of colors, not just one.
DDCKEY_DESTBLTSpecifies that the color key should be used as a destination color key for blit operations.
DDCKEY_SRCBLTSpecifies that the color key should be used as a source color key for blit operations.

LPDDCOLORKEY lpDDColorKey: This is a pointer to the DDCOLORKEY structure you filled out.

And that's all there is to it. From that point on, you just specify the appropriate flag on blits which you want to use the color key. Note that just because a surface has a color key attached to it, doesn't mean you have to use it every time. If you specify blits with only the DDBLT_WAIT or DDBLTFAST_WAIT flag and nothing else, any color keys will be ignored. So here's how you'd set up the color key we described earlier:

DDCOLORKEY ckey;
ckey.dwColorSpaceLowValue = RGB_16BIT565(0, 0, 0);  // or we could just say '0'
ckey.dwColorSpaceHighValue = RGB_16BIT565(0, 0, 0);
if (FAILED(lpddsBack->SetColorKey(DDCKEY_SRCBLT, &ckey)))
{
  // error-handling code here
}

If you want to create a surface with the color key already specified, there are just a few things you have to do. First, when you're specifying the valid fields of the DDSURFACEDESC2 structure, you need to include DDSD_CKSRCBLT or DDSD_CKDESTBLT in the dwFlags member, depending on which type of color key you want to use. Looking back at the DDSURFACEDESC2 structure, it contains two DDCOLORKEY structures. One is called ddckCKSrcBlt, and the other is called ddckCKDestBlt. Fill out the appropriate structure, create the surface, and you're all set! Here's the example code for an offscreen surface that's 640x480 in size.

// set up surface description structure
INIT_DXSTRUCT(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CKSRCBLT;
ddsd.dwWidth = 640;                                          // width of the surface  
ddsd.dwHeight = 480;                                         // and its height
ddsd.ddckCKSrcBlt.dwColorSpaceLowValue  = RGB_16BIT(0,0,0);  // color key low value
ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = RGB_16BIT(0,0,0);  // color key high value
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;                // type of surface

// now create the surface
if (FAILED(lpdd7->CreateSurface(&ddsd, &lpddsBack, NULL)))
{
  // error-handling code here
}

That wraps up color keys, so now we can cover the final topic of this article, which is clipping.




Next : The IDirectDrawClipper Interface