Call of Duty: Font System

From COD Modding & Mapping Wiki
Jump to: navigation, search
Call of Duty 2, 4 and 5 seem to use the same font system with identical file structure specifications. Call of Duty 1 is way different, it uses a combination of .dds images and .dat files and has not been investigated yet. Therefore, this article focuses on the font system from CoD2 on.

Font related files

A font is made up of 4 files:

  1. image (*.iwi)
  2. material
  3. material_properties
  4. font mapping

The material and material_properties files belong to the image, like for every other iwi. The font mapping file references itself, the material file and maps the letters in the image to the ascii (respectively unicode) characters, used in the string files (raw\[LANGUAGE]\localizedstrings\*.str). The material_properties file is implicitly associated with the material by the engine and doesn't require an explcit reference.

The main font of CoD4 is gamefonts_pc. It is located in main\localized_english_iw00.iwd --> images\gamefonts_pc.iwi. The image contains 7 different fonts (background is actually transparent):

CoD4 gamefonts pc.png
Font name size (hex) size (dec) UI font type constant Value
smallFont 0x0A 10 UI_FONT_SMALL 3
normalFont 0x10 16 UI_FONT_NORMAL 1
consoleFont 0x10 16 UI_FONT_CONSOLE 5
boldFont 0x10 16 UI_FONT_BOLD 4
bigFont 0x18 24 UI_FONT_BIG 2
objectiveFont 0x23 35 UI_FONT_OBJECTIVE 6
extraBigFont 0x30 48 - -
- - - UI_FONT_DEFAULT 0 (auto-chose betwen big/reg/small)

These are the settings of the font material in Asset Manager:

CoD4 gamefonts pc AssMan.png

File specifications

The structure of a font mapping file is like this:

Header (16 bytes)
int font_name_offset;		// string at the end of the file (self reference?)
int font_size;			// in pixels
int number_of_records; 	// 1 record = 1 character
int font_material_offset; 	// material name string (matrial references font image)

Entry (24 byte each)
byte char_code[2];		// ascii/unicode mapping of the character
byte char_spacing[3];		// margin left, top, right
byte char_dimension[2];	// pixel width & height
byte empty;			// always 0x00 in stock game fonts
float char_rectangle[4];	// image dimension * float = coord, one rectangle per char

string font_name;		// e.g. "fonts/normalFont"
string font_material;		// e.g. "fonts/gamefonts_pc"

A character record in detail (margin and dimension = pixels):

BYTE[0,1] == character code (2 bytes for asian languages such as Chinese Japaniese and Korean,so-called double-byte character set (DBCS) )
BYTE[2]   == margin left
BYTE[3]   == margin top
BYTE[4]   == margin right (actually more like padding, necessary because the game uses non-monospaced fonts)
BYTE[5]   == width
BYTE[6]   == height
BYTE[7]   == unknown (no visible change, always 0x00 in stock font files)
BYTE[8-11]  == (float) UV of left side of the bounding rectangle of the char (from top left of image)
BYTE[12-15] == (float) UV of top of the bounding rectangle
BYTE[16-19] == (float) UV of right side of the bounding rectangle
BYTE[20-23] == (float) UV of bottom of the bounding rectangle

Structure in FastFile:

FF FF FF FF  separator
23 00 00 00  font size
B8 00 00 00  number of records
29 CB 00 30  ?
69 CB 00 30  ?
FF FF FF FF  separator
66 6F .. 00  font name (e.g. fonts/objectiveFont)
20 00 00 ..  character records 24 bytes each

You need to calculate font_name_offset and font_material_offset if you want to create a font file from the fastfile data:

font_name_offset = 24 * number_of_records + 16

font_material_offset = font_name_offset + sizeof(font_name_offset)


File relations

In the font file are two strings (character arrays) at the end. One of them is the filename of the material. In the material file is another string to the actual image file (iwi). It references like this:

font file --> material --> iwi

The glyph (character) entries in the font file store the information, which pixels in the iwi are a letter (plus some other data). That's what i call "mapping". It maps common digital letters via their ascii codes to image data. This image data is a portion of the iwi. The so called UV coords tell the game what to "cut out" of the iwi and use as letter ingame. It actually uses small pictures and no computer text.

UV mapping

Wikipedia: UV mapping

U and V are variables like X and Y for coordinates. In 3D it would be UVW (compare to XYZ). XY is for a point in 2D space, UV is similar, but for texturing.

The special thing about UVs is, that they are floating point numbers relative to the image (iwi) dimension.

See here:

UV mapping.jpg

(0,0) is the coord in the top left corner. (1,1) is the bottom right corner. The first number is for the vertical direction (left to right), the second for the horizontal (top to bottom). Thus the generalized UV coord is (u,v).

In case of the CoD fonts, UVs can't be greater than 1 and have to be equal to or be larger than 0. The coord (0.5,0.5) is exactly the center of the image, no matter what height and width the image has. To calculate the UV into pixels, you multiply one image dimension by the appropriate UV value.


width  = 512
height = 1024
U = 0.5
V = 0.5

X = width  * U =  512*0.5 = 256
Y = height * V = 1024*0.5 = 512

coord in pixels: (256,512)

Dimension & margin

The UV coord cuts out the letter of the image only. The height and width in pixels define how large it will actually be ingame. It should usually be 1:1, so no re-scaling.

The margin is sort of similar. It's used to position the letters. Because the game does not use a mono-spaced font, it needs to know how much space it is supposed to leave between the current letter and the following (right padding). A mono-spaced font is if all letters have the same width. But that's not the case here, so the engine needs to know how much padding/margin/spacing is required to stick the letters to a word together without having unregular spaces. They have to be next to each other with a little free space between them to look good. so the margin positions the letters, it refines the spacing for a text (many letters).


Data.png Download Regolith's CoD Font Explorer

--CoDEmanX 00:23, 6 July 2009 (UTC)