MULTIMEDIA

DirectX 10 Game Programming : Direct3D Fonts

2/7/2012 9:16:30 AM
Even though it may seem like a fairly simple matter to implement your own font system, there are multiple problems that would take a while to overcome; luckily, you don’t have to worry because Direct3D already has a font system built in. The Direct3D font system, while sprite-based, doesn’t require you to create your own font texture. The fonts used by Direct3D are created using the fonts installed under Windows. This system also allows for the text to be drawn at multiple point sizes without the need to scale the sprites. This gives a crisper, cleaner look to the text.

The Direct3D font system is based upon functionality provided by the ID3DX10Font interface. This interface provides all the functions needed for text drawing.

Creating the Font Object

Before you can use the functionality in the ID3DX10Font object, it has to be instantiated; this is done using the D3DX10CreateFont function. During the font creation process, a texture is created that contains the letters and symbols in the font. When calling the D3DX10CreateFont function, you specify the font face, size, and weight that will be contained in the texture.

HRESULT D3DX10CreateFont(
ID3D10Device* pDevice,
INT Height,
UINT Width,
UINT Weight,
UINT MipLevels,
BOOL Italic,
UINT CharSet,
UINT OutputPrecision,
UINT Quality,
UINT PitchAndFamily,
LPCSTR pFaceName,
ID3DX10Font** ppFont
);

The D3DX10CreateFont function requires twelve parameters.

The first parameter is a pointer to the Direct3D device in use. The second and third parameters dictate the width and height of each of the letters in the font. The width and height are changeable only when the font is first created.

The fourth parameter is the font weight. The font weight is the thickness of the lines. Direct3D provides the following weights:

  • FW_DONTCARE

  • FW_THIN

  • FW_EXTRALIGHT

  • FW_LIGHT

  • FW_NORMAL

  • FW_MEDIUM

  • FW_SEMIBOLD

  • FW_BOLD

  • FW_EXTRABOLD

  • FW_HEAVY

The fifth parameter, MipLevels, allows you to designate the number of levels the resulting font texture will have. More mip levels increase the readability when the text is further away.

The sixth parameter allows you to create an italic font. This variable is either true if italic or false otherwise.

The seventh parameter dictates the character set the font will use. By specifying anything other than DEFAULT_CHARSET, you can create fonts based on character sets from other languages such as Chinese.

The next three parameters determine the precision, quality, and font pitch. The precision and quality help map the selected font size to existing Windows fonts. Default options are available for each of these settings.

The most important parameter passed to the D3DX10CreateFont function is pFace Name. This variable is used to set up the actual font to be used. Examples of font face names are Helvetica, Verdana, and Times New Roman.

The last parameter is the actual output variable. When the call to D3DX10Create Font completes, this last parameter is used as a pointer to the ID3DX10Font object.

Note

Most of the options available to be sent into the D3DX10CreateFont function can be found in the wingdi.h header file.


The following example shows how to use the D3DX10CreateFont function.

/*******************************************************************
* InitFont
* Initialize the font object
* Inputs - void
* Outputs - bool - true/success, false/failure
*******************************************************************/
bool InitFont()
{
HRESULT hr = D3DX10CreateFont(pD3DDevice,
35, // the font height
0, // the font width
FW_BOLD, // the weight of the font
1, // number of mip levels
FALSE, // this is not an italic font
DEFAULT_CHARSET, // default character set
OUT_DEFAULT_PRECIS, // default size mapping
DEFAULT_QUALITY, // default quality mapping
DEFAULT_PITCH | FF_DONTCARE, // default pitch
L"Helvetica", // use Helvetica as the basis for this font
&pFont); // the output

// make sure the font was created correctly
if (FAILED(hr))
{
return false;
}
return true;
}


DrawText

Drawing text to the screen using the ID3DX10Font object functionality is simple; the member function DrawText does all the work. DrawText takes the string you provide and creates a series of sprites containing the text. The sprites use the font texture you created previously.

The DrawText function is simple to use; its parameters and usage are explained next.

Since the text is rendered using a series of sprites, the first parameter to the DrawText function is a pointer to the ID3DX10Sprite object that should be used. If you want DrawText to create and use its own sprite object, pass in NULL.

The next two parameters specify the string and its length. You can either pass in the number of characters in the string or pass –1 if the string is null terminated.

The fourth parameter is a pointer to a RECT structure detailing the draw area. The RECT structure lets DrawText know the extents of the area the text will be drawn to.

The fifth parameter, Format, is the most confusing. This parameter specifies how the text should be aligned when drawn. Options such as left align, centered, and top justify are available. The text formatting options are as follows:

DT_TOPTop justify the text.
DT_BOTTOMBottom justify the text.
DT_CENTERCenter the text horizontally.
DT_VCENTERCenter the text vertically.
DT_LEFTLeft justify the text.
DT_RIGHTRight justify the text.

Format also contains some options that aren’t specifically used to position the text.

  • DT_CALCRECT— By setting the format to use this option, the RECT structure passed to the fourth parameter will be set with the correct size values for the text. When using this option, the text is not actually drawn. This is a great way to determine the size of the rectangle needed though.

  • DT_NOCLIP— No matter the size of the rectangle passed to the DrawText function, all the text will be drawn. This disables clipping of text that would normally fall outside the draw rectangle area.

  • DT_WORDBREAK— Words are split onto multiple lines if they extend past the draw area.

  • DT_SINGLELINE— Even if the text contains line feeds, this draws the text on a single line.

The final parameter to the DrawText function is the color in which the text should be drawn.

An updated Render function and helper function—GetFontRectangle, which demonstrates the DrawText functionality, are shown next.

