Direct3D text

Note: to use the D3DX functions you must include the header d3dx9.h and link with d3dx9d.lib (in debug build) or d3dx9.lib (in release mode).

Direct3D comes with a set of interfaces to help you easily draw text to the screen. It is worth knowing how it does it before using it. This is the traditional method used by games developers:

  • Create a texture containing all the letters in the alphabet and numbers etc.
  • Store the position of each letter in this texture (U,V texture co-ordinates)
  • When text needs to be displayed create a screen quad comprising two triangles at the correct position
  • Set the UV co-ordinates to the correct position in the font texture for the required character
  • Repeat for all letters in the word

Direct3D provides a set of interfaces that can do all this for you. It may not be the fastest method in the world so developers do normally create there own (as described above) but it will do perfectly well to start with.

Creating the Interface

As usual you must declare a pointer to the interface object:

LPD3DXFONT m_font;

or

ID3DXFont *m_font;

The D3DXCreateFont function creates a Windows 32 font and uses that to create its characters. This means there are a lot of parameters to this function call allowing a font to be specified. You can look in the DirectX help and at the Windows 32 CreateFont function for the list of parameters. Below is an example of creating a font with 20 point high characters, in bold and using the Arial typeface:

// Create a D3DX font object
D3DXCreateFont( gD3dDevice, 20, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &m_font );

Drawing Text

Now that you have created the font interface object you can use it, so in your render loop after calling BeginScene you could call a function to draw the text e.g.

void DisplaySomeText()
{

    // Create a colour for the text - in this case blue
    D3DCOLOR fontColor = D3DCOLOR_ARGB(255,0,0,255);   

    // Create a rectangle to indicate where on the screen it should be drawn
    RECT rct;
    rct.left=2;
    rct.right=780;
    rct.top=10;
    rct.bottom=rct.top+20;
     
    // Draw some text
    m_font->DrawText(NULL, "Hello World", -1, &rct, 0, fontColor );

}

The format of the draw call is:

int DrawText( LPD3DXSPRITE pSprite, LPCTSTR pString, INT Count, LPRECT pRect, DWORD Format, D3DCOLOR Color );

  • pSprite - the first parameter allows a sprite interface to be passed in. Setting this to NULL means Direct3D will use its own internal sprite object to render the text. If you are doing lots of DrawText calls passing your own sprite object can speed up rendering significantly (see font drawing optimisations below).
  • pString - this is the string to render. The type of string depends on your projects character set.
  • Count -  the number of characters in the string. You can set this to the magic number -1 in order to specify that Direct3D should count the characters itself. Note that this only works with null terminated strings.
  • pRect - the rectangular area in which the text will be displayed. How the text is justified within this rectangle depends on the next parameter:
  • Format - allows you to specify some flags. This allows you to specify the justification of the text within the rectangle plus some other options (see advanced below).
  • Color - the final parameter is the colour you want to render the text.

As always you must release the D3DX interface before your program exits or on a device reset:

m_font->Release();

Advanced

The third parameter to the DrawText function is a flag that allows you to specify justification etc. There is also a very useful flag: DT_CALCRECT that causes DrawText to set the passed rectangle to the size required to display the text. When using this flag DrawText will not actually draw anything, it is purely a way of obtaining the size of the text.

Font Drawing Optimisations

Text drawing can be slow and so there are a couple of optimisations provided by the font interface. Unfortunately these are not very well documented so I decided to carry out some tests of my own to determine some real world values.

I found that passing a sprite object as the first parameter to DrawText improved rendering speeds by up to 4 times - quite a significant improvement.

The sprite interface also provides a function to allow you to preload a text string into video card memory - PreloadText. This should theoretically improve performance as the function would not need to assemble the characters each time and upload them to the graphic card. However from my test results I found little speed improvement.

Further reading

  • Look in the DirectX help for details on each of the parameters to the calls.
  • Details on the sprite interface can be found here: Sprites



© 2004-2016 Keith Ditchburn