The Bitmap Font Generator is a free program to generate bitmap fonts from true type fonts. The bitmaps are generated in such a way as to leave as little unused space as possible. The position of the characters in the bitmap is not regular so you'll need the generated font descriptor file to determine how to draw each character.
You can open the font settings dialog by going to the Options menu and choosing Font settings, or you can just press F on the keyboard.
The left half of this dialog controls the properties of the font, i.e. the character set, and looks. The right half controls how the font will be stored, i.e. texture layout, file format, etc. The left half is pretty self explanatory, so I'll explain only the right half.
Padding is useful when you want to add some post processing effects in another paint program. For example, if you want to add a blurring effect that uses a 5x5 kernel, you would add a padding of 2 on all sides. Similarly if you want to add a drop shadow, you would add a bit of padding below and to the right of the characters (assuming that's the direction of the drop shadow that you want).
The spacing controls how much minimum space is left between characters in the font texture. If you're using mipmapping to scale the font texture when drawing the font, you'll need to add spacing to avoid bleeding when the texture is downscaled. The more mipmap levels you use the more spacing you need.
Bilinear filtering may also cause bleeding, so unless you use pixel perfect drawing, where each texel is perfectly mapped to a pixel on the screen with a 1-to-1 releation ship you'll want to use at least 1 for vertical and horizontal spacing.
BMFont supports several different texture layouts. The width and height, of course control the size of the texture. You'll want to keep the texture as small as possible, while still allowing all characters to fit in one texture.
If you're importing colored icons, or planning on using post processing to add colors to the characters, then you'll want to choose the 32bit format, otherwise the 8bit format may be sufficient.
If you choose the 32bit format, you may still optimize the usage of the texture memory if you choose to pack characters in each channel, though that will require a special pixel shader to decode during drawing. In this mode you can still import colored icons, the characters will be properly packed around them.
The font outline can also be encoded together with the character in 8 bits, allowing you to store many more characters in the same space than if you had stored the outlined characters as colored images. This too require a special pixel shader to decode during drawing.
Finally you can choose the file format for both the font descriptor and textures. This is mostly a matter of choice, rather than one having more benefits than the other. Though if you want to save disc space, you may want to choose binary file descriptor with png textures.
The application can be used from the command line, to performed automated generation of font files. The prerequisite is a font configuration file, that you can save from the application, or even generate yourself. The command line parameters are:
This tag holds information on how the font was generated.
face | This is the name of the true type font. |
size | The size of the true type font. |
bold | The font is bold. |
italic | The font is italic. |
charset | The name of the OEM charset used (when not unicode). |
unicode | Set to 1 if it is the unicode charset. |
stretchH | The font height stretch in percentage. 100% means no stretch. |
smooth | Set to 1 if smoothing was turned on. |
aa | The supersampling level used. 1 means no supersampling was used. |
padding | The padding for each character (up, right, down, left). |
spacing | The spacing for each character (horizontal, vertical). |
outline | The outline thickness for the characters. |
This tag holds information common to all characters.
lineHeight | This is the distance in pixels between each line of text. |
base | The number of pixels from the absolute top of the line to the base of the characters. |
scaleW | The width of the texture, normally used to scale the x pos of the character image. |
scaleH | The height of the texture, normally used to scale the y pos of the character image. |
pages | The number of texture pages included in the font. |
packed | Set to 1 if the monochrome characters have been packed into each of the texture channels. |
encoded | Set to 1 if the black outline is encoded together with the white char in the alpha channel. |
This tag gives the name of a texture file. There is one for each page in the font.
id | The page id. |
file | The texture file name. |
This tag describes on character in the font. There is one for each included character in the font.
id | The character id. |
x | The left position of the character image in the texture. |
y | The top position of the character image in the texture. |
width | The width of the character image in the texture. |
height | The height of the character image in the texture. |
xoffset | How much the current position should be offset when copying the image from the texture to the screen. |
yoffset | How much the current position should be offset when copying the image from the texture to the screen. |
xadvance | How much the current position should be advanced after drawing the character. |
page | The texture page where the character image is found. |
chnl | The texture channel where the character image is found (1 = blue, 2 = green, 4 = red, 8 = alpha, 15 = all channels). |
The kerning information is used to adjust the distance between certain characters, e.g. some characters should be placed closer to each other than others.
first | The first character id. |
second | The second character id. |
amount | How much the x position should be adjusted when drawing the second character immediately following the first. |
This section describes the layout of the tags in the binary file format. To understand what each tag means refer to the file tags section.
The first three bytes are the file identifier and must always be 66, 77, 70, or "BMF". The fourth byte gives the format version, currently it must be the binary 1 or 2. Version 2 sees the addition of outline in the infoBlock and encoded in the commonBlock.
Following the first four bytes is a series of blocks with information. Each block starts with a one byte block type identifier, followed by a 4 byte integer that gives the size of the block, including the 4 byte size value, but not the block type identifier.
#pragma pack(1) struct infoBlock { int blockSize; WORD fontSize; BYTE reserved:4; BYTE bold :1; BYTE italic :1; BYTE unicode :1; BYTE smooth :1; BYTE charSet; WORD stretchH; BYTE aa; BYTE paddingUp; BYTE paddingRight; BYTE paddingDown; BYTE paddingLeft; BYTE spacingHoriz; BYTE spacingVert; BYTE outline; // Added with version 2 char fontName[1]; };
This structure gives the layout of the fields. Remember that there should be no padding between members. Allocate the size of the block using the blockSize, as following the block comes the font name, including the terminating null char. Most of the time this block can simply be ignored.
#pragma pack(1) struct commonBlock { int blockSize; WORD lineHeight; WORD base; WORD scaleW; WORD scaleH; WORD pages; BYTE packed :1; BYTE encoded :1; // Added with version 2 BYTE reserved:6; };
#pragma pack(1) struct pagesBlock { int blockSize; char pageNames[1]; };
This block gives the name of each texture file with the image data for the characters. The string pageNames holds the names separated and terminated by null chars. Each filename has the same length, so once you know the size of the first name, you can easily determine the position of each of the names. The id of each page is the zero-based index of the string name.
#pragma pack(1) struct charsBlock { int blockSize; struct charInfo { WORD id; WORD x; WORD y; WORD width; WORD height; short xoffset; short yoffset; short xadvance; BYTE page; BYTE chnl; } chars[1]; };
The number of characters in the file can be computed by taking the size of the block and dividing with the size of the charInfo structure, i.e.: numChars = (charsBlock.blockSize - 4)/18.
#pragma pack(1) struct kerningPairsBlock { int blockSize; struct kerningPair { WORD first; WORD second; short amount; } kerningPairs[1]; };
This block is only in the file if there are any kerning pairs with amount differing from 0.
This pixel shader shows how to decode the color from a font texture with characters packed into all 4 channels, and each channel using special encoding to store the character with the outline. The texture is also allowed to store full 32bit images for some characters.
// DirectX 9 pixel shader float4 PixScene( float4 color : COLOR0, int4 chnl : TEXCOORD1, float2 tex0 : TEXCOORD0 ) : COLOR0 { float4 pixel = tex2D(g_samScene, tex0); if( dot(vector(1,1,1,1), chnl) ) { float val = dot(pixel, chnl); pixel.rgb = val > 0.5 ? 2*val-1 : 0; pixel.a = val > 0.5 ? 1 : 2*val; } return pixel * color; }
The chnl texture coordinate is a 4D vector that shows which channel the character should be read from. If this is (0,0,0,0) the character is interpreted as a 32 bit image. The texture coordinate can be stored in a UBYTE4 type, so it doesn't require much bandwidth when being sent to the video card.
With some fonts, some characters are cropped. An example is Bitstream's Cyberbit font, where the bottom of the square bracket characters are cropped off in some font sizes.
This is a compatibility problem between the font and GDI, not a problem in this application by itself. You get the same problem in WordPad for example. I will however try out other font rasterizers, to see if I can fix this problem in a future version.
Depending on your Windows configuration you may see that with some fonts characters are disabled, yet have a character image. Especially with the asian character sets. This is because Windows automatically fills in the missing characters by taking them from another font when the international language pack is installed.
I do not consider this an error in BMFont, but it may be fixed in a future version, especially if I end up using another font rasterizer.
Some font files have some but not all subsets with characters rotated by 90 degrees. For example @Arial Unicode MS, with subset Enclosed Alphanumerics. This is not an error, but a feature of that font file. With the font rotated like this it permits writing texts in normal text editors as if they were in vertical lines.