Adding Frame Rate Output


One more of the many things the sample framework does is keep track of the game's frame rate. Frame rate is something that most 3D games closely track because it deals directly with the performance of the game. It is simply the number of frames rendered in any given second, and the framework calculates it using the high-resolution timer discussed earlier in this chapter.

The code included on the CD only displays the frame rate in debug mode so it doesn't clutter the screen in full-screen mode. Therefore, the code in this section assumes this behavior as well. Add the following variable to your game engine class declarations:

 #if (DEBUG) private Direct3D.Font debugFont = null; #endif 

The first thing you'll notice here is that you've declared a new type of variable, the Direct3D.Font object. This object is used to render text onscreen as part of your scene.

Construction Cue

You'll also notice the 'alias' for the Direct3D namespace used here. It allows you to reference the items in the Direct3D namespace without having to type the full Microsoft.DirectX.Direct3D namespace (which is fully qualified). Using this alias is required for the Font class because more than one Font class exists, the one you just declared and another in the System.Drawing namespace. Make sure that you add the using alias at the top of your game engine code file:

 using Direct3D = Microsoft.DirectX.Direct3D; 


Now that the variable is declared, in your OnCreateDevice method add the following code to create a new font object:

 #if (DEBUG) debugFont = new Direct3D.Font(device, new System.Drawing.Font("Arial", 12)); #endif 

The only parameters you need for this object are the rendering device and the font you want to render with. Using a default font is adequate for this scenario. Because the font object here is also a resource, make sure that you clean up that object in your OnDestroyDevice method. Add this code to that method now:

 #if (DEBUG) if (debugFont != null) {     // Clean up the font     debugFont.Dispose();     debugFont = null; } #endif 

One thing you might notice on the font object is that it has two "special" methods for use when a device has just been reset or is about to be lost, OnDeviceReset and OnDeviceLost, respectively. You already have methods to handle when the device has just been reset and lost, so you want to call these font methods there. Add this section of code to the beginning of your OnResetDevice method to make sure that the font behaves correctly during a device reset:

 #if (DEBUG) // Make sure the debug font resets correctly debugFont.OnResetDevice(); #endif 

You want to handle the lost case as well, so add this section of code to the OnLostDevice method:

 #if (DEBUG) if (debugFont != null) {     // Make sure the debug font gets rid of any resources     debugFont.OnLostDevice(); } #endif 

Now that your font is created, you can look at the implementation of the UpdateFrameStats method from the framework, which is called every frame and calculates the current frame rate. See the code in Listing 5.5 from the framework.

Listing 5.5. Calculating Frame Rate
 private void UpdateFrameStats() {     // Keep track of frame count     double time = FrameworkTimer.GetAbsoluteTime();     State.LastStatsUpdateFrames++;     if (time - State.LastStatsUpdateTime > 1.0)     {         float fps = (float)(State.LastStatsUpdateFrames /              (time - State.LastStatsUpdateTime));         State.CurrentFrameRate = fps;         State.LastStatsUpdateFrames = 0;         State.LastStatsUpdateTime = time;         State.FrameStats = string.Format(State.StaticFrameStats,             fps.ToString("f2",             System.Globalization.CultureInfo.CurrentUICulture));     } } 

Now that you know how the frame rate is calculated, the last thing you need to do is actually update your scene by rendering this text. Add this code to the end of your render method, directly before your EndScene call (but not inside the finally block).

 #if (DEBUG) // Show debug stats (in debug mode) debugFont.DrawText(null, sampleFramework.FrameStats,     new System.Drawing.Rectangle(2,0,0,0),     DrawTextFormat.NoClip, unchecked((int)0xffffff00)); debugFont.DrawText(null, sampleFramework.DeviceStats,     new System.Drawing.Rectangle(2,15,0,0),     DrawTextFormat.NoClip, unchecked((int)0xffffff00)); #endif 

Look at the prototype for the DrawText call; it is more or less self-explanatory. The prototype looks like this:

 public System.Int32 DrawText ( Microsoft.DirectX.Direct3D.Sprite sprite ,     System.String text , System.Drawing.Rectangle rect ,     Microsoft.DirectX.Direct3D.DrawTextFormat format ,     System.Drawing.Color color ) 

Because the first parameter is null, you are specifying that you want to draw directly onscreen. Sprites are used to render 2D images onto the screen, and you use them for rendering the UI of the game later. For now, however, because you are just rendering debug information, you want it rendered directly to the screen. The second parameter is the string you will be rendering, and the third parameter is the rectangle you want to render the text into. The client rectangle is perfect here, even though you wouldn't need to use it all. The last parameter is the color you want the text to be rendered. It really is as simple as that.



Beginning 3D Game Programming
Beginning 3D Game Programming
ISBN: 0672326612
EAN: 2147483647
Year: 2003
Pages: 191
Authors: Tom Miller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net