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

#### Creating a Primary Surface

All right, to create any surface, you must follow these steps:

  1. Fill out a `DDSURFACEDESC2` data structure that describes the surface you want to create.
  2. Call `IDirectDraw4::CreateSurface()` to create the surface.

Here’s the prototype for `CreateSurface()`:

    HRESULT CreateSurface(

            LPDDSURFACEDESC2 lpDDSurfaceDesc2,

            LPDIRECTDRAWSURFACE4 FAR *lplpDDSurface,

            IUnknown FAR *pUnkOuter);

Basically, the function takes a DirectDraw surface description of the surface you want to create, a pointer to receive the interface, and finally `NULL` for the advanced COM feature `pUnkOuter.` Huh? Filling out the data structure can be a bit bewildering, but I’ll step you through it. First, let’s take a look at the `DDSURFACEDESC2`:

    typedef struct _DDSURFACEDESC2

            {

            DWORD dwSize;   // size of this structure

            DWORD dwFlags;  // control flags

            DWORD dwHeight; // height of surface in pixels

            DWORD dwWidth;  // width of surface in pixels

            union

            {

            LONG  lPitch;        // memory pitch per row

            DWORD dwLinearSize;  // size of the buffer in bytes

            } DUMMYUNIONNAMEN(1);

            DWORD dwBackBufferCount;  // number of back buffers chained

            union

            {

            DWORD dwMipMapCount;           // number of mip-map levels

            DWORD dwRefreshRate;           // refresh rate

            } DUMMYUNIONNAMEN(2);

            DWORD  dwAlphaBitDepth;        // number of alpha bits

            DWORD  dwReserved;             // reserved

            LPVOID lpSurface;              // pointer to surface memory

            DDCOLORKEY ddckCKDestOverlay;  // dest overlay color key

            DDCOLORKEY ddckCKDestBlt;      // destination color key

            DDCOLORKEY ddckCKSrcOverlay;   // source overlay color key

            DDCOLORKEY ddckCKSrcBlt;       // source color key

            DDPIXELFORMAT ddpfPixelFormat; // pixel format of surface

            DDSCAPS2   ddsCaps;            // surface capabilities

            DWORD      dwTextureStage;     // used to bind a texture

                                           // to specific stage of D3D

            } DDSURFACEDESC2, FAR* LPDDSURFACEDESC2;

As you can see, this is a complicated structure. Moreover, 75 percent of the fields are more than cryptic. Luckily, you only need to know about the ones that I’ve bolded. Let’s take a look at their functions in detail, one by one:

  `dwSize`—This is one of the most important fields in any DirectX data structure. Many DirectX data structures are sent by address, so the receiving function or method doesn’t know the size of the data structure. However, if the first 32-bit value is always the size of the data structure, the receiving function will always know how much data is there just by dereferencing the first `DWORD`. Hence, DirectDraw and DirectX data structures in general have the size specifier as the first element of all structures. It may seem redundant, but it’s a good design—trust me. All you need to do is fill it in like this:

      DDSURFACEDESC2 ddsd;

      ddsd.dwSize = sizeof(DDSURFACEDESC2);

  `dwFlags`—This field is used to indicate to DirectDraw which fields you’ll be filling in with valid info or, if you’re using this structure in a query operation, which fields you want to retrieve. Take a look at Table 6.5 for the possible values that the flags word can take on. For example, if you were going to place valid data in the `dwWidth` and `dwHeight` fields, you would set the `dwFlags` field like this:

      ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT;

  Then DirectDraw would know to look in the `dwHeight` and `dwWidth` fields and that the data would be valid. Think of `dwFlags` as a valid data specifier.

Table 6.5 The Various Flags for the `dwFlags` Field of `DDSURFACEDESC2`

Value | Description
--- | ---

`DDSD_ALPHABITDEPTH` | Indicates that the `dwAlphaBitDepth` member is valid.
`DDSD_BACKBUFFERCOUNT` | Indicates that the `dwBackBufferCount` member is valid.
`DDSD_CAPS` | Indicates that the `ddsCaps` member is valid.
`DDSD_CKDESTBLT` | Indicates that the `ddckCKDestBlt` member is valid.
`DDSD_CKDESTOVERLAY` | Indicates that the `ddckCKDestOverlay` member is valid.
`DDSD_CKSRCBLT` | Indicates that the `ddckCKSrcBlt` member is valid.
`DDSD_CKSRCOVERLAY` | Indicates that the `ddckCKSrcOverlay` member is valid.
`DDSD_HEIGHT` | Indicates that the `dwHeight` member is valid.
`DDSD_LINEARSIZE` | Indicates that the `dwLinearSize` member is valid.
`DDSD_LPSURFACE` | Indicates that the `lpSurface` member is valid.
`DDSD_MIPMAPCOUNT` | Indicates that the `dwMipMapCount` member is valid.
`DDSD_PITCH` | Indicates that the `lPitch` member is valid.
`DDSD_PIXELFORMAT` | Indicates that the `ddpfPixelFormat` member is valid.
`DDSD_REFRESHRATE` | Indicates that the `dwRefreshRate` member is valid.
`DDSD_TEXTURESTAGE` | Indicates that the `dwTextureStage` member is valid.
`DDSD_WIDTH` | Indicates that the `dwWidth` member is valid.

  `dwWidth`—Indicates the width of the surface in pixels. When you create a surface, this is where you set the width—320, 640, and so on. In addition, if you query the properties of a surface, this field will return the width of the surface (if you requested it).
  `dwHeight`—Indicates the height of the surface in pixels. Similarly to `dwWidth`, this is where you set the height of the surface you are creating—200, 240, 480, and so on.
  `lPitch`—This is an interesting field. It’s basically the horizontal memory pitch of the display mode that you’re in. Referring to Figure 6.8, the `lPitch` is the number of bytes per line for the video mode, also referred to as the stride or memory width. However you pronounce it, the bottom line is that this is a very important piece of data for the following reason: When you request a video mode like 640×480×8, you know that there are 640 pixels per line and each pixel is 8 bits (or 1 byte). Therefore, there should be exactly 640 bytes per line, and hence `lPitch` should be 640. Right? Not necessarily.

Figure 6.8 Accessing a surface.

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.