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

Everything seems fine, right? Wrong! The preceding `memcpy()` code will work only if `mempitch` or the primary surface stride is exactly 640 bytes per line. This may or may not be true. Alas, the preceding `memcpy()` code may fail terribly. A better way to write the double buffer copy function is to add a little function that tests if the memory pitch of the primary surface is 640. If so, the `memcpy()` is employed; if not, a line-by-line copy is used. A little slower, but the best you can do... Here’s the code for that:

    // can we use a straight memory copy?

    if (mempitch==640)

    {

    memcpy((void *)primary_buffer, (void *)double_buffer,640*480);

    } // end if

    else

    {

    // copy line by line, bummer!

    for (int y=0; y<480; y++)

        {

        // copy next line of 640 bytes

        memcpy((void *)primary_buffer, (void

        *)double_buffer,640);

        // now for the tricky part…

        // advance each pointer ahead to next line

        // advance to next line which is mempitch bytes away

        primary_buffer+=mempitch;

       // we know that we need to advance 640 bytes per line

       double_buffer+=640;

       } // end for y

    } // end else

Figure 7.9 shows the process graphically. As you can see, this is one of the times that you have to do the work—no cheating! However, at least you can optimize the code with 4-byte or 32-bit copy code later. That makes me feel a little better.

Figure 7.9 Copying the double buffer line by line.

As an example, I have created a demo that draws a set of random pixels on a double buffer and then copies the double buffer to the primary buffer in 640×480×8 mode. There’s a long delay between copies, so you can see that the image is entirely different. The name of the program is `DEMO7_4.CPP|EXE` and it’s on the CD. Remember to compile it yourself to add `DDRAW.LIB` to your project and have the header file paths set to the DirectX include directory. Here’s the `Game_Main()` from the program, which is where all the action occurs:

    int Game_Main(void *parms = NULL, int num_parms = 0)

    {

    // this is the main loop of the game, do all your processing

    // here

    UCHAR *primary_buffer = NULL; // used as alias to primary surface buffer

    // make sure this isn’t executed again

    if (window_closed)

       return(0);

    // for now test if user is hitting ESC and send WM_CLOSE

    if (KEYDOWN(VK_ESCAPE))

       {

       PostMessage(main_window_handle,WM_CLOSE,0,0);

       window_closed = 1;

       } // end if

    // erase double buffer

    memset((void *)double_buffer,0, SCREEN_WIDTH*SCREEN_HEIGHT);

    // you would perform game logic...

    // draw the next frame into the double buffer

    // plot 5000 random pixels

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

        {

        int   x   = rand()%SCREEN_WIDTH;

        int   y   = rand()%SCREEN_HEIGHT;

        UCHAR col = rand()%256;

        double_buffer[x+y*SCREEN_WIDTH] = col;

        } // end for index

    // copy the double buffer into the primary buffer

    DDRAW_INIT_STRUCT(ddsd);

    // lock the primary surface

    lpddsprimary->Lock(NULL,&ddsd,

                       DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);

    // get video pointer to primary surfce

    primary_buffer = (UCHAR *)ddsd.lpSurface;

    // test if memory is linear

    if (ddsd.lPitch == SCREEN_WIDTH)

       {

       // copy memory from double buffer to primary buffer

       memcpy((void *)primary_buffer, (void *)double_buffer,

              SCREEN_WIDTH*SCREEN_HEIGHT);

       } // end if

    else

       { // non-linear

       // make copy of source and destination addresses

       UCHAR *dest_ptr = primary_buffer;

       UCHAR *src_ptr  = double_buffer;

       // memory is non-linear, copy line by line

       for (int y=0; y < SCREEN_HEIGHT; y++)

           {

           // copy line

           memcpy((void *)dest_ptr, (void *)src_ptr, SCREEN_WIDTH);

           // advance pointers to next line

           dest_ptr+=ddsd.lPitch;

           src_ptr +=SCREEN_WIDTH;

           // note: the above code can be replaced with the simpler

           // memcpy(&primary_buffer[y*ddsd.lPitch],

           //        double_buffer[y*SCREEN_WIDTH], SCREEN_WIDTH);

           // but it is much slower due to the recalculation

           // and multiplication each cycle

           } // end for

       } // end else

    // now unlock the primary surface

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

       return(0);

    // wait a sec

    Sleep(500);

    // return success or failure or your own return code here

    return(1);

    } // end Game_Main

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.