Tricks of the Windows Game Programming Gurus:First Contact: DirectDraw

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

#### Plotting Pixels

To plot a pixel (or pixels) in a full-screen DirectDraw mode, you first must set up DirectDraw, set the cooperation level, set a display mode, and create at least a primary surface. Then you have to gain access to the primary surface and write to the video memory. However, before you learn how to do this, let’s take another look at how video surfaces work.

If you’ll recall, all DirectDraw video modes and surfaces are linear, as shown in Figure 6.9. This means that memory increases from left to right and from top to bottom as you move from row to row.

Figure 6.9 DirectDraw surfaces are linear.

> Tip: You may be wondering how DirectDraw can magically turn a nonlinear video mode into a linear one if the video card itself doesn’t support it. For example, Mode X is totally nonlinear and bank-switched. Well, the truth is this—when DirectDraw detects that a mode is nonlinear in hardware, a driver called `VFLATD.VXD` is invoked, which creates a software layer between you and the VRAM and makes the VRAM look linear. Keep in mind that this is going to be slow.

In addition, to locate any position in the video buffer, you need only two pieces of information: the memory pitch per line (that is, how many bytes make up each row) and the size of each pixel (8-bit, 16-bit, 24-bit, 32-bit). You can use the following formula:

    // assume this points to VRAM or the surface memory

    UCHAR *video_buffer8;

    video_buffer8[x + y*memory_pitchB] = pixel_color_8;

Of course, this is not exactly true because this formula works only for 8-bit modes, or modes that have one BYTE per pixel. For a 16-bit mode, or two BYTEs per pixel, you would have to do something like this:

    // assume this points to VRAM or the surface memory

    USHORT *video_buffer16;

    video_buffer16[x + y*(memory_pitchB >> 1)] = pixel_color_16;

There’s a lot going on here, so let’s take a look at the code carefully. Since we’re in a 16-bit mode, I’m using a `USHORT` pointer to the VRAM. What this does is let me use array access, but with 16-bit pointer arithmetic. Hence, when I say

    video_buffer16[1]

this really accesses the second `SHORT` or byte pair 2,3. In addition, because `memory_pitchB` is in bytes, you must divide it by two by shifting right one bit so that it’s in `SHORT` or 16-bit memory pitch. Finally, the assignment of `pixel_color16` is also misleading because now a complete 16-bit `USHORT` will be written into the video buffer, rather than a single 8-bit value as in the previous example. Moreover, the 8-bit value would be a color index, whereas a 16-bit value must be a RGB value, usually encoded in R5G6B5 format or five bits for red, six bits for green, and five bits for blue, as shown in Figure 6.10.

Figure 6.10 Possible 16-bit RGB encodings, including 5.6.5 format.

Here’s a macro to make up a 16-bit RGB word:

    // this builds a 16 bit color value

    #define _RGB16BIT565(r,g,b) ((b%32) + ((g%64) << 5) + ((r%32) << 11))

As you can see, 16-bit modes and RGB modes in general have a little more complex addressing and manipulation than do the 256-color 8-bit modes, so let’s begin there.

To gain access to any surface—primary, secondary, and so on—you must lock and unlock the memory. This lock and unlock sequence is necessary for two reasons: First, to tell DirectDraw that you are in control of the memory (that is, it shouldn’t be accessed by other processes), and second, to indicate to the video hardware that it shouldn’t move any cache or virtual memory buffers around while you’re messing with the locked memory. Remember, there is no guarantee that VRAM will stay in the same place. It could be virtual, but when you lock it, the memory will stay in the same address space for the duration of the lock so you can manipulate it. The function to lock memory is called `IDirectDrawSurface4::Lock()` and is shown here:

    HRESULT Lock(LPRECT   lpDestRect,      // destination RECT to lock

         LPDDSURFACEDESC2 lpDDSurfaceDesc, // address of struct to receive info

         DWORD            dwFlags,         // request flags

         HANDLE           hEvent);         // advanced, make NULL

The parameters aren’t that bad, but there are some new players. Let’s step through them. The first parameter is the `RECT` of the region of surface memory that you want to lock; take a look at Figure 6.11. DirectDraw allows you to lock only a certain portion of surface memory so that, if another process is accessing a region that you aren’t, processing can continue. This is great if you know that you’re going to update only a certain part of the surface and don’t need a full lock on the entire surface. However, in most cases you’ll just lock the entire surface to keeps things simple. This is accomplished by passing `NULL.`

Figure 6.11 Locking surface memory.

The second parameter is the address of a `DDSURFACEDESC2` that will be filled with information about the surface that you request. Basically, just send a blank `DDSURFACEDESC2` and that’s it. The next parameter, `dwFlags`, tells `Lock()` what you want to do. Table 6.7 contains a list of the most commonly used values.

Table 6.7 The Control Flags for the `Lock()` Method

Value | Description
--- | ---

`DDLOCK_READONLY` | Indicates that the surface being locked will be read-only.
`DDLOCK_SURFACEMEMORYPTR` | Indicates that a valid memory pointer to the top of the specified `RECT` should be returned. If no rectangle is specified, a pointer to the top of the surface is returned. This is the default.
`DDLOCK_WAIT` | If a lock cannot be obtained because a blit operation is in progress, the method retries until a lock is obtained or another error occurs, such as `DDERR_SURFACEBUSY`.
`DDLOCK_WRITEONLY` | Indicates that the surface being locked will be write-enabled.

> Note: I have bolded the most commonly used flags.

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.