Thursday, May 23, 2013

Rendering Text



Rendering Text in DX11 is not as easy as it used to be with the previous DirectX versions. Earlier there was an existing interface which handled this. Now it's all DIY.

The whole process is pretty simple actually. All you need is the the font texture sheet, and some quads with UV coordinates mapped to each letter on the font texture sheet, and you're all set. Now the question is, how do we get the font texture sheet? One answer is BMFont. The following link has the executable which can generate any font texture sheet you want

http://www.angelcode.com/products/bmfont/

I created a simple Arial sheet with all the letters, numbers and special symbols. The good thing about this software is that it creates a font info file which contains information about each character, like UV coords, spacing, kerning etc.

Once you generate the Texture sheet(s) and the font file, all you need to do is parse this in the engine.

Here's and example


info face="Arial" size=32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 outline=0
common lineHeight=32 base=26 scaleW=256 scaleH=256 pages=1 packed=0 alphaChnl=1 redChnl=4 greenChnl=4 blueChnl=4
page id=0 file="Arial_0.dds"
chars count=191

char id=32   x=253   y=27    width=1     height=1     xoffset=0     yoffset=0     xadvance=8     page=0  chnl=15
..
..
..
kernings count=91
kerning first=32  second=65  amount=-2  
...
...
..

First step is to parse this file based on the info. Easiest thing to do is read the file line by line, split each line into words, and process it. You also have an option to create the file in XML format, so if you want to get fancy and use an XML parser, that's possible too.

You have the following sections :
  1. Info
  2. Common
  3. Page
  4. Characters (id is the ASCII Code)
  5. Kernings (first and second are ASCII Codes and amount is the space adjustment)
I mainly used the page information which contains the texture file names, and the characters info with kerning info. Kerning basically helps us adjust the spacing between two characters in the string. If you notice in printed media, the spacing between 2 characters is different. Kerning Data is used to specify the spacing between any 2 characters

I created a Font Manager class, and anytime I needed to render text, all I did was specify the font , the string to be printed, and the position (normalized between 0-1) and this gets added to a list in the Font Manager. This was done at any time during the render scene time. Once all the rendering is done, the Font Manager renders all the strings. Following is the logic

-For each string to be rendered
--Get Font Type Info
--Set currPosition to specified location
--For each texture sheet
---For each character in string
----If character is in current texture sheet
-----Create quad based on character settings from starting location
-----Specify UV coords from character settings
-----Update currPosition based on character settings, spacing, and kerning between current and next character

I implemented my own push buffer, in which I can push quads along with UV's to a dedicated buffer, and then render all of them at once. It brings down the cost of rendering many quads.

If you want to get more fancier, you could implement the following
- left, center, right justification
- Multi-line string

With this feature, I can render the amount of time taken in a single frame.