Fonts

Quake 2, as I've said, is designed in a way that reflects Id's contempt for story and dialog. Today, I want to talk about Font. There is one font: the console font. If you want to write characters to the screen, there is a method called refexport_t#DrawChar that allows you to provide an ASCII character and screen X-Y coordinates, but it only accepts one font and only draws in one size. I could have used the refexport_t#DrawStretchPic, but that accepts the string filename of an image and not the image itself. DrawStretchPic does a linear lookup for images associated with the provided filename and uses those. Believe it or not, but this lookup is very slow.

Scaffolding

So, I had to provide a method in the render API that allows you to provide an ASCII character AND a spritesheet to draw text from. The default conchars font used by DrawChar doesn't actually use all ASCII characters, so I wanted to be able to configure the provided spritesheet to allow the user to configure a more extensible font (perhaps UTF-8 in the future but that would be massive for a single spritesheet, I'd have to figure out a way to load only certain spritesheets based on the logic of UTF-8). Fonts are configured, for now, in .txt conf files. If the user provides a font name to the XML, like:

<menu
    Font="red"
>
    Hello world
</menu>

Then the engine will look for fonts/red.txt, which defines a handful of fields, for now:

Width=16
Height=16
Offset=0
FontImage=redtext

Each field configures the spritesheet in some way. Width and Height are the width and height of each character in the sheet, so the draw function has some coefficients to multiply by to grab the right character. Offset is how many characters to ignore from the beginning of the ASCII table (mostly used to avoid having lots of empty space for control characters), so that you can have the letter a at the first position in the sheet and the offset will simply subtract 'a' - InputCharacter to get the correct position. Finally, FontImage is the name of the font image, in the pak file. Quake 2 will take plain image names with no path or extension and search under pics first for .pcx files. I added some code to then look for .tga files if no .pcx is found. I'm trying to avoid .pcx altogether because, as it turns out, they're completely unnecessary today: the old Quake 2 PCX palette that is evangelized in Quake 2 modding is only necessary for the software renderer and not OpenGL, so I've completely written off the software renderer as a backup.

When the menu is created, the XML parser looks for the Font property and then loads up the config file, constructing a struct which contains all the info for the spritesheet listed above and attaches it to the custom menu structure for the XML element. When it comes time to render text, the menu rendering system will check for the FontImage texnum in the Menu structure (if it's not available, it will use the default conchars), then does the necessary calculations using the other attributes of the spritesheet.