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

In most cases, `lpddsurface` would be your offscreen rendering surface, such as the back buffer surface. Usually, you don’t attach a clipper to the primary surface.

Okay, I know you’re probably turning purple with frustration because I’ve hedged about the details of creating the `RGNDATA` structure and setting it up. The reason is that it’s too hard to explain detail by detail; it’s easier to just look at the code. Hence, I’ve created a function called `DDraw_Attach_Clipper()` (part of the graphics library) that creates a clipper and a clip list, and attaches them to any surface. Here’s the code:

    LPDIRECTDRAWCLIPPER DDraw_Attach_Clipper(LPDIRECTDRAWSURFACE4 lpdds,

                                             int num_rects,

                                             LPRECT clip_list)

    {

    // this function creates a clipper from the sent clip list and attaches

    // it to the sent surface

    int index;                         // looping var

    LPDIRECTDRAWCLIPPER lpddclipper;   // pointer to the newly

                                       // created dd clipper

    LPRGNDATA region_data;             // pointer to the region

                                       // data that contains

                                       // the header and clip list

    // first create the direct draw clipper

    if (FAILED(lpdd->CreateClipper(0,&lpddclipper,NULL)))

       return(NULL);

    // now create the clip list from the sent data

    // first allocate memory for region data

    region_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+

                   num_rects*sizeof(RECT));

    // now copy the rects into region data

    memcpy(region_data->Buffer, clip_list, sizeof(RECT)*num_rects);

    // set up fields of header

    region_data->rdh.dwSize          = sizeof(RGNDATAHEADER);

    region_data->rdh.iType           = RDH_RECTANGLES;

    region_data->rdh.nCount          = num_rects;

    region_data->rdh.nRgnSize        = num_rects*sizeof(RECT);

    region_data->rdh.rcBound.left    =  64000;

    region_data->rdh.rcBound.top     =  64000;

    region_data->rdh.rcBound.right   = -64000;

    region_data->rdh.rcBound.bottom  = -64000;

    // find bounds of all clipping regions

    for (index=0; index<num_rects; index++)

        {

        // test if the next rectangle unioned with

        // the current bound is larger

        if (clip_list[index].left < region_data->rdh.rcBound.left)

           region_data->rdh.rcBound.left = clip_list[index].left;

        if (clip_list[index].right > region_data->rdh.rcBound.right)

           region_data->rdh.rcBound.right = clip_list[index].right;

        if (clip_list[index].top < region_data->rdh.rcBound.top)

           region_data->rdh.rcBound.top = clip_list[index].top;

        if (clip_list[index].bottom > region_data->rdh.rcBound.bottom)

           region_data->rdh.rcBound.bottom = clip_list[index].bottom;

        } // end for index

    // now we have computed the bounding rectangle region and set up the data

    // now let’s set the clipping list

    if (FAILED(lpddclipper->SetClipList(region_data, 0)))

       {

       // release memory and return error

       free(region_data);

       return(NULL);

       } // end if

    // now attach the clipper to the surface

    if (FAILED(lpdds->SetClipper(lpddclipper)))

       {

       // release memory and return error

       free(region_data);

       return(NULL);

       } // end if

    // all is well, so release memory and

    // send back the pointer to the new clipper

    free(region_data);

    return(lpddclipper);

    } // end DDraw_Attach_Clipper

The function is almost trivial to use. Let’s say you have an animation system with a primary surface called `lpddsprimary` and a secondary back buffer called `lpddsback`, to which you want to attach a clipper with the following `RECT` list:

    RECT rect_list[3] = {{10,10,50,50},

                         {100,100,200,200},

                         {300,300, 500, 450}};

    Here's the call to do it:

    LPDIRECTDRAWCLIPPER lpddclipper =

                         DDraw_Attach_Clipper(lpddsback,3,rect_list);

Cool, huh? If you made this call, only portions of bitmaps that were within the rectangles (10,10) to (50,50), (100,100) to (200,200), and (300,300) to (500, 450) would be visible. Also, just to let you know, this function is part of a library that I’m working on as I write this chapter. Later, I’m going to show you all the functions in it so you don’t have to write all this tedious DirectDraw code yourself and you can focus on game programming, my little spawn <BG>.

Anyway, based on the preceding code, I’ve created a demo called `DEMO7_9.CPP|EXE`. Basically, I took the blitter demo program `DEMO7_7.CPP`, converted it to 8-bit color, and added the clipper function so that only blits within the current clipping regions are displayed on the primary surface. Furthermore, to be consistent, the clipping regions are the same ones listed in the preceding paragraph. Figure 7.22 is a screen shot of the program in action. Notice that it looks like a bunch of little windows that the clipper allows bitmaps to be rendered to.

Figure 7.22 `DEMO7_9.EXE` in action.

Here’s the code that sets up the clipper in the `Game_Main()` of `DEMO7_9.CPP`:

    // now create and attach clipper

    RECT rect_list[3] = {{10,10,50,50},

                         {100,100,200,200},

                         {300,300, 500, 450}};

    if (FAILED(lpddclipper = DDraw_Attach_Clipper(lpddsprimary,3,rect_list)))

       return(0);

Coolio! At this point, I’m extremely bored with gradient fills and colored rectangles. If I don’t see some bitmaps, I’m going to lose my mind! Next I’ll show you how to load bitmaps with Windows.

### Working with Bitmaps

There are about a trillion different bitmap file formats, but I only use a few for game programming: `.PCX` (PC Paint), `.TGA` (Targa), and `.BMP` (Windows native format). They all have their pros and cons, but you’re using Windows, so you might as well use the native format `.BMP` to make life easier. (I’m already in DirectX API revision hell, so I’m a bit unstable at this point. If I see one more Don Lapre commercial, I think I’m going to go postal!)

The other formats all work in similar ways, so once you learn how to deal with one file format, figuring out another involves nothing more than getting hold of the header structure format and reading some bytes off the disk.

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.