Tricks of the Windows Game Programming Gurus:Advanced DirectDraw and Bitmapped Graphics

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 fields that matter the most right now are

`DDPF_PALETTEINDEXED8`—This indicates that the surface is an 8-bit palettized mode.

`DDPF_RGB`—This indicates that the surface is an RGB mode and the format can be queried by testing the value in `dwRGBBitCount`.

So all you need to do is write a test that looks something like this:

    DDPIXELFORMAT ddpixel; // used to hold info

    LPDIRECTDRAWSURFACE4 lpdds_primary; // assume this is valid

    // clear our structure

    memset(&ddpixel, 0, sizeof(ddpixel));

    // set length

    ddpixel.dwSize = sizeof(ddpixel);

    // make call off surface (assume primary this time)

    lpdds_primary->GetPixelFormat(&ddpixel);

    // now perform tests

    // check if this is an RGB mode or palettized

    if (ddpixel.dwFlags & DDPF_RGB)

        {

        // RGB mode

        // what's the RGB mode

        switch(ddpixel.dwRGBBitCount)

              {

              case 15: // must be 5.5.5 mode

                   {

                   // use the _RGB16BIT555(r,g,b) macro

                   } break;

              case 16: // must be 5.6.5 mode

                   {

                   // use the _RGB16BIT565(r,g,b) macro

                   } break;

              case 24: // must be 8.8.8 mode

                   {

                   } break;

              case 32: // must be alpha(8).8.8.8 mode

                   {

                   } break;

              default: break;

              } // end switch

        } // end if

    else

    if (ddpixel.dwFlags & DDPF_PALETTEINDEXED8)

        {

        // 256 color palettized mode

        } // end if

    else

        {

        // something else??? more tests

        } // end else

Fairly simple code, huh? A bit ugly, but that comes with the territory, baby! The real power of `GetPixelFormat()` comes into play when you don’t set the video mode and you simply create a primary surface in a windowed mode. In that case, you’ll have no idea about the properties of the video system and you must query the system.

Otherwise, you won’t know the color depth, pixel format, or even the resolution of the system.

Now that you’re a 16-bit expert, here’s a demo! There’s nothing to creating a 16-bit application—just make the call to `SetDisplayMode()` with 16 bits for the color depth, and that’s it. As an example, here are the steps you would take to create a full-screen, 16-bit color mode in DirectDraw:

    LPDIRECTDRAW   lpdd_temp = NULL; // used to get directdraw1

    LPDIRECTDRAW4  lpdd      = NULL; // used to get directdraw4

    DDSURFACEDESC2 ddsd;             // surface description

    LPDIRECTDRAWSURFACE4 lpddsprimary = NULL; // primary surface

    // create IDirectDrawdirectdraw interface 1.0 object and test for error

    if (FAILED(DirectDrawCreate(NULL,&lpdd_temp,NULL)))

       return(0);

    // now query for IDirectDraw4

    if (FAILED(lpdd_temp->QueryInterface(IID_IDirectDraw4,

                                   (LPVOID *)&lpdd)))

       return(0);

    // set cooperation level to requested mode

    if (FAILED(lpdd->SetCooperativeLevel(main_window_handle,

               DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN |

               DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)))

        return(0);

    // set the display mode to 16 bit color mode

    if (FAILED(lpdd->SetDisplayMode(640,480,16,0,0)))

       return(0);

    // Create the primary surface

    memset(&ddsd,0,sizeof(ddsd));

    ddsd.dwSize = sizeof(ddsd);

    ddsd.dwFlags = DDSD_CAPS;

    // set caps for primary surface

    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

    // create the primary surface

    lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL);

And that’s all there is to it. At this point, you would see a black screen (possibly garbage if the primary buffer memory has data in it).

To simplify the discussion, assume that you already tested the pixel format and found that it’s RGB 16-bit 5.6.5 mode—which is correct, because you set the mode! In the worst-case scenario, however, it could have been the 5.5.5 format. Anyway, to write a pixel to the screen, you must

  1. Lock the surface. In this example, that means locking the primary surface with a call to `Lock()`.
  2. Build the RGB `WORD` for 16-bit mode. This entails using one of the macros or doing it yourself. Basically, you’re going to send the pixel-plotting function red, green, and blue values. They must be scaled and then combined into the 16-bit 5.6.5 format that the primary surface needs.
  3. Write the pixel. This means addressing the primary buffer using a `USHORT` pointer and writing the pixel into the VRAM buffer.
  4. Unlock the primary surface. A call to `Unlock()` is made.

Here’s the code for a rough 16-bit plot pixel function:

    void Plot_Pixel16(int x, int y, int red, int green, int blue,

                      LPDIRECTDRAWSURFACE4 lpdds)

    {

    // this function plots a pixel in 16-bit color mode

    // very inefficient…

    DDSURFACEDESC2 ddsd; // directdraw surface description

    // first build up color WORD

    USHORT pixel = _RGB16BIT565(red,green,blue);

    // now lock video buffer

    DDRAW_INIT_STRUCT(ddsd);

    lpdds->Lock(NULL,&ddsd,DDLOCK_WAIT |

                DDLOCK_SURFACEMEMORYPTR,NULL);

    // write the pixel

    // alias the surface memory pointer to a USHORT ptr

    USHORT *video_buffer = ddsd.lpSurface;

    // write the data

    video_buffer[x + y*(ddsd.lPitch >> 1)] = pixel;

    // unlock the surface

    lpdds->Unlock(NULL);

    } // end Plot_Pixel16

Notice the use of `DDRAW_INIT_STRUCT(ddsd)`, which is a simple macro that zeros out the structure and sets its `dwSize` field. I’m getting tired of doing it the long way. Here’s the macro definition:

    // this macro should be on one line

    #define DDRAW_INIT_STRUCT(ddstruct)

    { memset(&ddstruct,0,sizeof(ddstruct));

      ddstruct.dwSize=sizeof(ddstruct); };

For example, to plot a pixel on the primary surface at (10,30) with RGB values (255,0,0), you would do something like this:

    Plot_Pixel16(10,30,   // x,y

                 255,0,0, // rgb

                 lpddsprimary); // surface to draw on

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.