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

Everything else in the preceding 8-bit example would stay the same. DirectDraw isn’t that bad, huh?

To see the blitter hardware in action, I’ve created a little psychedelic demo for you called `DEMO7_6.CPP|EXE`. It puts the system into 640×480×16-bit mode and then fills different regions of the screen with random color. You’ll see about a zillion colored rectangles per second getting blitted to the screen (try turning the lights off and tripping out on it). Take a look at the `Game_Main()`; it’s almost trivial:

    int Game_Main(void *parms = NULL, int num_parms = 0)

    {

    // this is the main loop of the game, do all your processing

    // here

    DDBLTFX ddbltfx; // the blitter fx structure

    RECT dest_rect;  // used to hold the destination RECT

    // make sure this isn’t executed again

    if (window_closed)

       return(0);

    // for now test if user is hitting ESC and send WM_CLOSE

    if (KEYDOWN(VK_ESCAPE))

       {

       PostMessage(main_window_handle,WM_CLOSE,0,0);

       window_closed = 1;

       } // end if

    // first initialize the DDBLTFX structure

    DDRAW_INIT_STRUCT(ddbltfx);

    // now set the color word info to the color we desire

    // in this case, we are assuming an 8-bit mode, hence,

    // we'll use a color index from 0-255, but if this was a

    // 16/24/32 bit example then we would fill the WORD with

    // the RGB encoding for the pixel - remember!

    ddbltfx.dwFillColor = _RGB16BIT565(rand()%256, rand()%256, rand()%256);

    // get a random rectangle

    int x1 = rand()%SCREEN_WIDTH;

    int y1 = rand()%SCREEN_HEIGHT;

    int x2 = rand()%SCREEN_WIDTH;

    int y2 = rand()%SCREEN_HEIGHT;

    // now set up the RECT structure to fill the region from

    // (x1,y1) to (x2,y2) on the destination surface

    dest_rect.left   = x1;

    dest_rect.top    = y1;

    dest_rect.right  = x2;

    dest_rect.bottom = y2;

    // make the blitter call

    if (FAILED(lpddsprimary->Blt(&dest_rect, // pointer to dest RECT

                             NULL, // pointer to source surface

                             NULL, // pointer to source RECT

                             DDBLT_COLORFILL | DDBLT_WAIT,

                             // do a color fill and wait if you have to

                             &ddbltfx))) // pointer to DDBLTFX holding info

       return(0);

    // return success or failure or your own return code here

    return(1);

    } // end Game_Main

Now that you know how to use the blitter to fill, let me show you how to use it to copy data from surface to surface. This is where the real power of the blitter comes into play. It’s the foundation for the sprite or blitter object engine that you’re going to make in a little while.

#### Copying Bitmaps from Surface to Surface

The whole point of the blitter is to copy rectangular bitmaps from some source memory to destination memory. This may involve copying the entire screen, or small bitmaps that represent game objects. In either case, you need to learn how to instruct the blitter to copy data from one surface to another. Actually, you already know how to do this and may not realize it. The blitter fill demo will do the job with a couple of changes.

When you’re using the `Blt()` function, you basically send a source `RECT` and surface and a destination `RECT` and surface to perform the blit. The blitter will then copy the pixels from the source `RECT` to the destination `RECT`. The source and destination surface can be the same (surface to surface copy or move), but they’re usually different. In general, the latter is the basis for most sprite engines. (A sprite is a bitmap game image that moves around the screen.)

At this point you know how to create a primary surface and secondary surface that serves as a back buffer, but you don’t know how to create plain offscreen surfaces that aren’t related to the primary surface. You can’t blit them if you can’t make them. Thus, I’m going to hold off on showing you the general blitting case of any surface to the primary surface until I’ve shown you how to blit from the back buffer to the primary surface. Then the transition from generic surface to primary or back buffer will be trivial.

All you need to do to make a blit from any two surfaces (the back buffer to the primary surface, for example) is set the `RECT`s up correctly and make a call to `Blt()` with the right parameterization. Take a look at Figure 7.15. Imagine that you want to copy the `RECT` defined by (x1,y1) to (x2,y2) on the source surface (the back buffer in this case) to (x3,y3) to (x4,y4) on the destination surface (the primary surface in this case). Here’s the code:

    RECT source_rect, // used to hold source RECT

         dest_rect;   // used to hold the destination RECT

    // set up the RECT structure to fill the region from

    // (x1,y1) to (x2,y2) on the destination surface

    source_rect.left   = x1;

    source_rect.top    = y1;

    source_rect.right  = x2;

    source_rect.bottom = y2;

    // now set up the RECT structure to fill the region from

    // (x3,y3) to (x4,y4) on the destination surface

    dest_rect.left     = x3;

    dest_rect.top      = y3;

    dest_rect.right    = x4;

    dest_rect.bottom   = y4;

    // make the blitter call

    lpddsprimary->Blt(&dest_rect, // pointer to dest RECT

                    lpddsback,    // pointer to source surface

                    &source_rect, // pointer to source RECT

                    DDBLT_WAIT,   // control flags

                    NULL); // pointer to DDBLTFX holding info

That was easy, huh? Of course, there are still a few details I’m leaving out, such as clipping and transparency. I’ll talk about clipping first. Take a look at Figure 7.16, which depicts a bitmap that’s drawn to a surface with and without clipping. Blitting without clipping is obviously a problem if the bitmap extends past the rectangle of the destination surface. Memory may be overwritten and so forth, so DirectDraw supports clipping via the `IDirectDrawClipper` interface. Or, if you wrote your own bitmap rasterizer, as you did in the example `Blit8x8()`, you could always add clipping code. That will slow things down, however. The second issue pertaining to blitting is transparency.

Figure 7.16 The basic bitmap clipping problem.

When you draw a bitmap, the image is always within a rectangular matrix of pixels. However, you don’t want all those pixels copied when you blit. In many cases, you select a color, such as black, blue, green, or whatever, to serve as a transparent color that isn’t copied (you saw this implemented in `Blit8x8()`). DirectDraw also has support for this called color keys, which I will also talk about shortly.

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.