Larry Hastings
01-17-2004, 10:31 PM
Like most everybody else, I have my own font engine. But I only supported monospaced fonts. I figured it would be too big a pain to support proportionally spaced fonts--I'd had enough trouble just making the monospaced font texture, so making one for a proportionally spaced font sounded like a real pain. And I didn't look forward to generating the character width information!
Well, yesterday I finally got sick of looking at my monospaced font, and of being envious of other games' proportionally-spaced fonts. So I dug out a tool I downloaded most of a year ago, and lookee there! it was actually pretty easy. Less than a day of work later and I had 'em working--and I'm here to share with you the two stumbling blocks I tripped over.
The tool I downloaded a year ago was MudgeFont (http://sourceforge.net/projects/mudgefont/). I first read about it when it was Flipcode's Code Of The Day for May 19th, 2003 (http://www.flipcode.com/cgi-bin/msg.cgi?showThread=COTD-FontGenerationTool&forum=cotd&id=-1). I suspect font generator tools are a dime a dozen, but this one was nice because of its liberal license. The author wrote:This tool is quite similar to "all" (I only found 2) those other font generation tools, but it comes with full source-code, and you are free to use, modify, and redistribute it, also for commercial use.. no GPL or anything... just completely free.You specify what font/size you want, and how big you want the bitmap to be, and it generates two files: a .TGA file with the font encoded in the alpha channel, and a .XML file describing the coordinates and width/height for each character in the font. You can also save your preferences, in a (poorly-named) .FNT file, though the reloading later is a skosh wonky.
Generating the font I wanted was a snap, and I had the TGA and XML file in five minutes. My next step, and the first stumbling block, was getting that XML into a format I actually wanted to use. As ostensibly "easy" a format as XML is, I don't want to add another file format to my game. I have my own deadly simple hierarchical data format, which in a whimsical moment I named "Twiddle". It looks like this:
a = b
x = y
subkey name
{
this=that
those other things = whatever
nested dude
{
oops = I did it again
}
}
You get the idea. Anyway, I wanted to get the font metrics as a Twiddle file instead of as XML. I considered just hacking the MudgeFont sources to output Twiddle, but I didn't want to maintain those diffs. I also thought about a brute-force converter, ignoring the XML and just picking out the pieces I needed, but that too seemed inflexible and subject to breakage if MudgeFont ever changed.
So I looked into using Python's XML support. After a couple of false starts, I figured out how to suck the XML file in and work it over with Python's xml.dom.minidom library. My final Python script is attached to this posting; feel free to download it and adapt it to your funny-little hierarachical file format. Just specify the .xml files on the command-line, and it'll generate matching .txt files. I'm glad I settled on that solution, as it's definitely the best of the three solutions, and it wasn't really any harder or more time-consuming.
So, that was problem one. Problem two came later. First I had a long debugging session, until I realized I had inverted the vertices for the font (my Y coordinates start at the lower left and increase going up the screen, but my font had the bottoms above the tops, which flipped them from CW to CCW...). Once I had the font rendering to the screen, I discovered the second problem: sometimes I was getting little thin lines between characters, or sometimes above or below characters.
I'd had a problem with that before on my monospaced font, where the texel coordinates were just bordering on the next character over, and with the occasional rounding error I'd sometimes pick up some pixels from the neighboring character. But I knew that MudgeFont generates a one-pixel (or wider) border around each character, so that couldn't be it... could it?
It turned out that it was, sorta. I wasn't picking up the next character. Rather, the characters were surrounded with boxes of opaque pixels! When MudgeFont generated the font, it first filled in the bitmap with bright-cyan pixels. It would then clear the rectangle for each character as it drew it, but it would leave the surrounding bright cyan pixels alone. Those wound up in the final texture. (Seeing that in the final texture was a pain, as Photoshop would draw those TGA files as all opaque white. I only saw it when I tried the texture in the DirectX Texture Tool.)
My fix for that was a change to MudgeFont. Unfortunately, the email address for MudgeFont's author doesn't work anymore, so I don't know if this was the right thing to do. But it works for me. Just download the MudgeFont sources, then change the first m_Dib.SetPixel() call
in cMudFontDlg::UpdateTextureSize() from this:m_Dib.SetPixel(x,y, RGB(255,0,255));to this:m_Dib.SetPixel(x,y, RGB(0,0,0));Since I wasn't sure what the other m_Dib.SetPixel() calls were for, I took a guess, and changed the one that set pixels black to setting them to bright cyan. (It didn't seem to hurt anything.) With that change in place, MudgeFont generated .TGA files that were completly transparent except where the characters should be. And now my game has sharp-looking proportionally-spaced fonts!
If your game has only monospaced fonts, I hope this article inspires you to trade up to proportionally-spaced fonts. It's not that much harder to do, and you'll be very pleased with the results. I know I am.
Cheers ,
Well, yesterday I finally got sick of looking at my monospaced font, and of being envious of other games' proportionally-spaced fonts. So I dug out a tool I downloaded most of a year ago, and lookee there! it was actually pretty easy. Less than a day of work later and I had 'em working--and I'm here to share with you the two stumbling blocks I tripped over.
The tool I downloaded a year ago was MudgeFont (http://sourceforge.net/projects/mudgefont/). I first read about it when it was Flipcode's Code Of The Day for May 19th, 2003 (http://www.flipcode.com/cgi-bin/msg.cgi?showThread=COTD-FontGenerationTool&forum=cotd&id=-1). I suspect font generator tools are a dime a dozen, but this one was nice because of its liberal license. The author wrote:This tool is quite similar to "all" (I only found 2) those other font generation tools, but it comes with full source-code, and you are free to use, modify, and redistribute it, also for commercial use.. no GPL or anything... just completely free.You specify what font/size you want, and how big you want the bitmap to be, and it generates two files: a .TGA file with the font encoded in the alpha channel, and a .XML file describing the coordinates and width/height for each character in the font. You can also save your preferences, in a (poorly-named) .FNT file, though the reloading later is a skosh wonky.
Generating the font I wanted was a snap, and I had the TGA and XML file in five minutes. My next step, and the first stumbling block, was getting that XML into a format I actually wanted to use. As ostensibly "easy" a format as XML is, I don't want to add another file format to my game. I have my own deadly simple hierarchical data format, which in a whimsical moment I named "Twiddle". It looks like this:
a = b
x = y
subkey name
{
this=that
those other things = whatever
nested dude
{
oops = I did it again
}
}
You get the idea. Anyway, I wanted to get the font metrics as a Twiddle file instead of as XML. I considered just hacking the MudgeFont sources to output Twiddle, but I didn't want to maintain those diffs. I also thought about a brute-force converter, ignoring the XML and just picking out the pieces I needed, but that too seemed inflexible and subject to breakage if MudgeFont ever changed.
So I looked into using Python's XML support. After a couple of false starts, I figured out how to suck the XML file in and work it over with Python's xml.dom.minidom library. My final Python script is attached to this posting; feel free to download it and adapt it to your funny-little hierarachical file format. Just specify the .xml files on the command-line, and it'll generate matching .txt files. I'm glad I settled on that solution, as it's definitely the best of the three solutions, and it wasn't really any harder or more time-consuming.
So, that was problem one. Problem two came later. First I had a long debugging session, until I realized I had inverted the vertices for the font (my Y coordinates start at the lower left and increase going up the screen, but my font had the bottoms above the tops, which flipped them from CW to CCW...). Once I had the font rendering to the screen, I discovered the second problem: sometimes I was getting little thin lines between characters, or sometimes above or below characters.
I'd had a problem with that before on my monospaced font, where the texel coordinates were just bordering on the next character over, and with the occasional rounding error I'd sometimes pick up some pixels from the neighboring character. But I knew that MudgeFont generates a one-pixel (or wider) border around each character, so that couldn't be it... could it?
It turned out that it was, sorta. I wasn't picking up the next character. Rather, the characters were surrounded with boxes of opaque pixels! When MudgeFont generated the font, it first filled in the bitmap with bright-cyan pixels. It would then clear the rectangle for each character as it drew it, but it would leave the surrounding bright cyan pixels alone. Those wound up in the final texture. (Seeing that in the final texture was a pain, as Photoshop would draw those TGA files as all opaque white. I only saw it when I tried the texture in the DirectX Texture Tool.)
My fix for that was a change to MudgeFont. Unfortunately, the email address for MudgeFont's author doesn't work anymore, so I don't know if this was the right thing to do. But it works for me. Just download the MudgeFont sources, then change the first m_Dib.SetPixel() call
in cMudFontDlg::UpdateTextureSize() from this:m_Dib.SetPixel(x,y, RGB(255,0,255));to this:m_Dib.SetPixel(x,y, RGB(0,0,0));Since I wasn't sure what the other m_Dib.SetPixel() calls were for, I took a guess, and changed the one that set pixels black to setting them to bright cyan. (It didn't seem to hurt anything.) With that change in place, MudgeFont generated .TGA files that were completly transparent except where the characters should be. And now my game has sharp-looking proportionally-spaced fonts!
If your game has only monospaced fonts, I hope this article inspires you to trade up to proportionally-spaced fonts. It's not that much harder to do, and you'll be very pleased with the results. I know I am.
Cheers ,