CU_MDX_Text.zip (63.8 KB, 1,275 hits)
CUnitFramework.zip (101.1 KB, 12,582 hits)
inside the project (not solution) directory.
Text is useful to show scores, game menus, and any other information you may want to share. DirectX supports both 2D and 3D fonts. 2D fonts are represented by the Font class. The Font constructor and the Font.DrawText method contain some parameters that are a bit hard to memorize, so I created my own Font class that encapsulates the Direct3D Font class:
{
public class Font
{
private int m_size;
public enum Align { Left, Center, Right, TopRight, TopLeft, BottomRight, BottomLeft };
/// <summary>Default constructor</summary>
public Font()
}
/// <summary>Create a new font.</summary>
/// <param name=”device”>Direct3D Device</param>
/// <param name=”faceName”>Font face name</param>
/// <param name=”size”>Size of the font</param>
/// <param name=”bold”>true for bold text, false for normal text</param>
/// <param name=”italic”>true for italic text, false for normal text</param>
public Font( Device device, string faceName, int size, bool bold, bool italic )
m_font = new Microsoft.DirectX.Direct3D.Font( device, -size, 0,
( bold ) ? FontWeight.Bold : FontWeight.Normal, 1, italic,
CharacterSet.Default, Precision.Default, FontQuality.Default,
PitchAndFamily.DefaultPitch | PitchAndFamily.FamilyDoNotCare, faceName );
}
/// <summary>Print some 2D text.</summary>
/// <param name=”sprite”>Sprite for batch printing</param>
/// <param name=”text”>Text to print</param>
/// <param name=”xPosition”>X position in window coordinates</param>
/// <param name=”yPosition”>Y position in window coordinates</param>
/// <param name=”textBoxWidth”>Width to constrain text in</param>
/// <param name=”textBoxHeight”>Height to constrain text in</param>
/// <param name=”color”>Color of the text</param>
/// <param name=”alignment”>CUnit.Font.Alignment enum</param>
public void Print( Sprite sprite, string text, int xPosition, int yPosition,
{
{
}
DrawStringFormat format = 0;
if ( textBoxWidth == 0 )
{
}
else
{
switch ( alignment )
{
break;
case Align.Center:
format |= DrawStringFormat.Center;
break;
case Align.Right:
break;
case Align.TopRight:
format |= DrawStringFormat.Right | DrawStringFormat.Top;
break;
case Align.BottomRight:
break;
case Align.TopLeft:
format |= DrawStringFormat.Left | DrawStringFormat.Top;
break;
case Align.BottomLeft:
break;
}
if ( textBoxHeight == 0 )
{
// Make it seem like height is infinite
textBoxHeight = 2000;
}
}
format |= DrawStringFormat.ExpandTabs;
System.Drawing.Rectangle rect = new System.Drawing.Rectangle( xPosition, yPosition, textBoxWidth, textBoxHeight );
m_font.DrawString( sprite, text, rect, (DrawStringFormat)format, color );
}
/// <summary>Print some 2D text.</summary>
/// <param name=”text”>Text to print</param>
/// <param name=”xPosition”>X position in window coordinates</param>
/// <param name=”yPosition”>Y position in window coordinates</param>
/// <param name=”color”>Color of the text</param>
public void Print( string text, int xPosition, int yPosition, int color )
}
/// <summary>Print some 2D text.</summary>
/// <param name=”sprite”>Sprite for batch printing</param>
/// <param name=”text”>Text to print</param>
/// <param name=”xPosition”>X position in window coordinates</param>
/// <param name=”yPosition”>Y position in window coordinates</param>
/// <param name=”color”>Color of the text</param>
public void Print( Sprite sprite, string text, int xPosition, int yPosition, int color )
}
/// <summary>Call after the device is reset.</summary>
public void OnResetDevice()
{
}
}
/// <summary>Call when the device is lost</summary>
public void OnLostDevice()
{
}
}
/// <summary>Call when the device is destrroyed</summary>
public void OnDestroyDevice()
{
m_font = null;
}
}
/// <summary>Gets the font size.</summary>
public int Size
}
}
}
Through the use of a few overloaded methods, the process of creating and printing 2D text is simplified. The Direct3D.Font class constructor contains parameters that we will probably never change, so my Font wrapper eliminates the need to specify these parameters.
The Direct3D.Font.DrawText method is also wrapped up in its own Print method. The Print methods simplify the process of printing and aligning text by setting certain parameters automatically.
/// <param name=”device”>The Direct3D device</param>
/// <param name=”elapsedTime”>Time elapsed since last frame</param>
public override void OnRenderFrame( Device device, float elapsedTime )
{
device.BeginScene();
// Clip…
m_font.Print( “Printing text without a sprite likernthis slows things down a bit.”, BackBufferWidth - 300, BackBufferHeight - 100, Color.ForestGreen.ToArgb() );
// Batch print text with a Sprite is a good optimization
m_textSprite.Begin( SpriteFlags.AlphaBlend | SpriteFlags.SortTexture );
m_font.Print( m_textSprite, sometext, 50, 100, 200, 0, Color.Red.ToArgb(), Font.Align.Center );
m_font.Print( m_textSprite, “We can even align a bunch of text along the right side. Isn’t that neat?”,
BackBufferWidth - 110, BackBufferHeight - (int)( BackBufferHeight / 2 ) - 30, 100, 0, Color.LightBlue.ToArgb(), Font.Align.Right );
m_textSprite.End();
// Clip…
device.EndScene();
device.Present();
}
The above code shows how to use the Font wrapper class to print text in your applications. Notice after the first line of text is printed, a Sprite instance is making a call to Sprite.Begin. When you are making lots of printing calls, using a Sprite increases the performance of your application by a noticeable amount. In my tests, I received as much as a 20% increase in performance by using a Sprite. To take advantage of this Sprite optimization, we simply put all our Print calls in between Sprite.Begin and Sprite.End while passing the sprite in to each Print method.
/// This event will be fired immediately after the Direct3D device has been
/// reset, which will happen after a lost device scenario, a window resize, and a
/// fullscreen toggle. This is the best location to create_ Pool.Default resources
/// since these resources need to be reloaded whenever the device is reset. Resources
/// created here should be released in the OnLostDevice callback.
/// </summary>
/// <param name=”device”>The Direct3D device</param>
public override void OnResetDevice( Device device )
{
// Create the light
device.Lights[0].LightType = LightType.Directional;
device.Lights[0].Diffuse = Color.White;
device.Lights[0].Direction = Vector3.Normalize( new Vector3( -1.0f, -1.0f, 1.0f ) );
device.Lights[0].Update();
device.Lights[0].Enabled = true;
// Set render states
device.RenderState.Lighting = true;
device.RenderState.Ambient = Color.FromArgb( 80, 80, 80 );
// Create our 3d text mesh
m_text3D = Microsoft.DirectX.Direct3D.Mesh.TextFromFont( device, new System.Drawing.Font( “Arial”, 20 ), “C-Unit”, 0.001f, 0.4f );
// Create the material
Material material = new Material();
material.DiffuseColor = ColorValue.FromColor( Color.CornflowerBlue );
material.AmbientColor = ColorValue.FromColor( Color.CornflowerBlue );
device.Material = material;
// Clip…
}
3D text is stored in a Mesh class. A Mesh class is basically an encapsulation of a vertex buffer and an index buffer. Since text in a Mesh is 3D, it is affected by lighting and the world transform matrix, therefore we have to specify a light and a material to view 3D text properly. To create_ the text mesh, we call simply Mesh.TextFromFont. The color of the mesh can be controlled through the specified material of the device.
/// <param name=”device”>The Direct3D device</param>
/// <param name=”elapsedTime”>Time elapsed since last frame</param>
public override void OnRenderFrame( Device device, float elapsedTime )
{
device.BeginScene();
// Clip…
device.RenderState.FillMode = m_framework.FillMode;
device.Transform.World = m_transform.Transform;
// Render 3D text
if ( m_text3D != null )
{
}
// Clip…
device.EndScene();
device.Present();
}
To render the 3D text, all we do is call BaseMesh.DrawSubset.
The Font and Sprite classes have methods, OnLostDevice and OnResetDevice, that need to be called whenever the device is lost or reset. Also, since the Mesh.TextFromFont method creates the mesh in the Pool.Default memory pool, the mesh needs to be disposed when the device is lost by calling Mesh.Dispose. The code for these calls is so small, I didn’t bother to display them here. Check out the source code to see all the resource handling.
The Direct3D Font class is an easy to use interface for printing text. However, pretty much all of the text displayed in the C-Unit Framework does not use the Direct3D Font class. I wrote my own bitmap font system which gives better performance and allows for better looking fonts at the cost of less justification options. You’ll learn about my bitmap font system in a later tutorial.