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
 The Design
 CreateSurfaces()
 DestroySurfaces()
 The Game Loop
 Switching Modes
 While Running


 Get the demo!
 Printable version

 


  The Series

 Part 1
 Part 2

 

The Game Loop

You may think that the only real difference in the game loop is that you blit the back buffer to the primary surface when you're in windowed mode instead of flipping… We'll start with that part though. Split your rendering function into two sections, separated by an if statement:

if( g_bExclusive ) { // exclusive code } else { // windowed code }

Where did that g_bExclusive flag come from? It's that global variable that we use to keep track of the mode we're working in.

Put your old exclusive mode rendering code in the exclusive code section, then add a call to Blt in the windowed code section. Use the primary surface as the destination, and the back buffer as the source, like this:

lpddPrimary->Blt(NULL, lpddBack, NULL, DDBLT_WAIT, NULL);

That's about as simple as you can get! But wait, that code draws to the whole primary surface, not just our window! How do we get DirectDraw to copy the entire back buffer to our main window's client area? Well, we obtain the client area of the window, then convert the two points of the rectangle into points that are relative to the upper left corner of the screen. Pass that rect as the first parameter of the Blt call and you're set! Here's some code to do that:

// calculate the client rect in screen coordinates RECT rect; ZeroMemory(&rect, sizeof( rect )); // get the client area GetClientRect(hMainWnd, &rect); // copy the rect's data into two points POINT p1; POINT p2; p1.x = rect.left; p1.y = rect.top; p2.x = rect.right; p2.y = rect.bottom; // convert it to screen coordinates (like DirectDraw uses) ClientToScreen(hMainWnd, &p1); ClientToScreen(hMainWnd, &p2); // copy the two points' data back into the rect rect.left = p1.x; rect.top = p1.y; rect.right = p2.x; rect.bottom = p2.y; // blit the back buffer to our window's position g_lpPrimary->Blt(&rect, g_lpBack, NULL, DDBLT_WAIT, NULL);

There's one more part to your game loop: you can't hog the system like you could in exclusive mode. Whenever Windows (or another app) wants resources, you must give it to them. This is because the user has made the choice, not just the OS. A good Windows app lets the user switch between windows, using other apps at the same time. That's why it's called Windows!

So, how do we do that? Well, what consumes most of the computer's power? The game loop, of course! So, we "pause" the game automatically when the user switches to something else, and "resume" it automatically when the user switches back to our app. (In games like massive online multiplayer games, this is not plausible; you'll have to think of something else. Tip: you could at least pause the rendering, or slow it down a little.) Anyway, to pause the game loop, we add a variable to keep track of whether the game is running or not:

bool bRunGame;

Then, we handle a certain Windows message in our main WndProc: WM_ACTIVATE. Whenever our main window receives the focus, we get one of these messages. We get another one of those messages when our main window loses the focus (which happens when another window gains the focus). Checking the value of wParam tells us if we're gaining or losing the focus. Set the bRunGame flag like this:

if( LOWORD( wParam ) == WA_INACTIVE ) { // the user is now working with another app bRunGame = false; } else { // the user has now switched back to our app bRunGame = true; }

To use this variable we have just set up, check it before you continue the game loop. Replace your program's main message loop (probably in WinMain) with this; you'll note that the game loop is embedded in the message loop (near the end):

Popup : Source Listing 1

Then place your game code inside that if statement we just added, where it says: // game code here. This completes the game loop section. Whew! We need to now look at changing modes while running the program. Trust me, it'll be the easiest section in this article!!


Next : Switching Modes While Running