Timothy S. Singer took the time to write down the complete
FNT file specs using the Descent 1 Source code. I have been chewing on the Descent font
file format, and I now know enough to post what I know, but there is still more to know.
Remember: dword = 32 bits unsigned, short = 16 bits
unsigned, uchar = 8 bits unsigned
struct fontfile
{
char file_id[4] = "PSFN"; //"Parallax Software FoNt"
dword data_size; //file size - 8
struct font_header header; //Header info for font
char data[data_size - sizeof(header)];
};
|
If the font is a color font, then a palette will follow
data[] (but the size is not included in data_size).
struct font_header
{
short ft_w; // Width of
a character in pixels (for proportional fonts use max width)
short ft_h; // Height of
a character in pixels
short ft_flags; // a combination of FT_COLOR=1 |
FT_PROPORTIONAL=2 | FT_KERNED=4
short ft_baseline; // The baseline of the font (top pixel is
#1). Usually the same as ft_h
uchar ft_minchar; // The first character defined in the font
uchar ft_maxchar; // The last character defined in the font
short ft_bytewidth; // For proportional fonts this is usually 0.
For fixed fonts this is ft_w/8.
dword ft_data; // Offset to raw font data
from beginning of this struct
dword ft_chars; // Reserved - must be 0.
This is set by the Descent program at load-time.
dword ft_widths; // If FT_PROPORTIONAL is set, then
this is the offset to the width table.
dword ft_kerndata; // If FT_KERNED is set, then this is the offset
to the kerning table.
};
|
The data, width table, and kerning table are all found in
fontfile.data[].
This is just an array of shorts specifying the width in
pixels of the corresponding character. character_widths[x] corresponds to ASCII code
(ft_minchar+x).
struct width_table
{
short character_widths[ft_maxchar - ft_minchar + 1];
};
|
The data table is just an array of character definitions with
the first definition corresponding to the first character. Each character definition is
divided into (ft_h) rows with the first row at the top and the last row at the bottom.
Each row has one or more bytes of information. If the FT_COLOR flag is set, in each row
there will be as many bytes as there are pixels across the character (i.e. the character
width), with each byte being a color reference to the palette at the end of the file
(color 255 is transparent). The first byte is the leftmost pixel and the last byte
is the rightmost.
If the FT_COLOR flag is clear (the font is mono), there will
be (character width) / 8 bytes. A '1' bit means an opaque pixel, and a '0' bit means
a transparent. The first byte is the leftmost 8 pixels of the character, and the
most-significant bit (MSB) is the leftmost pixel in the byte.
Kerning is the process of adjusting the font's spacing based
on which characters are next to each other. For instance, a period following a
"T" might be put closer to the "T" because it can fit neatly
underneath the top bar.
Here is the format of the Kerning Table (There are an
undefined number of entries of the following type, followed by a uchar with a value of
0xFF):
struct KerningTableEntry
{
uchar firstChar; // If secondChar follows firstChar,
uchar secondChar;
uchar newWidth; // The first character's width will be temporarily
set to this value.
};
|
Notice that the width table is in shorts, but that this is in
uchars. But nobody's going to declare a font with a character of width 256 or more,
are they?
If the FT_COLOR flag is set, a palette will follow the font.
struct palette
{
uchar rgbValues[256][3];
};
|
The table is in BGR style (instead of RGB). Be careful not to
assign an important color to rgbValues[255][], because to the data, index 255 means
transparent.