Dune 2000 Font
Format type | Font |
---|---|
Max glyph count | 255 + space (width only) |
Minimum glyph size (pixels) | 0×0 |
Maximum glyph size (pixels) | 2147483647×2147483647 (space symbol: 255×0) |
Access mode | Sequential |
Metadata? | None |
Bitmap glyphs? | Yes |
Vector glyphs? | No |
Compressed glyphs? | No |
Hidden data? | No |
Games |
The font used in Dune 2000 is an 8-bpp font with individual widths and heights per symbol. It seems to contain a lot of mechanisms meant for optimizing, but the final format doesn't seem to use any of them as they were intended, resulting in a contrived format with a needlessly bloated header.
Despite the fact Dune 2000 is officially a Westwood Studios game, this font is not a new version of the Westwood Studios font format. In reality, the game was outsourced, and this format is designed by Intelligent Games, the real creator of the game.
Note that Dune 2000 is not a DOS game. This font format is included on this wiki for the sake of completeness in the scope of documenting all indexed graphics formats in the Westwood Studios games.
File format
The format is a bit of a mess; while it saves the width of the space character instead of its image data, and has a start symbol and a way of compacting the used symbol codes, it has no way to set the amount of used symbols, making all that optimisation completely irrelevant. Instead, it always contains 256 symbols, starting at index 0x21, just after the space character, wrapping around to zero after 0xFF, and going back up to 0x20 after that. This final symbol for index 0x20 should be ignored, and should be replaced by a space character generated from the width in the header. The header is also polluted with a dump of 256 completely irrelevant 32-bit memory addresses, which are probably leftovers of the saving process.
These specifications were originally researched by Roman "Siberian GRemlin" Lotchenov.
Header
Offset | Data type | Name | Description |
---|---|---|---|
0x00 | UINT8 | FontLoadedFlag | Always 0x01. Siberian_GRemlin's analysis marked this as "Must be $00", but the actual files contradict that. |
0x01 | UINT8 | SpaceWidth | Width of the space character, in pixels. Strangely enough, this is a single byte, while the sizes of the other symbols are defined as 32-bit integers. |
0x02 | UINT8 | FirstSymbol | Always 0x21; start after the space. Given the fact the space is specifically saved in the header, is it probably not a good idea to change this, since this may determine which symbol gets generated from the space width instead of from the font's image data. |
0x03 | UINT8 | Padding | Amount of pixels to add between each symbol when displaying it. |
0x04 | UINT8 | FontHeight | Overall font height, in pixels. This also seems to serve as maximum for the symbol heights, but it is unknown if the game enforces that in any way. |
0x05 | UINT8 | Unused05 | Unused (0x00) |
0x06 | UINT8 | Unused06 | Unused (0x00) |
0x07 | UINT8 | Unused07 | Unused (0x00) |
0x08 | UINT32LE[0x100] | DataOffsets | Leftover memory dump. Ignore. This space might be used by the game to store the address for each symbol after loading the font into memory. |
Image data
The image data starts at offset 0x408, and is an array of 256 structs containing the width, height and image data of each symbol. Given the variable size of the images, and the lack of index, this array can only be read sequentially.
Offset | Data type | Name | Description |
---|---|---|---|
0x00 | INT32LE | SymbolWidth | Symbol width. |
0x04 | INT32LE | SymbolHeight | Symbol height. |
0x08 | BYTE[SymbolWidth * SymbolHeight] | SymbolData | Symbol data. |
As noted before, these start at FirstSymbol
(which should be 0x21), and wrap around to 0 after reaching 0xFF. Given the symbol code compacting detailed in the next section, the sanest way to read these is probably indeed to apply the wraparound and order the symbols correctly.
Note that the data contains 256 entries; there is in fact a final entry in there for the space, but it should be a 0×0 pixels entry without symbol data. This entry should be ignored, since the real space is only defined by the SpaceWidth
in the header.
Symbol code compacting
An important note when editing this format is that the symbol codes do not correspond to any known text encoding. They are in fact a compacted version of Windows-1252 encoding, which uses an external mapping file to look up the actual index in the font data. These mappings can be found in FONT.BIN, which is located in the game's Data\BIN\ folder.
FONT.BIN is a very simple 0x100-byte remap file. If you want to find, for example, the symbol "é", which has symbol code 0xE9 in the Windows-1252 encoding, you look at the offset 0xE9 in FONT.BIN, and will see that the value there is 0x8D, meaning the "é" character in the font file is on the location indicated by code 0x8D (with the aforementioned start symbol and wraparound taken into account). Any unsupported symbols in the file are mapped to the space character (0x20). This also means that, to add new symbols into the font, this mapping table needs to be edited, otherwise the newly added symbols will never be used by the game.
In the Westwood Font Editor, the mapping problem is remedied by adding the default FONT.BIN mapping as specific "Dune 2000" choice in the text encodings list. However, to properly edit the fonts and unlock all characters, the whole system could be disabled simply by replacing FONT.BIN by a file with bytes ranging from 0x00 to 0xFF, and rearranging the symbols in the fonts themselves to match normal Windows-1252. Nyerguds released a small pack on his website containing the adapted mapping table and fonts.
Tools
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 | |
Engie File Converter | Windows | Yes | Yes | Yes | N/A | N/A | Was added to Engie to allow creation of font sheets. |