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

Then, once you know the pixel format, you can use some conditional logic, function pointers, or virtual functions to set the pixel plotting function to the correct color depth. To keep things simple, you’ll just use some conditional logic that tests the global `pixel_format` variable before plotting. Here’s some code that plots random pixels at random locations in the client area of the window:

    DDSURFACEDESC2 ddsd;    // directdraw surface description

    RECT           client;  // used to hold client rectangle

    // get the window’s client rectangle in screen coordinates

    GetWindowRect(main_window_handle, &client);

    // initialize structure

    DDRAW_INIT_STRUCT(ddsd);

    // lock the primary surface

    lpddsprimary->Lock(NULL,&ddsd,

                  DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);

    // get video pointer to primary surface

    // cast to UCHAR * since we don’t know what we are

    // dealing with yet and I like bytes :)

    UCHAR *primary_buffer = (UCHAR *)ddsd.lpSurface;

    // what is the color depth?

    if (pixel_format == 32)

       {

        // draw 10 random pixels in 32 bit mode

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

            {

            int x=rand()%(client.right - client.left) + client.left;

            int y=rand()%(client.bottom - client.top) + client.top;

            DWORD color = _RGB32BIT(0,rand()%256, rand()%256, rand()%256);

            *((DWORD *)(primary_buffer + x*4 + y*ddsd.lPitch)) = color;

            } // end for index

        } // end if 24 bit

    else

    if (pixel_format == 24)

       {

        // draw 10 random pixels in 24 bit mode (very rare???)

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

            {

            int x=rand()%(client.right - client.left) + client.left;

            int y=rand()%(client.bottom - client.top) + client.top;

            ((primary_buffer + x*3 + y*ddsd.lPitch))[0] = rand()%256;

            ((primary_buffer + x*3 + y*ddsd.lPitch))[1] = rand()%256;

            ((primary_buffer + x*3 + y*ddsd.lPitch))[2] = rand()%256;

            } // end for index

        } // end if 24 bit

    else

    if (pixel_format == 16)

        {

        // draw 10 random pixels in 16 bit mode

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

            {

            int x=rand()%(client.right - client.left) + client.left;

            int y=rand()%(client.bottom - client.top) + client.top;

            USHORT color = _RGB16BIT565(rand()%256, rand()%256, rand()%256);

            *((USHORT *)(primary_buffer + x*2 + y*ddsd.lPitch)) = color;

            } // end for index

        } // end if 16 bit

    else

        {// assume 8 bits per pixel

        // draw 10 random pixels in 8 bit mode

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

            {

            int x=rand()%(client.right - client.left) + client.left;

            int y=rand()%(client.bottom - client.top) + client.top;

            UCHAR color = rand()%256;

            primary_buffer[x + y*ddsd.lPitch] = color;

            } // end for index

        } // end else

    // unlock primary buffer

    lpddsprimary->Unlock(NULL);

Of course, this code is an optimization nightmare, and it hurts me to even show you such slow, crude, troglodyte code, but it’s easy to understand. In real life, you would use function pointers or a virtual function, completely remove all multiplies and mods, and use incremental addressing. Anyway, just wanted to indemnify myself <BG>.

For an example of plotting pixels in any color depth, take a look at `DEMO7_19.CPP|EXE`. It creates a 400×400 window and then plots pixels in the client area (well, almost). Try running the program with different color depths, and notice that it still works! When you’re done, come back and I’ll talk about rendering more accurately to the actual interior client area…

#### Finding the Real Client Area (51)

The problem with windows is that when you create a window using `CreateWindow()` or `CreateWindowEx()`, you’re specifying the total width and size of the window, including any controls. Hence, if you create a blank `WS_POPUP` window without any controls, the size of the window is exactly the size of the client area. Presto—no drama. On the other hand, the second you add controls, menus, borders, whatever, and make the call to `CreateWindowEx()`, Windows shrinks the interior client area so that it can fit in all the controls. The result: a working area that’s less than what you desired. Figure 7.39 illustrates this cosmic dilemma. The solution is to resize your window taking into consideration the border, controls, etc.

Figure 7.39 A window’s client area is smaller than the window surrounding it.

For example, let’s say you want a window that has a working area of 640×480, but you want to also have a border, a menu, and standard window controls. What you need to do is calculate how many pixels all the extra Windows gadgetry takes in the X and Y direction, and then simply increase the size of your window until the working client area is the desired size. The magical function that computes the size of a window with various styles is called `AdjustWindowRectEx()` and is shown here:

    BOOL AdjustWindowRectEx(

         LPRECT lpRect,    // pointer to client-rectangle structure

         DWORD  dwStyle,   // window styles

         BOOL   bMenu,     // menu-present flag

         DWORD  dwExStyle);// extended style

You fill in all the parameters, and the function resizes the structure data sent in `lpRect` to take into consideration all the extra styles and flags for the window. To use the function, you first set up a `RECT` structure with the desired client area size, say, 640×480. Then you make the call, along with all the proper parameters you created the original window with. However, I never can remember what I set the window to, or the exact names of the flags, so you can ask Windows to tell you what you did and save some neurons. Here’s the call, along with the window’s helper functions that query the styles based on the `HWND` that you send:

    // the client size we desire

    RECT window_rect = {0,0,640,480};

    // make the call to adjust window_rect

    AdjustWindowRectEx(&window_rect,

         GetWindowStyle(main_window_handle),

         GetMenu(main_window_handle) != NULL,

         GetWindowExStyle(main_window_handle));

    // now resize the window with a call to MoveWindow()

    MoveWindow(main_window_handle,

               CW_USEDEFAULT, // x position

               CW_USEDEFAULT, // y position

               window_rect.right – window_rect.left, // width

               window_rect.bottom – window_rect.top, // height

               FALSE;

And that’s it, baby!

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.