SuperVGA Graphics Library — SVGAlib for short — is a low level graphics library for Linux that eliminates having to delve into the complexities of the X Windows system. One aspect of SVGAlib that frequently baffles programmers, however, is the use of fonts. Many coders find themselves with more questions than answers on the subject. How are SVGAlib fonts created? How are they displayed? Several programs (such as the Linux game Sasteroids) clearly use lettering on the screen, yet there’s no obvious explanation given. You won’t find any tutorials regarding SVGAlib fonts on the Net, nor will you find any mention of fonts in the standard FAQs. It almost seems like there’s been a deliberate omission — a veritable conspiracy of silence.
This article aims to give you all the basic information you need to program SVGAlib fonts, from manipulating existing character sets to creating new ones. You’ll learn where to download some good typefaces (hint: www.svgalib.org), and how to use a new external library to display TrueType fonts — the visually superior, cross-platform standard. But let’s start at the beginning, by considering some basics about fonts.
What Is a Font?
A font can be defined as a set of typewritten characters, all using a consistent style or design. You may be familiar with fonts from other operating systems, such as Arial or Helvetica. Perhaps you’ve used them on the web? Regardless, fonts are an integral part of today’s computing environment.
Fonts don’t have the ability to display themselves. Most fonts are contained within data files, which are then called by executables. (These data files are often in binary format, which means that they can’t be read by a text editor).
Types of Fonts
It’s important to know that there are two types of fonts available: bitmapped and scalable. These two font types are nearly identical in concept to the bitmapped and vectored graphic files commonly available. A bitmapped font (the simpler of the two) is like a BMP or GIF image. It’s stored as a matrix (or grid) of pixel values, and is displayed exactly as it’s written — no interpretation is involved. It’s a perfect copy, but as a result, it can’t be resized without a significant loss of quality. See the diagram below for an example.
A scalable font, on the other hand, is stored in the same manner as a vectored graphic. Rather than being mapped pixel by pixel, a scalable font’s “stylistic information” is saved in its data file. This information includes the angles of each character’s curves, and how they’re proportioned. Because no actual picture exists, it’s up to the program that reads in the font to construct it for display. This adds some processing overhead, but the end result is well worth it. Scalable fonts can be resized without losing any quality, and often have smooth (or antialiased) edges. Now, have a look at the next diagram for an example of a scalable font. It’s quite nice, isn’t it? This is Arial, a TrueType font.
Bitmapped Fonts
Unfortunately, SVGAlib is only capable of displaying bitmapped fonts. (However, we can get around that later by using another library). The good news is that the code is fairly simple. To use it, you’ll have to employ SVGAlib’s sister library: vgagl.
Here’s how you prepare a bitmapped font for use, using gl_font8x8:
void *font = malloc(256 * FONT_WIDTH * FONT_HEIGHT * BYTESPERPIXEL); gl_expandfont(FONT_WIDTH, FONT_HEIGHT, COLOR, gl_font8x8, font); gl_setfont(FONT_WIDTH, FONT_HEIGHT, font);
This loads SVGAlib’s one internal font, gl_font8x8, into memory. The “8×8” means that each character in the font is eight pixels high by eight pixels across. That means you’ll need to define
FONT_HEIGHT |
and
FONT_WIDTH |
as being 8.
COLOR |
can be any color value, as long as it’s within the parameters of your chosen screen mode. Finally,
BYTESPERPIXEL |
is defined in vgagl.h.
The next step is to actually display your words on the screen. This is accomplished with gl_write():
gl_write(10, 10, "Hello, world.");
The first two arguments (10 and 10) place the words on the screen — they refer to the x and y corrdinates of the upper left-hand corner of the first character.
Here’s a complete program, using the four commands you just learned:
#include#include #include #define FONT_HEIGHT 8 #define FONT_WIDTH 8 void prepare_font(void); int main(void) { int x = 10, y = 10; char text[] = "Hello, world!"; vga_init(); vga_setmode(G320x200x256); gl_setcontextvga(G320x200x256); prepare_font(); gl_write(x, y, text); vga_getch(); vga_setmode(TEXT); return 0; } void prepare_font(void) { int color = 15; /* white */ void *font = malloc(256 * FONT_WIDTH * FONT_HEIGHT * BYTESPERPIXEL); gl_expandfont(FONT_WIDTH, FONT_HEIGHT, color, gl_font8x8, font); gl_setfont(FONT_WIDTH, FONT_HEIGHT, font); }
Upon running this program, you should see the words “Hello, world!” displayed in white at the top of the screen. Hooray! You’ve done it. Feel free to play around — for example, try varying the placement of your text by providing different x and y values to gl_write().
It’s worth noting that gl_writen(int x, int y, int n, char *s) is identical to gl_write(), except that it only displays the first “n” characters of your string.
Should you choose to include your string directly in gl_write() or gl_writen(), you’ll have to terminate it with “