Dynamix Font Format v2-v3
A 1-bpp font with the file header specifying the global width and height for all symbols, the start symbol and the amount of symbols. The existence of the start symbol means it is optimized by only saving the used range of symbols. Typically, the first symbol code is 0x20 (32), the space character. A font with a full uppercase set has a count of at least 0x40 (64) while a font with an upper/lowercase set has a count of at least 0x60 (96).
The v2 and v3 types are identical, except that the v3 one is embedded in a "FNT" chunk of the typical Dynamix chunk format: a 3-character ID string, followed by a ':', followed by the chunk size in UINT32LE format, in which the highest bit is reserved for a flag indicating whether the chunk embeds chunks inside itself (which this "FNT" one does not), followed by the chunk data. The following explanation details the structures inside that chunk data, meaning all calculations of offsets should compensate for the extra 8 bytes at the start when reading a v3 font.
The font format starts with the following 4-byte header:
|0x00||UINT8||FontWidth||Font symbol width, in pixels.|
|0x01||UINT8||FontHeight||Font symbol height, in pixels.|
|0x02||UINT8||StartSymbol||Start symbol. Symbols lower than this are not saved in the font file. Usually 0x20|
|0x03||UINT8||NrOfSymbols||Number of symbols in the font file. Since this is a byte, the font is limited to a maximum of only 255 symbols, and not the full 256. However, since C-style strings end with byte 0x00, index 0 is technically useless, and can be skipped to get the full real range.|
This is followed by raw blocks of 1-bpp data for the actual symbols, as determined by the header. Each line of a symbol is the width in bits rounded up to the next full byte, in bytes, which can be calculated as
stride = ((FontWidth + 7) / 8). Multiply that by the
FontHeight to get the size of one symbol. There should be
NrOfSymbols of these blocks, meaning the file size can perfectly be calculated as
HeaderSize + (stride * FontHeight * NrOfSymbols), with
HeaderSize being 4, as detailed above.
Note that the
stride may exceed one byte if the width in the header is greater than 8. Some existing systems simply interpret the symbol size as being equal to the height, but since the format supports widths greater than 8 pixels this is a dangerous simplification that should never be used.
To validate the font and correctly identify it, some other simple checks can be done. The most obvious one is that the amount of symbols plus the start symbol cannot exceed 256. Another one is that the later Dynamix fonts use the first byte as version, using values 0xFF and 0xFD to indicate respectively v4 and v5. This means that, for convenience, and because no officially released files ever have a width exceeding 127, the font dimensions could be interpreted as signed bytes.
The actual font data is 1 bit per pixel. To find a particular symbol, look at the following position in the
(symbolCode - start) * symbolSize
The 6x6.FNT font included in Heart of China starts at symbol code 0x20 and has a size of 6x6 pixels, giving it a symbol size of 0x06. For symbol code 0x42 (66, letter B) the position would be:
0x04 + (0x42 - 0x20) * 0x06 = 0xD0 (208)
The data at this location is:
70 48 70 48 70 00
The font is just a basic raster bitmap using 1 bit per pixel:
70: .111.... 48: .1..1... 70: .111.... 48: .1..1... 70: .111.... 00: ........
If the width is less than the full 8 bits shown here, the remaining bits on the line are simply ignored, and the graphics are cut off at the actual width specified in the header. The format does not use partial bytes to compact the data; as mentioned before, lines are always rounded up to the next full byte.
The following tools are able to work with files in this format.
|Name||Platform||View images in this format?||Convert/export to another file/format?||Import from another file/format?||Access hidden data?||Edit metadata?||Notes|
|Westwood Font Editor||Windows||Yes||Yes||Yes||N/A||N/A|