bw logo

Chapter 18. Fonts

BigWorld has an in-built font generation and glyph caching system. It supports large international character sets. Internally, BigWorld uses GDI+ and requires an installed true-type font file to draw the glyphs into a glyph-cache render target. As an alternative, you can ship your game with pre-cached font maps, however this method does not support dynamic glyph usage, and as such is not appropriate for large character sets.

18.1. Creating and Using Fonts

To use fonts, you must first create a font definition file that describes the font style, point size, and desired effects. Once a font is defined, you can use the font to display text on-screen. The main way to display text on-screen is via a Python GUI.Text component.

18.1.1. Creating a Font Definition File

Font Definition Files are an XML file describing the font itself, the size of the glyph cache and the details of any preloaded glyphs :

<example_font.font>
    <creation>
        <sourceFont> Arial </sourceFont>
        <sourceFontSize> 16 </sourceFontSize>
        <effectsMargin>   1 </effectsMargin>
        <textureMargin>   1 </textureMargin>
        <dropShadow>   true </dropShadow>
        <shadowAlpha>   192 </shadowAlpha>
        <bold>         true </bold>
    </creation>
</example_font.font>

Since fonts are generated on-the-fly and their glyphs cached at runtime, this is all you need to do to begin using a new font. If the specified source font name does not exist on the system, then Windows will automatically choose the nearest matching typeface. To avoid any potential problems, please make sure you license and install your desired true-type fonts on the end-users' system (e.g. as part of the installer scripts). If you do decide to choose only Windows fonts (and assume they exist on the end-users' machines) then be aware that there are large differences in the standard fonts used by Windows, depending on the region. For example, if Windows has been installed with the Asian font pack, it will have a significantly different standard font sets by default (even for English language fonts).

See .font for a detailed description of the .font definition format.

18.1.1.1. Secondary Font Families

In order to allow mixing different character sets within the same string of text while maintaining control over how each character set is rendered, secondary font families can be defined. For example, Arial may be desired for latin-1 (e.g. English) characters, however Arial is not designed to render east-Asian character sets (e.g. Chinese). This would mean artifacts are produced when rendering east-Asian characters.

Secondary fonts are defined using one or more secondary tags within the creation section. A secondary font consists of a font name and a Unicode range used to selected which secondary font to use.

For example, to use Arial and Chinese you could add a secondary font using SimSun:

<example_font.font>
    <creation>
        <sourceFont> Arial </sourceFont>
        ...
        <secondary>
            <sourceFont>      SimSun          </sourceFont>
            <unicodeRange>    U+2F00-U+9FFF   </unicodeRange>
        </secondary>
    </creation>
</example_font.font>

18.1.2. Preloading Glyphs

For languages that have a limited number of glyphs, for example English, you may want to preload all the glyphs into the cache so the client doesn't have to do anything more at runtime. Additionally, for larger Asian languages, you may still want to preload the cache with some often-used glyphs and from then on let the cache deal with whichever less-frequently used glyphs are required at runtime. The glyph caching system will still be in effect, but the cache will contain these glyphs to begin with. Additionally, the preloaded glyphs will never leave the cache during the duration of client execution, even if they are not used.

To preload glyphs or a range of glyphs, add any combination of the following tags into your font definition file.

<startChar>    32    </startChar>
<endChar>     192    </endChar>

or

<unicodeChar>  U+3000  <unicodeChar>

and/or

<unicodeRange>  U+AC00-U+D7A3   </unicodeRange>

18.1.3. Specifying the widest character

Font glyphs are cached into a texture and are positioned on a regular grid (i.e. each grid element is the same width and height). In order to determine the size of each grid element up front, the glyph cache must know the dimensions of the widest character. By default the letter 'W' is used to calculate this size but this may be inappropriate for some character sets (including Chinese). If the widest character is too narrow, then visual artifacts will occur (characters will be clipped and neighbouring characters may 'leak' into each other). If it is too wide, then texture space will be wasted.

The widest character can be set using the <widestChar> tag in the font definition file. For example:

