Next: , Previous: Common Pinball Library, Up: Top


10 Fonts and Graphics

This chapter explains in detail how FreeWPC fonts and graphics work.

FreeWPC uses simple bitmaps to represent fonts, icons, and full-screen graphics. A bitmap is an array of rectangular pixel data. The data bits are prefixed by a short header which contains the width and height information. The image is stored one row at a time, starting from the top. Within a row, the bits are stored in little-endian format, with the least significant bit representing the leftmost pixel.

A font is a set of bitmaps mapped to a contiguous sequence of characters. The font header identifies the ASCII code for the first bitmap that is represented; this saves space by not needing to encode the low-valued ASCII control characters. The nominal height of the characters is also defined, which allows for descenders.

A frame is a full-screen bitmap, 128x32. Since these are fairly common, special APIs are used to draw them that are more optimal, and the width/height is implied and not actually stored in the bitmap. A frame can have 4 colors per pixel (3 shades plus black) so the frame is actually stored as two consecutive bit planes.

10.1 Compression

Each bit plane of a frame can optionally be compressed using run-length encoding (RLE) or zero suppression to save space. An uncompressed frame requires 1KB, which limits the total number of frames in a ROM significantly. Every frame header includes a flags field, which indicates which if any compression method was used. The frame decoders are written in assembly language in platform/wpc/dmd.s.

Compression is a balance between ROM size and processor speed. The best compression methods would take far too long for the 6809 to decode. The methods used strike a compromise. In particular, bitwise operations are avoided in the decoders because of the 6809's inability to do bitlevel operations quickly.

10.2 Using TrueType Fonts

The script fontgen2 converts TrueType font files (.ttf files) into WPC font files (.fon). Not all characters are supported; in particular, lowercase characters are not included by default in order to save space. Trying to display any characters not included in the font will generally cause a system crash, as there is not much error checking.

10.3 Printing Text

The font_render_string family of APIs is used to draw text to the display. The arguments are a font object, the x and y coordinates where the string should be placed, and a string. The string can be a constant string literal or the global format buffer (see below).

There are three variants which justify the text differently: centered, left-justified, and right-justified. Centering is done both vertically and horizontally; the others only justify left-to-right, and the y coordinate always specifies the top of the print area.

Text printing is CPU intensive. Display effects should take care not to print text more than needed. It is often more efficient to print strings to an overlay buffer, and then copy them to the main display page, if the same text needs to be printed over and over again.

10.4 Formatting Text

FreeWPC contains a printf-like function for formatting text strings with variable data, however, it is not quite the same.

The sprintf() function formats a string into a unique, global buffer named sprintf_buffer. It is like the actual C function of the same name, but the first argument is implied.

The format specifiers are also slightly different. Here is a list of the valid ones:

%b
Print a binary-coded decimal value. The format length gives the total number of digits; for example, %8b would print a 4-byte BCD string containing 8 digits. Also, this format will insert commas (or periods) between digits as necessary.
%c
Print a single 8-bit ASCII character.
%d
Print an 8-bit decimal integer (declared U8).
%E
When this is the first specifier in a string, it will cause all output to be appended to the previous string in the print buffer, rather than overwriting it completely.
%ld
Print a 16-bit decimal integer (declared U16).
%lx
Print a 16-bit hexadecimal integer (declared U16).
%p
Print a pointer.
%s
Print a string.
%w
Print a 32-bit hexadecimal integer (declared U32).
%x
Print an 8-bit hexadecimal integer (declared U8).

Like in C, you can insert a number in front of the format letter to limit the output to a particular width. If the length begins with '0', then it will be padded with leading zeroes if necessary.

The formatter does not support signed numbers, and will print them as if they were declared unsigned.

The formatter is not particularly efficient for printing large decimal values, as the 6809 is not very good at long division.

10.5 Frame List

The list of all frames compiled in the ROM is defined in an image map. This is a machine-specific file that says which images to copy into the final ROM image.

There can be multiple frame list files. The common code provides a frame list of standard images, like the FreeWPC logo, which go into every build.

Each entry in the image map gives an image to be imported, such as a PGM graphics file, plus an optional frame ID. The frame ID becomes a C #define that refers to the image from the source code. The image linker writes a file build/imagemap.h which contains a list of all the frame IDs. Frame IDs are optional for the internal frames in a sequence (a for loop would only need to name the starting and ending frame).

It is the job of the image linker to decide what compression techniques to perform. The linker is told the maximum amount of space that can be used for images, which is the total size of the ROM minus any sections reserved for source code. If all images fit without compression, then all is well.

Otherwise, the linker will perform as much as compression as necessary. At present, images are compressed in the order that they were declared. A future enhancement would be to start with those images that can be compressed the best without requiring much more CPU power to decode them.

In some rare cases, trying to compress an image fails to produce a smaller buffer. The linker notices this and leaves such images uncompressed.