Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
89 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

  Contents

 Introduction
 Windows’ window
 coordinate
 systems

 Making the Main
 Window Shine

 Multi-threading
 Theory and
 Performance
 Issues


 Get the demo!
 Printable version

 


  The Series

 Part 1
 Part 2

 

Making the Main Window Shine

Remember when I said we’d add some neat tricks to the AdjustMainWindow function? Now we’re going to do just that. You can see with the Step 1 version of the Mode Switch Demo app that it doesn’t own the whole screen, even in exclusive mode – it still has a title bar, a close button, and other things that will mess up your game (however, the whole screen can still be drawn to – it would be very frustrating for the user to start clicking on a monster near the top of the screen and the game closes... well, you get my point!). You can try to override those things with some messaging tricks, but it’s always better (and far easier ;-) ) to do it by the books. To make a window with absolutely no title bar, border, or system menu, you just set its style to WS_POPUP in the CreateWindow function. But wait, do I have to destroy and re-create the window every time I switch modes? No, there is a way to change the window style while the app is running – we’ll look at it now.

Here are the Windows API functions:

LONG GetWindowLong(HWND hWnd, int nIndex); LONG SetWindowLong(HWND hWnd, int nIndex, LONG dwNewLong);

Kind of unassuming, aren’t they? Who would’ve guessed the names? (don’t lie – you wouldn’t have guessed them! ;-) ) Basically, with these functions, hWnd indicates the window you want to set or retrieve information about, and nIndex indicates the type of information you want to specify. If you are setting new information about the window, you put it in dwNewLong. You can do a lot of neat things with this function, but we’ll just look at GWL_STYLE for nIndex.

So, to get the window style for the main window, you do this:

LONG nMainWindowStyle = GetWindowLong(hMainWnd, GWL_STYLE);

Remember though, this is directly accessing the window style, whereas CreateWindow supplies the proper defaults or just quits when you don’t specify something properly. We’ll need to take a little extra care to make it work. Here’s how the AdjustWindow function looks now:

void AdjustMainWindow(bool bExclusive, int nScreenWidth, int nScreenHeight) { static HMENU hOldMenu = NULL; // hide the window while we're working... ShowWindow(hMainWnd, SW_HIDE); if( bExclusive ) { // exclusive mode code if( !g_bExclusive ) { // change the style of the window SetWindowLong(hMainWnd, GWL_STYLE, WS_POPUP); // remove the menu and save the old menu hOldMenu = GetMenu(hMainWnd); SetMenu(hMainWnd, NULL); } } else { // windowed mode code if( g_bExclusive ) { // change the style of the window SetWindowLong(hMainWnd, GWL_STYLE, /* windowed mode style */); // re-attach the old menu if( hOldMenu ) SetMenu(hMainWnd, hOldMenu); } // calculate the new window rect SIZE szDesiredClient; szDesiredClient.cx = nScreenWidth; szDesiredClient.cy = nScreenHeight; RECT rcNewWindowRect = CalculateWindowRect(hMainWnd, szDesiredClient); // resize the window according to the new rect MoveWindow(hMainWnd, rcNewWindowRect.left, rcNewWindowRect.top, (rcNewWindowRect.right – rcNewWindowRect.left), (rcNewWindowRect.bottom – rcNewWindowRect.top), true); } // unhide the window now that we're done with it ShowWindow(hMainWnd, SW_SHOW); }

Just specify the window style you normally use for a windowed mode app for the /* windowed mode style */, and the WS_POPUP style for the exclusive mode style. Also, we have to remove the menu when in exclusive mode and restore it when we switch to windowed mode. Note, however, that simply changing the window style will not take care of status bars, toolbar, and other additions to the window – it only takes care of the things that can be created with the window style alone. You must hide any toolbars, status bars, etc. yourself.

Now for the bad news – DirectDraw apparently hooks the WndProc of fullscreen mode programs and makes it so the window is topmost, even when we’re in windowed mode. So, we must destroy the window and re-create it in our SwitchMode function to make sure the window works as planned. Just move your own CreateWindow code into the SwitchMode function, just before the call to AdjustWindow. Then, add this code directly before the CreateWindow code you just added, and after the DestroySurfaces call:

if( IsWindow(hMainWnd) ) DestroyWindow(hMainWnd);

That code just destroys the window if it exists, so we can create it again without losing resources. The IsWindow and DestroyWindow are just Windows API functions. Note that DestroyWindow sends a WM_DESTROY message to the WndProc, so you’ll have to move your PostQuitMessage(0) call to WM_CLOSE or something else. Otherwise, your program will exit every time you try to switch modes! ;-)

What, exactly, has this accomplished? Well, we’ve managed to create a system that changes between exclusive and windowed mode. It works transparently to your actual drawing code (blitting sprites, rendering 3D, etc.), so anything you can draw on the back buffer will show up on the screen. As mentioned before, you can even do 3D with this system – just make the appropriate changes to CreateSurfaces and DestroySurfaces.

What is this good for? Well, I hate to say this, but trends indicate more powerful computers in the future. If Moore’s law is true, CPU speed will double in a few months, 3D cards will look nearly 5% better (ok, that’s a little bit of cynicism), and many other improvements will be made. I have many older DX games that I find enjoyable, which someone took the time to write so that they can do windowed mode almost as fast as exclusive mode. Now, I can look up game codes on the Internet, draw, or whatever with those games running, because my computer’s been upgraded since they came out. Upgrading your computer should allow new features for old games – it adds to the replay value.

Windowed mode also has excellent uses in the present for the developer. Not everyone is a performance nut (nut, meaning craving an extra fps when already doing 83 fps ;-) ), and your game will almost certainly be out-of-date three months after it was released. Besides, now that you know what things are involved, you can write editors for your games as easily as copying and pasting your drawing code (think map editors). Read on for performance tips in Windows!




Next : Multi-threading Theory and Performance Issues