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

So I’ll begin with the details of getting into a windowed mode. You already know how to do this! The only difference is that you don’t set the video mode or create a secondary back buffer. You’re not allowed to page flip in windowed modes. You must either use the blitter to double buffer or do it yourself, but you can’t set up a complex surface chain and then call `Flip()`. It won’t work. No problem, really; you’ll just create another surface that’s the same size as your window’s client area, draw on it, and blit it to the client area of your window on the primary buffer. That way you can avoid screen flicker.

Let me show you the code to create a windowed DirectDraw application. First, the DirectDraw initialization:

    LPDIRECTDRAW lpdd_temp = NULL; // used to get IDIRECTDRAW4 interface

    // first create base IDirectDraw interface

    if (FAILED(DirectDrawCreate(NULL, &lpdd_temp, NULL)))

       return(0);

    // now query for IDirectDraw4

    if (FAILED(lpdd_temp->QueryInterface(IID_IDirectDraw4,

                                   (LPVOID *)&lpdd)))

       return(0);

    // set cooperation to full screen

    if (FAILED(lpdd->SetCooperativeLevel(main_window_handle, DDSCL_NORMAL)))

       return(0);

    // clear ddsd and set size

    DDRAW_INIT_STRUCT(ddsd);

    // enable valid fields

    ddsd.dwFlags = DDSD_CAPS;

    // request primary surface

    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

    // create the primary surface

    if (FAILED(lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL)))

       return(0);

The key thing here is the cooperation level setting. Notice that it’s `DDSCL_NORMAL`, rather than the usual `(DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)` that you’ve been using for full-screen modes.

Also, when you’re creating the application window, you’ll want to use `WS_OVERLAPPED` or maybe `WS_OVERLAPPEDWINDOW` rather than `WS_POPUP`. The `WS_POPUP` style creates a window without any title, controls, and so on. `WS_OVERLAPPED` creates a window with a title, but it can’t be resized, and the `WS_OVERLAPPEDWINDOW` style creates a fully functional window with all the controls. However, in most cases I like to use `WS_OVERLAPPED` because I don’t want to deal with the resizing problem—it’s up to you.

For an example of what you know so far, take a look at `DEMO7_18.CPP|EXE`. It basically creates a windowed DirectX application with a client window that’s 400×400, along with a primary surface.

#### Drawing Pixels in a Window

Okay, now let’s move on to accessing the client area of the window. There are two things to remember: The primary surface is the entire screen, and you don’t know the color depth. Let’s look at the first problem—finding the client area of the window.

Because the user can move a window anywhere on the screen, the client coordinates are always changing—that is, if you think in terms of absolute coordinates. You need to find a way to figure out the upper-left corner of the client area in screen coordinates and then use that as your origin for pixel plotting. The function you need to use (which I’ve mentioned before) is `GetWindowRect()`:

    BOOL GetWindowRect(HWND hWnd, // handle of window

                       LPRECT lpRect);  // address of structure

                                        // for window coordinates

> Warning: `GetWindowRect()` actually retrieves the coordinates of your entire window, including the controls and border. I’ll show you how to figure out the exact client coordinates in a bit, but keep that in mind…

When you send the window handle of your application window, the function returns the screen coordinates of the client area of your window in `lpRect`. So all you need to do is call this function to retrieve the upper-left corner of your window in screen coordinates. Of course, every time the window moves, the coordinates change, so you must call `GetWindowRect()` every frame or when you receive a `WM_MOVE` message. I prefer calling it once a frame because I hate processing Windows messages!

Now that you know the screen coordinates of your window’s client area, you’re ready to manipulate the pixels. But wait a minute—what’s the pixel format?

I’m glad you asked, because you know the answer! That’s right, you need to use the `GetPixelFormat()` function at the beginning of your program to determine the color depth and then, based on this, make calls to different pixel plotting functions. So somewhere in your program, maybe in `Game_Init()` after setting up DirectDraw, you should make a call to `GetPixelFormat()` from the primary surface, like this:

    int pixel_format = 0;        // global to hold the bpp

    DDPIXELFORMAT ddpixelformat; // hold the pixel format

    // clean out the structure and set it up

    DDRAW_INIT_STRUCT(ddpixelformat);

    // get the pixel format

    lpddsprimary->GetPixelFormat(&ddpixelformat);

    // set global pixel format

    pixel_format = ddpixelformat.dwRGBBitCount;

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.