Putting it all together

Now that we have all these initialization routines, we need to actually call them, so the question is, where to call them?

In an MFC application, a logical place to do this is in the application’s InitInstance routine:

In a plain Win32 application, you can do this in your WinMain function just before you enter the main message loop, but after you’ve created your window:

Restoring lost surfaces

As if all this initialization wasn’t enough, we also have to make sure our DirectDraw surfaces are not getting “lost”. The memory associated with DirectDraw surfaces can be released under certain circumstances, because it has to share resources with the Windows GDI. So each time we render, we first have to check if our surfaces have been lost and Restore them if they have. This is accomplished with the IsLost function.

The rendering loop

Now that we’ve got most of the general initialization out of the way, we need to set up a rendering loop. This is basically the main loop of the game, the so-called HeartBeat function. So we’re going to call it just that.

The HeartBeat function gets called during your applications idle-time processing, which is typically whenever the window has no more messages to process.

MFC: We can override the application’s OnIdle function and call our HeartBeat function from there. Use ClassWizard or the toolbar wizard to create a handler for “idle-time processing” for your main application class.

Win32: We can call the heartbeat function from inside the message loop, by using the function PeekMessage in our WinMain function to determine if we have any messages waiting:

There are alternate ways to decide when to call the HeartBeat function, for example you could use a timer. The method you use depends on the type of game you are making. If you are making a first-person 3D shooter, you probably want as high a frame rate as possible, so you might use the idle-time method. If you are making a 2D scrolling game, this might not be optimal, as you may want to control the frame rate.

The HeartBeat function

Now let’s look at the heartbeat function. The function checks for lost surfaces, then clears the back buffer with black, then draws a color square to the back buffer, and then flips the back buffer to the front.

The DDPutPixel function used here is already explained.

Flipping surfaces

Now let’s look at the function that performs the surface flipping.

A primary surface in windowed mode represents the entire Windows screen, so we have to first find out where on the screen our window is, and then translate by that offset in order to blit into the Window.

Note the Blt parameter DDBLT_WAIT. By default, if a surface is “busy” when you call Blt (for example if the GDI is accessing it) then DirectDraw will return an error, without performing the blit. Passing the DDBLT_WAIT option will instruct DirectDraw to wait until the surface becomes available and then perform the blit.

Cleaning up

When we’re done with DirectX objects, we have to “release” them, which is done by calling Release on them, for example:

Sample TODO

There are a few things the sample can’t do yet. For one thing, full-screen mode doesn’t work properly yet. It should also demonstrate how to handle switching between windowed and full-screen modes.

1 Shares
Share
Tweet
Share
Pin
+1