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_TOP | Top justify the text. |
DT_BOTTOM | Bottom justify the text. |
DT_CENTER | Center the text horizontally. |
DT_VCENTER | Center the text vertically. |
DT_LEFT | Left justify the text. |
DT_RIGHT | Right 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.