Font file

From Stunts Wiki
Revision as of 22:56, 18 March 2021 by Cas (talk | contribs) (→‎Glyphs)

Stunts (BB 1.1) includes three font files, which have a ".FNT" extension and a very unique format. The files in question are FONTDEF.FNT, FONTN.FNT and FONTLED.FNT. FONTDEF (probably standing for "Default Font") is the thick font used for the text in menus, dialog boxes and buttons. FONTN is used for longer text, for example, car descriptions in the showroom, scoreboard rows and the high score information when viewing the complete track in 3D in the Track menu. FONTLED only contains digits and a couple of punctuation characters and is used for the lap times in the replay menu panel.

While this font format appears to be unique to Stunts, it is pretty flexible and worth considering for other projects. The three fonts included with Stunts are bitmaps of character height 8, but vary in width. As a matter of fact, FONTDEF and FONTN are variable width, that is, each character can have an individual width. Yet, Stunts allows for fonts of other characteristics to be loaded. If the files are modified, Stunts adapts to the changes very well.

Font format features

Stunts font format is strictly bitmap based, but very configurable. It allows for up to 256 characters that can be mapped to 256 code points from 0 to 255. Unused code points don't need to have their glyphs defined, which saves space. Fonts can have either fixed or variable width. For variable width, widths up to 255 are theoretically possible, although Stunts surely must have a much smaller limit. With fixed width, this could go up to 32767 or perhaps 65535 depending on how the values are interpreted. Character height can also, in theory, go up to these values. As of 18 March 2021, it is not known whether height can be made variable too.

Format structure

After an analysis made by Cas on 17 March 2021, the font format was found to have the following structure:

Header

  • (1 byte) Fixed = 3
  • (11 bytes) Fixed: all zeroes
  • (1 word) Not fully understood: 1 or 2 for variable width, but has to be 1 for fixed width
  • (1 word) Font height
  • (1 word) Font width (if width is variable, this is zero)
  • (1 word) Unknown: Always 8 in the three original fonts and doesn't seem to do anything if changed
  • (1 word) Variable width flag: 1 for variable width, 0 for fixed width

Total: 22 bytes

Index

Following the 22-byte header, comes the index. It's exactly 256 words long (512 bytes) and each word points to the position in the file where the glyph is defined for each code point from 0 to 255 in order. If a glyph is not defined for a certain code point, its index is set to zero. Valid indeces count from 0 at the beginning of the file. This means that position 534 (starting from 0) is the first byte in the file available for glyph definition and is used as such in the three fonts originally provided with Stunts. This could, however, be skipped freely and additional information stored there.

Glyphs

For each code point with a non-zero index, a glyph has to be defined. If the font is variable width, the first byte in the glyph region contains the character width in pixels. For fixed width fonts, this byte is omitted. Following are the glyph rows. The number of bytes to represent each row depend on the character width. One byte is required for every 8 pixels. In other words, the number of bytes per row will be the ceiling of the division of the character width by 8. Stunts fonts go over 8 pixels wide, but never reach 17, so it is not known if it supports wider fonts, yet the format allows for defining them.

Pixels in each row are defined in ascending order (from lower bit to higher bit) from right to left and can be 0 for off or 1 for on. If more than one byte is used, the format is little-endian. Unused bits are left as 0 in original Stunts fonts, which is a good practice. In theory, they should be ignored anyway.

Each row is followed by the next immediately after without any separation other than the bits to complete the exact number of bytes, so glyphs are generated from the top down.