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

The last parameter is to facilitate an advanced feature that Win32 supports called events. Set it to `NULL`.

Locking the primary surface is really easy. What you want to do is request the memory pointer to the surface, along with requesting DirectDraw to wait for the surface to become available. Here’s the code:

    DDSURFACEDESC2 ddsd; // this will hold the results of the lock

    // clear the surface description out always

    memset(&ddsd, 0, sizeof(ddsd));

    // set the size field always

    ddsd.dwSize = sizeof(ddsd);

    // lock the surface

    if (FAILED(lpddsprimary->Lock(NULL,

               &ddsd,

               DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL)))

     {

     // error

     } // end if

    // ****** at this point there are two fields that we are

    // concerned with: ddsd.lPitch which contains the memory

    // pitch in bytes per line and ddsd.lpSurface which is a

    // pointer to the top left corner of the locked surface

Once you’ve locked the surface, you’re free to manipulate the surface memory as you wish. The memory pitch per line is stored in `ddsd.lPitch`, and the pointer to the actual surface is `ddsd.lpSurface`. Therefore, if you’re in any 8-bit mode (1 byte per pixel), the following function can be used to plot a pixel anywhere on the primary surface:

    inline void Plot8(int x, int y,  // position of pixel

                  UCHAR color,   // color index of pixel

                  UCHAR *buffer, // pointer to surface memory

                  int mempitch)  // memory pitch per line

    {

    // this function plots a single pixel

    buffer[x+y*mempitch] = color;

    } // end Plot8

Here’s how you would call it to plot a pixel at (100,20) with color index 26:

    Plot8(100,20,26, (UCHAR *)ddsd.lpSurface,(int)ddsd.lPitch);

Similarly, here’s a 16-bit 5.6.5 RGB mode plot function:

    inline void Plot16(int x, int y,  // position of pixel

                  UCHAR red,

                  UCHAR green,

                  UCHAR, blue  // RGB color of pixel

                  USHORT *buffer, // pointer to surface memory

                  int mempitch)   // memory pitch bytes per line

    {

    // this function plots a single pixel

    buffer[x+y*(mempitch>>1)] = _RGB16BIT565(red,green,blue);

    } // end Plot16

And here’s how you would plot a pixel at (300,100) with RGB value (10,14,30):

    Plot16(300,100,10,14,30,(USHORT *)ddsd.lpSurface,(int)ddsd.lPitch);

Now, once you’re done with all your video surface access for the current frame of animation, you need to unlock the surface. This is accomplished with the `IDirectDrawSurface4::Unlock()` method shown here:

    HRESULT Unlock(LPRECT lpRect);

You send `Unlock()` the original `RECT` that you used in the lock command, or `NULL` if you locked the entire surface. In this case, here’s all you would do to unlock the surface:

    if (FAILED(lpddsprimary->Unlock(NULL)))

       {

       // error

       } // end if

That’s all there is to it. Now, let’s see all the steps put together to plot random pixels on the screen (without error detection):

    LPDIRECTDRAW lpdd  = NULL; // standard DirectDraw 1.0

    LPDIRECTDRAW lpdd4 = NULL; // DirectDraw 6.0 interface 4

    LPDIRECTDRAWSURFACE4 lpddsprimary = NULL; // surface ptr

    DDSURFACEDESC2      ddsd;    // surface description

    LPDIRECTDRAWPALETTE lpddpal = NULL; // palette interface

    PALETTEENTRY palette[256]; // palette storage

    // first create base IDirectDraw interface

    DirectDrawCreate(NULL, &lpdd, NULL);

    // now query for IDirectDraw4

    lpdd->QueryInterface(IID_IDirectDraw4,

                         (LPVOID *)&lpdd4);

    // release lpdd

    lpdd->Release();

    // set the cooperative level for full-screen mode

    lpdd4->SetCooperativeLevel(hwnd,

                               DDSCL_FULLSCREEN |

                               DDSCL_ALLOWMODEX |

                               DDSCL_EXCLUSIVE |

                               DDSCL_ALLOWREBOOT);

    // set the display mode to 640x480x256

    lpdd4->SetDisplayMode(640,480,8,0,0);

    // clear ddsd and set size

    memset(&ddsd,0,sizeof(ddsd));

    ddsd.dwSize = sizeof(ddsd);

    // enable valid fields

    ddsd.dwFlags = DDSD_CAPS;

    // request primary surface

    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

    // create the primary surface

    lpdd4->CreateSurface(&ddsd, &lpddsprimary, NULL);

    // build up the palette data array

    for (int color=1; color < 255; color++)

        {

        // fill with random RGB values

        palette[color].peRed   = rand()%256;

        palette[color].peGreen = rand()%256;

        palette[color].peBlue  = rand()%256;

        // set flags field to PC_NOCOLLAPSE

        palette[color].peFlags = PC_NOCOLLAPSE;

        } // end for color

    // now fill in entry 0 and 255 with black and white

    palette[0].peRed   = 0;

    palette[0].peGreen = 0;

    palette[0].peBlue  = 0;

    palette[0].peFlags = PC_NOCOLLAPSE;

    palette[255].peRed   = 255;

    palette[255].peGreen = 255;

    palette[255].peBlue  = 255;

    palette[255].peFlags = PC_NOCOLLAPSE;

    // create the palette object

    lpdd4->CreatePalette(DDPCAPS_8BIT |DDPCAPS_ALLOW256 |

                         DDPCAPS_INITIALIZE,

                         palette,&lpddpal, NULL);

    // finally attach the palette to the primary surface

    lpddsprimary->SetPalette(lpddpal);

    // and you're ready to rock n roll!

    // lock the surface first and retrieve memory pointer

    // and memory pitch

    // clear ddsd and set size, never assume it's clean

    memset(&ddsd,0,sizeof(ddsd));

    ddsd.dwSize = sizeof(ddsd);

    lpddsprimary->Lock(NULL, &ddsd,

                  DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL))

    // now ddsd.lPitch is valid and so is ddsd.lpSurface

    // make a couple aliases to make code cleaner, so we don't

    // have to cast

    int mempitch        = ddsd.lPitch;

    UCHAR *video_buffer = ddsd.lpSurface;

    // plot 1000 random pixels with random colors on the

    // primary surface, they will be instantly visible

    for (int index=0; index<1000; index++)

        {

        // select random position and color for 640x480x8

        UCHAR color = rand()%256;

        int x = rand()%640;

        int y = rand()%480;

        // plot the pixel

        video_buffer[x+y*mempitch] = color;

        } // end for index

    // now unlock the primary surface

    lpddsprimary->Unlock(NULL);

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.