/*******************************************************************
* Render
* All drawing happens in the Render function
* Inputs - void
* Outputs - void
*******************************************************************/
void Render()
{
if (pD3DDevice != NULL)
{
// clear the target buffer
pD3DDevice->ClearRenderTargetView(pRenderTargetView, D3DXCOLOR(0.0f,
0.0f, 0.0f, 0.0f));

// Create and Initialize the destination rectangle
RECT rc;
SetRectEmpty(&rc);

// Use the GetFontRectangle helper function to get the proper size of
the rectangle.
GetFontRectangle(TEXT("This is a test string"), &rc);

// Draw the text to the screen
HRESULT hr = pFont->DrawText( NULL,
TEXT("This is a test string"),
-1,
&rc,
DT_LEFT,
D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
// display the next item in the swap chain
pSwapChain->Present(0, 0);
}
}
/*******************************************************************
* GetFontRectangle
* Resizes the font's destination rectangle
* Inputs - LPCWSTR, the text that will be drawn
* RECT, pointer to the rectangle to return
* Outputs - void
*******************************************************************/
void GetFontRectangle(LPCWSTR text, RECT *rect)
{
// Using DT_CALCRECT causes the rectangle to be determined but
// not to be drawn
pFont->DrawText(NULL,

text,
-1,
rect,
DT_CALCRECT | DT_LEFT,
D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f));
}


The GetFontRectangle function is used to calculate the proper rectangle size for the text. This requires two calls to the DrawText function, but makes sure the rectangle is always accurate. Figure 1 shows an example of Direct3D font drawing.

Figure 1. Direct3D font drawing.


Other  
  •  DirectX 10 Game Programming : Adding Text & Creating a Font System Using Sprites
  •  Adobe InDesign CS5 : Importing Graphic Objects (part 3) - Using the Image Import Options Dialog Box
  •  Adobe InDesign CS5 : Importing Graphic Objects (part 2) - Importing Graphics with the Place Command
  •  Adobe InDesign CS5 : Importing Graphic Objects (part 1) - Understanding Adobe Bridge
  •  Building a WPF Application without XAML (part 2)
  •  Building a WPF Application without XAML (part 1)
  •  iPhone 3D Programming : Drawing an FPS Counter (part 2) - Rendering the FPS Text
  •  iPhone 3D Programming : Drawing an FPS Counter (part 1) - Generating a Glyphs Texture with Python
  •  Programming with DirectX : Game Input - XInput
  •  Programming with DirectX : Game Input - Win32 Input
  •  Introducing Windows Presentation Foundation and XAML : Investigating the WPF Assemblies
  •  Introducing Windows Presentation Foundation and XAML : The Motivation Behind WPF & The Various Flavors of WPF
  •  Microsoft XNA Game Studio 3.0 : Getting the Date and Time
  •  Microsoft XNA Game Studio 3.0 : Text and Computers
  •  Silverlight Recipes : Managing Embedded Resources
  •  Silverlight Recipes : Managing XAML Resources
  •  Silverlight Recipes : Updating the UI from a Background Thread
  •  Programming with DirectX : Sound in DirectX - XAudio2
  •  Programming with DirectX : Sound in DirectX - XACT3 (part 2) - XACT3 Demo
  •  Programming with DirectX : Sound in DirectX - XACT3 (part 1) - XACT3 Tools
  •  
    Top 10
    Expert computing advice (Part 1) - Autorun worm, Sketching software & Two networks, one router
    Mixing Windows and Forms
    MySQL Server Monitoring (part 3) - Server Logs, Third-Party Tools & The MySQL Benchmark Suite
    SQL Server 2008 : Using the CLR - Understanding Permission Sets
    Algorithms for Compiler Design: THE LR PARSER
    Personalizing Windows 7 (part 5) - Choosing Your Mouse Pointers
    Windows 7: Managing Software Once It’s Installed (part 3) - Viewing and Managing Startup Programs
    Get Network Card Information
    Exchange Server 2010 : Perform Essential Database Management (part 2) - Manage the Transaction Log Files
    Windows Server 2008 R2 Active Directory Domain Services Primer : Explaining AD DS Replication
    Most View
    Understanding IIS 7.0 Architecture : Request Processing in Application Pool
    SharePoint 2010 : Implementing Authentication Scenarios
    Windows Server 2008 : Understanding the Identity Management for UNIX Components
    Understanding Exchange Policy Enforcement Security : Creating Messaging Records Management Policies
    Windows Server 2008: Using OUs to Delegate Administration
    Programming with DirectX : Shading and Surfaces - Types of Textures
    Choosing a super-zoom camera (part 6)
    Windows Server 2008 R2 Active Directory Domain Services Primer : Understanding Domain Trusts
    IIS 7.0 : Managing Configuration - Delegating Configuration (part 1)
    Programming .NET Security : Extending the .NET Framework (part 1) - Defining the Key Exchange Formatter
    Algorithms for Compiler Design: SWITCH/CASE
    Introducing Role-Based Security in .NET
    Transact-SQL in SQL Server 2008 : GROUP BY Clause Enhancements
    Managing Exchange Server 2010 : The Exchange Management Shell (part 1) - Bulk user creation in the Exchange Management Shell
    .NET Micro Framework : Weak Delegates
    Becoming an Excel Programmer : Where's My Code?
    Algorithms for Compiler Design: Implementation
    Programming Microsoft SQL Server 2005 : FOR XML Commands (part 1) - FOR XML RAW & FOR XML AUTO
    SharePoint 2010 : Operations Management with the SharePoint Central Administration Tool (part 5) - Reviewing Security Settings in SPCA
    CPU System Workshop (Part 1)