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

Let’s start with making a real function that takes transparency into consideration (use color 0), and that uses better addressing to speed things up and get rid of the multiplies. Here’s one example:

    void Blit8×8(int x, int y,

                 UCHAR *video_buffer,

                 UCHAR *bitmap)

    {

    // this function blits the image sent in bitmap to the

    // destination surface pointed to by video_buffer

    // the function assumes a 640x480x8 mode with linear pitch

    // compute starting point into video buffer

    // video_buffer = video_buffer + (x + y*640)

    video_buffer+= (x + (y << 9) + (y << 7));

    UCHAR pixel; // used to read/write pixels

    // main loop

    for (int index_y=0; index_y < 8; index_y++)

        {

        // inner loop, this is where it counts!

        for (int index_x=0; index_x < 8; index_x++)

             {

             // copy pixel, test for transparent though

             if ((pixel = bitmap[index_x])

                 video_buffer[index_x] = pixel;

             } // end for index_x

        // advance pointers

        bitmap+=8;          // next line in bitmap

        video_buffer+=640;  // next line in video_buffer

        } // end for index_y

    } // end Blit8×8

This version of the blitter function is many times faster than the previous one with multiplication, and this one even works with bitmaps that have transparent pixels—wow! The point of this exercise is to show you how something so simple can take up so many processor cycles. If you count cycles, the function is still crap. There’s the overhead of the loop mechanics, of course, but the guts of the function are still ugly. A test for transparency must be made, two array accesses, a write to memory… yuck, yuck, yuck! This is why there are accelerators. A hardware blitter can do this in its sleep, which is why you need to use the hardware to blit images down. That way you can save processor cycles for other things, like AI and physics!

Not to mention that the blitter function just shown is really stupid. It is hard-coded to 640×480×256, doesn’t do any clipping (more logic), and only works for 8-bit images.

Now that I’ve shown you the old way to draw bitmaps, here’s the first look at the blitter and how to use it to do memory fills. Then you’ll see how to copy images from one surface to another. Later in the chapter, you’ll use the blitter to draw game objects, but take your time.

#### Using the Blitter for Memory Filling

Although accessing the blitter under DirectDraw is trivial compared to programming it manually, it’s still a reasonably complex piece of hardware. Therefore, whenever I get my hands on a new piece of video hardware, I always like to try something simple first before I try pushing the envelope. So let me show you how to do something that’s very useful—memory fills.

Memory filling simply means filling a region of VRAM with some value. You’ve done this a number of times by locking a surface and then using `memset()` or `memcpy()` to manipulate and fill the surface memory, but there are a number of problems with this approach. First, you’re using the main CPU to do the memory fill, so the main bus is part of the transfer. Second, the VRAM that makes up a surface may not be totally linear. In that case, you’ll have to do a line-by-line fill or move. However, with the hardware blitter you can directly fill or move chunks of VRAM or DirectDraw surfaces instantly!

The two functions that DirectDraw supports for blitting are `IDIRECTDRAWSURFACE4::Blt()` and `IDIRECTDRAWSURFACE4::BltFast()`. Their prototypes are shown here:

    HRESULT Blt(LPRECT lpDestRect, // dest RECT

       LPDIRECTDRAWSURFACE4 lpDDSrcSurface, // dest surface

       LPRECT lpSrcRect,  // source RECT

       DWORD dwFlags,     // control flags

       LPDDBLTFX lpDDBltFx); // special fx (very cool!)

The parameters are defined here and illustrated graphically in Figure 7.15:

Figure 7.15 Blitting from source to destination.

`lpDestRect` is the address of a `RECT` structure that defines the upper-left and lower-right points of the rectangle to blit to on the destination surface. If this parameter is `NULL`, the entire destination surface will be used.

`lpDDSrcSurface` is the address of an `IDIRECTDRAWSURFACE4` interface for the DirectDraw surface to be used as the source of the blit.

`lpSrcRect` is the address of a `RECT` structure that defines the upper-left and lower-right points of the rectangle to blit from on the source surface. If this parameter is `NULL`, the entire source surface will be used.

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.