Tricks of the Windows Game Programming Gurus:First Contact: DirectDraw

All ITKnowledge Source Code Search Tips Advanced Search |

| Tricks of the Windows Game Programming Gurus by Andre LaMothe Sams, Macmillan Computer Publishing ISBN: 0672313618 Pub Date: 09/27/99

Search this book:

Previous | Table of Contents | Next

### The Subtleties of Color

DirectDraw supports a number of different color depths, including 1, 2, 4, 8, 16, 24, and 32 bpp. Obviously, 1, 2, and 4 bits per pixel are a little outdated, so don’t concern yourself with these color depths. On the other hand, the 8-, 16-, 24-, and 32-bit modes are of utmost interest. Most games you write, you’ll write to run in either 8-bit palettized mode for speed reasons, or 16- or 24-bit mode for full RGB color utilization. The RGB modes work by writing similar-sized `WORD`s into the frame buffer, as shown in Figure 6.6. The palletized mode works by using a look-up table that is indexed by each individual pixel value in the frame buffer, which is always a single byte. Thus, there are 256 different values—you have seen all this before, so it should look familiar.

Figure 6.6 Comparison of various color depths.

What you need to learn to do is create a 256-color palette and then tell DirectDraw that you want to use it. So let’s see the steps involved:

  1. Create one or more palette data structures as arrays of 256 `PALETTENTRY`’s.
  2. Create a DirectDraw palette interface `IDirectDrawPalette` object from the DirectDraw object itself. In many cases, this will be directly mapped to the hardware VGA palette registers.
  3. Attach the palette object to a drawing surface, such as the primary surface, so all data rendered to it is displayed in the appropriate colors.
  4. (Optional) If you desire, you can change the palette entries or the entire palette. You will need to take this step if you sent a `NULL` palette during step 2 and opted to omit step 1. Basically, what I’m trying to say is that when you create a palette interface, you can send it a palette of color also. But if you don’t, you can always do it later. Therefore, step 2 can be step 1 if you remember to fill up the palette entries at a later time.

Let’s begin by creating the palette data structure. It’s nothing more than an array of 256 palette entries based on the `PALETTENTRY` Win32 structure, shown here:

    typedef struct tagPALETTEENTRY

            {

            BYTE peRed;     // red component 8-bits

            BYTE peGreen;   // green component 8-bits

            BYTE peBlue;    // blue component 8-bits

            BYTE peFlags;   // control flags: set to PC_NOCOLLAPSE

            } PALETTEENTRY;

Look familiar? It better! Anyway, to create a palette, you simply create an array of these structures, like this:

    PALETTEENTRY palette[256];

And then you fill them up in any way you desire. However, there is one rule: You must set the `peFlags` field to `PC_NOCOLLAPSE`. This is necessary because you don’t want Win32/DirectX optimizing your palette for you. With that in mind, here’s an example of creating a random palette with black in position 0 and white in position 255:

    PALETTEENTRY palette[256]; // palette storage

    // fill em up with color!

    for (int color=1; color < 255; color++)

        {

        // fill with random RGB values

        palette[color].peRed   = rand()%256;

        palette[color].peGreen = rand()%256;

        palette[color].peBlue  = rand()%256;

        // set flags field to PC_NOCOLLAPSE

        palette[color].peFlags = PC_NOCOLLAPSE;

        } // end for color

    // now fill in entry 0 and 255 with black and white

    palette[0].peRed   = 0;

    palette[0].peGreen = 0;

    palette[0].peBlue  = 0;

    palette[0].peFlags = PC_NOCOLLAPSE;

    palette[255].peRed   = 255;

    palette[255].peGreen = 255;

    palette[255].peBlue  = 255;

    palette[255].peFlags = PC_NOCOLLAPSE;

That’s all there is to it! Of course, you can create multiple palettes and fill them with whatever you want; it’s up to you.

Moving on, the next step is to create the actual `IDirectDrawPalette` interface. Luckily for you, the interface hasn’t changed as of DirectX 6.0, so you don’t need to use `QueryInterface()` or anything. Here’s the prototype for `IDirectDraw4:: CreatePalette()`, which creates a palette object:

    HRESULT CreatePalette(DWORD dwFlags,   // control flags

    LPPALETTEENTRY lpDDColorArray,  // palette data or NULL

    LPDIRECTDRAWPALETTE FAR *lplpDDPalette,  // received palette interface

           IUnknown FAR *pUnkOuter);   // advanced, make NULL

The function returns `DD_OK` if successful.

Let’s take a look at the parameters. The first parameter is `dwFlags,` which controls the various properties of the palette—more on this in a minute. The next parameter is a pointer to the initial palette, or `NULL` if you don’t want to send one. Next you have the actual `IDirectDrawPalette` interface storage pointer that receives the interface if the function is successful. Finally, `pUnkOuter` is for advanced COM stuff, so simply send `NULL`.

Previous | Table of Contents | Next

Copyright © Macmillan Computer Publishing, Inc.

Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.