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

#### Making a DirectDraw Clip with IDirectDrawClipper

Now that you see the work it takes to perform clipping via software, it’s time to look at how easy it is with DirectDraw. DirectDraw has an interface called `IDirectDrawClipper` that’s used for all 2D blitter clipping, as well as 3D rasterization under Direct3D. In essence, the buck stops here. Right now, however, you’re only interested in using the clipper to clip bitmaps that are blitted using the `Blt()` function and the associated blitter hardware.

To set up DirectDraw clipping, you must do the following:

  1. Create a DirectDraw clipper object.
  2. Create a clipping list.
  3. Send the clipping list data to the clipper with `IDIRECTDRAWCLIPPER::SetClipList()`.
  4. Attach the clipper to a window and/or surface with `IDIRECTDRAWSURFACE4::SetClipper()`.

I’ll begin with step 1. The function to create an `IDirectDrawClipper` interface is called `IDIRECTDRAW4::CreateClipper()` and is shown here:

    HRESULT CreateClipper(DWORD dwFlags, // control flags

            LPDIRECTDRAWCLIPPER FAR *lplpDDClipper, // address of interface

            pointer

            IUnknown FAR *pUnkOuter); // COM stuff

The function returns `DD_OK` if successful.

The parameters are pretty easy. `dwFlags` is currently unused and must be 0. `lplpDDClipper` is the address of a `IDirectDrawClipper` interface that will point to a valid DirectDraw clipper after the function succeeds. Finally, `pUnkOuter` is for COM aggregation, which is something you don’t care about—make it `NULL`. To create a clipper object, just enter this:

    LPDIRECTDRAWCLIPPER lpddclipper = NULL; // hold the clipper

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

        return(0);

If the function succeeds, `lpddclipper` will point to a valid `IDirectDrawClipper` interface and you can call the methods on it.

That’s great, but how do you create the clipping list, and what does it represent? Under DirectDraw, the clipping list is a list of rectangles stored in `RECT` structures that indicate the valid regions that can be blitted to, as shown in Figure 7.20. As you can see, there are a number of rectangles on the display surface, but DirectDraw’s blitter system can blit only within these rectangles. You can draw anywhere you want with `Lock()`/`Unlock()`, but the blitter hardware will be able to draw only within the clipping regions, more commonly called the clip list.

Figure 7.20 The relationship between the clip list and the blitter.

To create a clip list, you must fill in a rather ugly data structure called `RGNDATA` (Region Data), which is shown here:

    typedef struct _RGNDATA

            { /* rgnd */

            RGNDATAHEADER rdh; // header info

            char Buffer[1];    // the actual RECT list

            } RGNDATA;

This is a very odd data structure. Basically, it’s a variant size structure, which means that the `Buffer[]` part of it can be any length. The structure is generated dynamically rather than statically, and its true length is stored in the `RGNDATAHEADER`. What you’re seeing here is the old version of the new DirectX data structure technique that sets the `dwSize` field of every structure. Maybe a better approach would have been to make `Buffer[]` a pointer rather than storage for a single byte?

Whatever the thinking was, here’s the deal: All you have to do is allocate enough memory for a `RGNDATAHEADER` structure, along with memory to hold an array of one or more `RECT` structures that are contiguous in memory, as shown in Figure 7.21. Then you’ll just cast it to a `RGNDATA` type and pass it.

Figure 7.21 The memory footprint of the `RGNDATA` clipping structure

Anyway, look at what’s in the `RGNDATAHEADER` structure:

    typedef struct _RGNDATAHEADER

            { // rgndh

            DWORD dwSize;   // size of this header in bytes

            DWORD iType;    // type of region data

            DWORD nCount;   // number of RECT'S in Buffer[]

            DWORD nRgnSize; // size of Buffer[]

            RECT  rcBound;  // a bounding box around all RECTS

            } RGNDATAHEADER;

To set this structure up, set `dwSize` to the `sizeof(RGNDATAHEADER)`, set `iType` to `RDH_RECTANGLES`, set `nCount` to the number of rectangles or `RECTS` in your clipping list, set `nRgnSize` to the size in bytes of your `Buffer[]` (which is equal to `sizeof(RECT)*nCount)`, create a bounding box around all your `RECT`s, and store this box in `rcBound`. Once you’ve generated the `RGNDATA` structure, you send it to your clipper with a call to `IDIRECTDRAWCLIPPER::SetClipList()`, shown here:

    HRESULT SetClipList(LPRGNDATA lpClipList, // ptr to RGNDATA

                        DWORD dwFlags);  // flags, always 0

There’s not much more to say about this. Assuming you’ve already generated the `RGNDATA` structure for your clipping list, here’s how you would set the clipping list:

    if (FAILED(lpddclipper->SetClipList(&rgndata,0)))

        return(0);

Once the clip list is set, you can finally attach the clipper to the surface you want it to be associated with using `IDIRECTDRAWSURFACE4::SetClipper()`, which is shown here:

    HRESULT SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper);

And here’s the function in action:

    if (FAILED(lpddsurface->SetClipper(&lpddcliper)))

        return(0);

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.