<example_font.font>
    <creation>
        ...
        <widestChar>  U+FF1F  </widestChar>
        ...
    </creation>
</example_font.font>

18.1.4. Displaying Text

Text GUI Components are the main way that fonts are used to display text on-screen. For full details on Text GUI Components and their python GUI.Text counterpart, please refer to the Python Client API guide, under the section GUI.Text. The GUI.Text class supports the "font" attribute, this specifies the name of the font definition file, relative from the font root (see File Grammar Guide / resources.xml to see how to choose or change the font root folder.)

Here is an example of how to use the above example font file, which for now we will assume was saved to $FONT_ROOT/example_font.font.

import GUI
t = GUI.Text( "Some Text" )
t.font = "example_font.font"
GUI.addRoot(t)

18.2. Artist modified Fonts

Built-in or licensed true-type fonts may not necessarily have to desired look for your game. For example you may want to use fonts that have a glow effect, or an internal gradient fill. In these situations, you have the choice to output a fixed snapshot of a glyph cache as a .dds file. This file can then be processed by an artist to generate whatever font effects they like. Note that this procedure will only work with a fixed set of glyphs, as the client will not internally posess the ability to recreate the steps the artist took to modify the font.

18.2.1. Generating a Snapshot of a Font's Glyph Cache

The python API contains a function, BigWorld.saveFontCacheMap, that outputs the contents of the font's glyph cache to a DDS file, and the details of the font metrics to the .font file. Once this snapshot is taken, the .font file contains a <generated> section, and the font will no longer use the glyph cache, or be able to generate any new glyphs at runtime. To revert this change, simply remove the <generated> section from the .font file, and delete the .dds file. The texture will be named $FONT_ROOT/$FONTNAME_font.dds

import BigWorld
BigWorld.saveFontCacheMap( "super_turbo.font" )
#this generates super_turbo.font.dds, super_turbo.font.generated, and super_turbo.font.grid.dds

18.2.2. Modifying the Font Texture

Once a snapshot has been created, the generated font .dds file can be loaded into Photoshop (you may need to download and install a .dds file plugin, depending on the version of Photoshop you are using). The glyphs can then be modified freely, however care must be taken not to go outside of the designated bounds for each character. The grid reference bitmap describes the go and no-go areas, and its alpha-channel has a copy of the glyphs to provide shape information and to simply demonstrate which character goes where.

Once you have modified a font texture, simply save over the *.font.dds file, and make sure both it and the *.font.generated file is committed as part of your asset repository. The presence of these files on disk instructs the font system to use the generated map from now on, and never attempt to expand the glyph cache. If glyphs are encountered that do not exist as part of the generated glyph cache, a warning will be output to the debug window and a filler character will be used.

18.2.3. Explaining the Font Grid .dds File

Below is a portion of a font.grid.dds file, duplicated 3 times in photoshop with various colour channels extracted. You can see the three colour channels, with the alpha channel overlayed in white.

Example extracted from a .font.grid.dds file

On the left, the red channel describes the raw glyph rectangle as given by GDI+. As you can see in the example, the W and / glyphs go outside of this region. This is because this particular font already has a drop-shadow applied. The drop shadow, as provided in-engine, is a copy of the glyph, with a single pixel offset. This is demonstrated by the green region below.

The green region describes the glyph region plus the effect margin, and is the rectangle that will be drawn by the engine. Any pixels outside of the green area will be clipped when drawing text to the screen. Note too that when glyphs are drawn together, creating a string or a sentence, the red regions (raw size) determine the spacing between characters, and any effects margin is overlapped by the next glyph, this ensures that adding effects like drop shadows do not increase the width of your strings.

The blue region describes the glyph region plus effect margin plus texture margin. The texture margin is used to pad the glyphs apart in the texture map, to avoid any filtering artifacts. The texture margin should never be drawn, and is pretty much wasted space. If you are sure that your font will only be drawn at a 1:1 ratio between pixels and texels (for example the text will never be shrunk, or drawn in 3D where it can be rotated and mip-maps come into play), then you can safely do away with any texture margin.