http://GameProgrammer.Com

Programming

GP Mailing List
     Thread Index
     Date Index

ATXGPSIG List
     Thread Index
     Date Index

Google
>

Home

Wise2Food


The PolyFonts Library

Bob Pendleton


Download Source in .tar.gz
Download Source in .zip

Download OOFonts in .tar.gz
Download OOFonts in .zip

Download Larabie fonts in .tar.gz
Download Larabie fonts in .zip


Table of Contents


Introduction

The PolyFonts library is a (hopefully) simple to use text library for SDL. PolyFonts draws text into all types of SDL surfaces. It works the same on software and hardware surfaces as it does on OpenGL surfaces. PolyFonts provides a usable set of fonts. The fonts are stored as geometry in the form of OpenGL rendering commands and vertex data. That means that all the fonts can be drawn in any size and any orientation. It means that one font can be used to draw text of any without having to recreate the font in the new size. You do not have to load a font file, or convert glyphs to images before you can draw text on the screen.

To the best of my knowledge any TrueType font can be converted for use with PolyFonts. Due to the difficulty of finding redistributable fonts only a small set of fonts is provided. If you need a font converted for use with PolyFonts, contact me. I am willing to convert fonts for you so long as you can prove you have the right to do use the font. If you find a source of provably free fonts, please contact me so I can include them in the library. If you own any fonts and you are willing to give permission to include them in the library, please contact the me.

The Fonts

PolyFonts include three different styles of fonts, stroke fonts, outline fonts and polygonal fonts.

  • Stroke fonts are drawn using lines. As a result of the way they are stored, these fonts use little memory and can be drawn very quickly. But, they don't look that good at large sizes. Stroke fonts look like they were drawn with a sharp pencil.

  • Outline fonts are also drawn using lines. Outline fonts are the outlines of a TrueType font.

  • Polygonal fonts look like the kind of solid fonts we are used to seeing. Like the fonts used to draw the characters you are currently reading. Polygonal fonts are stored as triangles, triangle fans, and triangle strips. Polygonal fonts take up more space than the other fonts and take longer to render. But, they look very good at large sizes.

Due to the restrictive copyrights on most fonts it is difficult to find fonts that you can legally include in a library like this. I have tracked down three sources of redistributable fonts and include all of them in PolyFonts. If you know of other freely redistributable fonts, or own the copyrights to fonts you are willing to place in this library, please contact me. The more fonts the better.

The fonts provided with PolyFonts are derived from several sources:

  • PEX – PEX is the original 3D API for X11. PEX included a nice stroke font that is covered by the X license. The PEX stroke font is the same the stroke font used in GLUT.

  • Hershey Fonts – A. V. Hershey, while working at the U.S. National Bureau of Standards, digitized a large number of stroke fonts. Various forms of these fonts have been determined to be freely redistributable and have been used in a wide variety of applications. Some of these fonts are unlike anything I have ever seen.

  • Bitsream Vera Fonts – GNOME and Bitstream got together and created a great set of fonts and put them out under an amazingly liberal license. All of the outline and polygonal fonts included in this library are derived from these fonts. One of the restrictions in the license is that you can not use the names “Bitstream” or “Vera” in conjunction with derivatives of those fonts. So, I don't.

  • OpenOffice.org – The OpenOffice.org fonts are distributed under you choice of the LGPL, the GPL, or the Sun SISSL license. Because not everyone is willing to comply with those licenses I have made the PolyFonts form of these libraries available as a separate download. (OOFonts.zip or OOFonts.tar.gz) If you have OpenOffice on your computer you already have the TrueType versions of these fonts.

  • Ray Larabie – Mr. Larabie has created over 300 fonts that he has made available for use with the PolyFonts library. You really have to see these fonts to believe them. Mr. Larabie has created a valuable resource by allowing the use of these fonts with the PolyFonts library. The download for these fonts is nearly 30 megabytes (larabie.zip or larabie.tar.gz) so be careful. The fonts are covered by his own license. But, as he said in his email to me:

Hi Bob,
Yes, you can include my fonts. The license agreement is the same for all fonts so just make sure that the users can find it fairly easily. You might want to make it clear that users don't have to get special permission to use my fonts in a game but I always appreciate a copy of the final product, swag etc - if you think it's appropriate to mention it somewhere. Your call.
Cheers,
Ray Larabie
www.typodermic.com
www.larabiefonts.com

Font Files

The font files are stored in the fonts subdirectory of the distribution. Each font has a corresponding .h and .c file. To use a font you may either include the .h file in your program and compile the .c file and link it into your program. Or, you can load the .c files at run time using the pfLoadFont() function. That's right. The .c files are compilable C source code that can be compiled into you program, and they are data files that can be read and loaded while the program is running. The font loader is a small function that adds little overhead.

The pfStrokeFutura font is compiled into PolyFonts and is the default font. You can remove the dependency on this font or change the default font by editing polyfonts.c.

Font File Naming Convention

The font files are named according to an overly complex and inconsistent convention. Sorry about that. The first two characters of the font file name are “pf” for PolyFonts. After that is one of the letters:

  • S – for a stroke font. “Stroke” is always followed by the name of the font, such as Times, or Roman, of Futura.

  • O – for an outline font.

  • P – for a polygonal font.

The names of polygonal and outline fonts are further qualified by adding some of the following words to the name:

  • Sans – Sans is short for “sans serif”. Arial is a well known sans serif fonts. I'm rather fond of sans serif fonts.

  • Serif – Serif fonts have little pointy things (called serifs) of the ends of the letters.

After that are more words that describe other features of the font.

  • Mono – for mono spaced fonts. If a font isn't labeled as a mono spaced font it is a proportionally spaced font.

  • Bold – for bold fonts.

  • Italic – for italic fonts.

Finally at the end the names of outline and polygonal fonts there is a number, either 7, 8, or 16. These fonts are derived from TrueType fonts that originally contained glyphs for many of the characters defined in the Unicode 16 bit character set. Most of the code I write only needs the 7 bit subset of Unicode that covers the old ASCII character set. But, other people have other needs. So, the files ending in 7 contain a 7 bit subset of the font and cover characters in the range 0-127. Files ending in 8 cover the characters with codes in the range 0-255. And the files ending in 16 cover the full range of the 16 bit character set. This does NOT mean that they contain 65,536 glyphs. It just means that the “16” files cover all the characters that were covered by the original TrueType font.

Now for the inconsistent part... The OpenOffice fonts and the Larabie fonts are polygonal fonts. But, their licenses do not allow you to change their names. So, the fonts are have their original names with pfP prefixed to them for consistency.

The Stroke Fonts

Most of the stroke fonts are derived from the Hershey fonts. There are a several very unique fonts in this set and they deserve a description. The only way to really get a feel for these fonts is to run the glfont or sglfont programs included with the library and see what they look like.

  • pfStrokeAstrology – This is a serif font in which all the special characters, like = and < have been replaced with astrological symbols.

  • pfStrokeCursive – Really a cursive font. Have you ever seen on of those old cursive typewriters? (Ever seen a typewriter? :-) This font draws letters the way your grade school teacher wanted you to do it.

  • pfStrokeCyrillic – A Cyrillic alphabet mapped on top of the ANSI characters. Useful for all you Russian out there?

  • pfStrokeFutura – I like this font. It is a nice sans serif font that is easy to read.

  • pfStrokeFuturaMono – This is a mono spaced font that is very nice for use in terminal emulation. It is is almost an outline font. Works well for debug output.

  • pfStrokeGothicEnglish – Yes, an honest to goodness Gothic English font. Great for scrolls. I've even used it on T-Shirts.

  • pfStrokeGothicGerman – A Gothic German font, really. Must be seen to be believed.

  • pfStrokeGothicItalian – Hershey must have liked Gothic fonts. Between the three Gothic fonts you have a huge set of Gothic characters to play with.

  • pfStrokeGreek – Handy for Greeks and scientific applications all over the world.

  • pfStrokeJapanese – These look like Japanese to me, but I know nothing of Japanese. I include them in the hope they will be useful and for the sake of completeness. Not to mention that these are really pretty characters.

  • pfStrokeMarkers – A set of symbols for use in charts.

  • pfStrokeMathLower – Mathematical symbols with lower case letters.

  • pfStrokeMathUpper – Mathematical symbols with upper case letters.

  • pfStrokeMeteorology – A sans serif font with meteorological symbols substituted for the special characters.

  • pfStrokeMusic – An Italic serif font with music symbols substituted for the special characters. Looks a lot like all the sheet music I have ever seen.

  • pfStrokeRoman – This is the PEX proportionally spaced font. It is a nice sans serif font. If you have ever used GLUT, or a GLUT application, you have probably seen this font.

  • pfStrokeRomanMono – Same as above but mono spaced. Good for terminals and debugging output. I find both of the PEX fonts to be easy to read. Because these fonts have been around for a long time they have been used in a lot of applications. Most of the text you see in pictures of heads up displays look suspiciously like it was drawn with these fonts.

  • pfStrokeScript – A very fancy cursive font. Really nice.

  • pfStrokeSymbolic – A large collection of symbols including the symbols on cards and some used on maps.

  • pfStrokeTimes,
    pfStrokeTimesBold,
    pfStrokeTimesBoldItalic,
    pfStrokeTimesGreek,
    pfStrokeTimesItalic – These are all variations on a fancy serif font. Very nice.

Demo and Test Code

The following demos and test programs are included with the library:

  • glfonts.cpp
    sglfonts.cpp
    – These two programs are basically the same program, except that glfonts is written to use only OpenGL for its graphics while sglfonts use an SDL software surface for all of its graphics. Each program starts with a blank white screen and displays another font each time you press the space bar. Pressing “q” or Escape will terminate the program. Look at these programs to get an idea how to use the library.
    In case you are wondering, the only reason why polyfontsALL.h exists is to make it easier to write these two programs. You can safely ignore that file in your code.

  • Loadfonts.cpp – This program loads font files at runtime and can be used as a general viewer for examining the fonts that come with PolyFonts as well as the add on font libraries.

  • sgltest.cpp – This is a test program I wrote to test both SGL and PolyFonts. Pressing “g” will bring up the graphics tests and pressing “t” will bring up the text tests. When the program starts it is using software rendering. Pressing “q” or Escape will stop the first test and bring up the OpenGL version of the tests. Pressing “q” or Escape in the second test will stop the program. Pressing the space bar will cycle through the different tests.
    This program prints a lot of information so it is best to pipe its output to a file.

Functions

There are a few things you need to know when working with this library.

  • The vertex data has been scaled so that every character in a font fits inside a box such that -1 < x < 1 and -1 < y < 1. Scaling it that way makes it much easier to work with the data and made it possible to reduce the size of the data 50%.

  • To reduce the size of the fonts all the font data has been converted to a signed 16 bit fixed point format. The unFix() macro in polyfonts.c is used to convert back to floating point format.

  • A character is drawn so that the lower left hand corner of a capital letter is at the current text position.

  • The scale factors controls how large a character appears on the screen.

  • The text drawing routines assume that the screen 0,0 coordinate is in the upper left hand corner of the screen and Y increases down the screen. If you want 0,0 to be in the lower left hand corner of the screen just use a negative Y scale value to flip the characters.

  • PolyFonts does not have a function for setting the text color. Use one of the SGL color functions to set the color.

int pfSetFont(pffont *f);

This function is used to set the font. For example, if you have compiled in the pfStrokeTimes font then you can select that font with pfSetFont(&pfStrokeTimes). The select font stays selected until you select a new font. The names of the fonts are defined in the corresponding .h and .c files.

F: A pointer to a font.

Returns: -1 on error and 0 on success.

pffont *pfLoadFont(char *fileName);

This function is used to load a font file at run time. The pf*.c PolyFonts font file can be compiled and linked into your program or they can be loaded at runtime. There is no magic being done here, I haven't added a runtime C compiler to the library. It just turns out that with a little information added as comments and some careful formatting of the files it is pretty easy to read the data out of the .c files.

FileName: The file name, including the full path, of the .c font file you want to load.

Returns: On error it returns NULL. Otherwise it returns a pointer to the font data that can be used with pfSetFont().

void pfUnloadFont(pffont *f);

This function frees the memory used by a font. It only works on fonts that were loaded using pfLoadFont(). It should simply ignore attempts to free fonts that are compiled into the program. But, it can be fooled. If you are foolish enough to try to fool it, or unlucky enough to fool it accidentally, well, trying to free statically allocated memory will usually crash you program.

F: A pointer returned by pfLoadFont().

char *pfGetFontName();

This function is here because it is nice for writing demos of the library.

Returns: A pointer to string containing the name of the current font.

pffont *pfGetCurrentFont();

This function returns a pointer to the current font. This function is here because sometimes you need to save the current font and then restore it. This is the only way to get a pointer to the default font.

Returns: A pointer to the current font.

int pfGetFontBBox(float *minx, float *miny, float *maxx, float *maxy);

This returns a bounding box that is guaranteed to be large enough to contain every character in the font. That does not mean that there is a character in the font that is the same size as the box. The values returned reflect the current scale and skew and may be negative numbers.

Returns: -1 on error and 0 on success. If the current font is NULL, -1 will be returned;

float pfGetFontHeight();

Returns: The absolute height of the font, maxy – miny.

float pfGetFontWidth();

Returns: The absolute width of the font, maxx – minx.

float pfGetFontAscent();

Use this function to find out how high above (0,0) the font extends.

Returns: The height above zero of the font, maxy.

float pfGetFontDescent();

Use this function to find out how far below (0,0) the fonts extends.

Returns: The distance below zero of the font, miny.

int pfGetFontNumGlyphs();

This function returns the number of glyphs in the font. The number of glyphs can be different from the character range of the font. For example, all of the fonts cover the character range 0 to 127. None of them have glyphs for the characters in the range 0 to 31. So, a font with a character range of 0 to 127 has only 96 (or fewer) glyphs.

Returns: The number of glyphs in the font.

wchar_t pfGetChar(int glyph);

The glyphs in a font are numbered starting at zero and ending at pfGetFontNumGlyphs() - 1. They are numbered consecutively even though the character set they cover may not be consecutive. This is especially true of the “16” fonts where the character codes covered by the font may range from 0 to 65535 even though the font only has a few hundred glyphs. This function maps from the glyph number to the character code for the glyph. This is another function that is mostly here to support writing demo programs.

Glyph: The index of a specific glyph in the font. Not to be confused with the character code for the character the glyph represents.

Returns: The character code for a specific glyph.

void pfSetScale(float s);
void pfSetScaleXY(float sx, float sy);

These functions are used to set the font size. The scale factors in the X and Y positions can be set to the same value using pfSetScale() or to two different values using pfSetScaleXY(). The default scale factor in both directions is 20.0.The scale factors can be set to any positive or negative value. Using negative values flips the characters.

S: Scale factor to be applied to both the X and Y axies.

Sx: Scale factor for the X axis.

Sy: Scale factor for the Y axis.

int pfSetScaleBox(char *c, float w, float h);
int pfSetScaleBoxW(wchar_t *c, float w, float h);

Being able to set the scale factor is great, but usually I have a rectangle that I want the text to fill. These routines set the scale factors so that the given string will fill that box. So, if you want to display “Hello World” in a box that is 20 pixels wide, and 100 pixels high, this is the function to use to make that happen. These routines do not print the string. They just set the scale factors.

C: A pointer to a zero terminated vector of characters, a “C” string. I've provided two versions, one to support normal “C” strings and one for wide character sets.

W: The width of the box.

H: The height of the box.

Returns: -1 on error and 0 on success. You will get an error if the string pointer is NULL, or if there is no glyph in the font for one or more characters in the string.

void pfSetPosition(float x, float y);

This routine sets the position for drawing the next character. Normally, the position you set will be the location of the lower left hand corner of an upper case letter. But, pfSetCenter() changes that behavior. After each character is drawn the position is advanced by the width of the character. The direction of the advance is controlled by the current angle setting.

X and Y: The x and y coordinates of the point.

void pfGetPosition(float *x, float *y);

This function returns the location at which the next character will be drawn. It is useful for telling when you have reached the end of a line or the end of the screen.

X and Y: Pointers to floating point variables that will receive the X and Y coordinates of the current text position.

void pfSetSkew(float s);

The skew factor makes characters lean to the left of right. A skew factor of -1 will make characters lean to the left at a 45 degree angle. This routine is here because it is fun to use it to make your text dance back and forth :-). The real reason this is here because it gives you a very cheap way to get italic characters without including a italic font. Setting skew to 0.3 causes and font to be drawn so that it looks like an italic font.

The library clamps the skew to be in the range -1 <= skew <= 1. If you want to use larger skew factors, change the library.

S: The skew factor to be applied when a character is drawn.

void pfSetWeight(int w);

Because the stroke fonts are drawn using lines the glyphs can be very fine and hard to see. Setting the weight factor causes the glyphs to be drawn several times. Each time they are drawn the starting point is offset by 1 in either the X and/or Y direction. In effect, creating a bold font from a line font. The default weight is 1 and the maximum weight is 9. The library clamps the value you specify to that range. I was surprised to find that this trick works well with the polygonal fonts too.

in OpenGL applications you can use all the line attributes to control how these fonts are drawn.

W: The number of times to redraw a character.

void pfSetAngleR(float a);
void pfSetAngleD(float a);

If you are like me (most of the world is not :-) when you learned to write you used lined paper and you wrote along the lines. These routines control the angle of that line. The default is to draw text left to right along a horizontal line. You can use these functions to make the text draw at an angle. The text is rotated along with the line, just as if you drew a diagonal line on a sheet of paper and then wrote along that line instead of the preprinted lines on the paper.

You can specify the angle in degrees using pfSetAngleD() or in radians using pfSetAngleR().

A: The new angle.

void pfSetCenter(int onOff);

If you draw the letter “O” using this library it will be drawn to the upper left of the text position. If you call pfSetCenter(1) and then draw the letter “O” it will be drawn so that the text position is in the middle of the “O”. You turn this effect off by calling pfSetCenter(0).

This effect is handy when you are trying to draw a symbol at a specific location rather than trying to draw text.

OnOff: Should be 1 to turn on centering and 0 to turn it off.

Int pfGetCharBBox(wchar_t c, float *minx, float *miny, float *maxx, float *maxy);

This routine gets the bounding box for the specified character in the current font. If there is no glyph in the font for the specified character it sets all the returned values to 0.0 and returns an error status.

C: The character you are interested in.

Minx and Miny: The smallest X and Y values reached by any part of the glyph. These values may be negative.

Maxx and Maxy The largest X and Y values reached by any part of the glyph.

Returns: -1 on error and 0 on success. You can get an error if the font does not contain a glyph for the a specific character.

float pfGetCharAdvance(wchar_t c);

This function returns the distance the text position will be advanced after drawing the specified character. The value depends on the character, the font, and the scale factor.

C: The character you are interested in.

Returns: The distance. It returns 0.0 if the font does not have a glyph for the specified character code.

float pfGetCharHeight(wchar_t c);

This function returns the height of the character. That is, it returns the distance from maxy to miny.

C: The character you are interested in.

Returns: The character height. It returns 0.0 if the font does not have a glyph for the specified character code.

float pfGetCharWidth(wchar_t c);

Use this function to get the total width of a character. That is, it returns the difference between maxx and minx.

C: The character you are interested in.

Returns: The character width. It returns 0.0 if the font does not have a glyph for the specified character code.

float pfGetCharAscent(wchar_t c);

Returns the height of the character above the baseline. That is, it returns maxy.

C: The character you are interested in.

Returns: The character ascent. It returns 0.0 if the font does not have a glyph for the specified character code.

float pfGetCharDescent(wchar_t c);

Returns the depth of the character below the base line. That is, it returns miny. This value is usually negative, but it is not always negative because the bottom of the character could be above the base line.

C: The character you are interested in.

Returns: The character descent. It returns 0.0 if the font does not have a glyph for the specified character code.

int pfDrawChar(SDL_Surface *s, wchar_t c);

This function draws the glyph for the specified character at the current text location, with the current text rotation, skew, and weight. It then advances the text location by the characters advance value.

S: An SDL surface pointer. It can be a hardware surface, a software surface, or an OpenGL surface.

C: The character you want to draw.

Returns: -1 on error and 0 on success. You will get an error if the current font does not have a glyph for the specified character. You will also get an error if the surface pointer is NULL.

int pfDrawString(SDL_Surface *s, char *c);
int pfDrawStringW(SDL_Surface *s, wchar_t *c);

These functions are used to draw strings into an SDL surface. I have provided two versions, one for normal “C” strings and one for wide character sets.

S: A pointer to an SDL surface. It can be a hardware surface, a software surface, or an OpenGL surface.

C: A pointer to a string. Depending on the function this is either a 0 terminated vector of char or a 0 terminated vector of wchar_t.

Returns: -1 on error and 0 on success. These functions will return an error if the surface pointer or the string pointer is NULL. Invalid characters in the strings are simply ignored.

SGL

I wrote the first version of PolyFonts using OpenGL to do all the text rendering. Even the data structures used to store the font data includes the names of the OpenGL drawing primitives used to render the fonts. That approach worked great. The data is compact. And the code is fast.

But... The more I used PolyFonts the more I wanted to use it with SDL software and hardware surfaces. It is really handy to be able to use it to create images in main memory or to render text into textures while they are still in main memory. I had to come up with a way to make PolyFonts work with both SDL surfaces, and OpenGL surfaces. Examining the code I saw that I only used a very small number of OpenGL functions. So, I dredged up some old software rendering code that I had lying around and implemented a tiny subset of OpenGL that works on with SDL software and hardware surfaces. Some of this code has its roots in code in wrote in Pascal on a z80 running CP/M. Goes to show, never throw out working code.

I called it SGL for Small GL, but maybe it should have been Tiny GL.

#define USE_GL

Having developed a library that works on any kind of SDL surface I realized that people, including my self, would want to use it when there is no OpenGL available. So, in sgl.h I define USE_GL. If you remove the definition of that value the library will compile with no references to OpenGL. At least it did the last time I tested it. Any values that SGL needs that are normally defined in the OpenGL header files will be defined by the SGL header file when USE_GL is undefined.

Functions

void sglBegin(SDL_Surface *s, int prim);

This is the replacement for glBegin(). It has an added parameter to tell it which SDL surface to draw into. The primitives are the same as those used by OpenGL.

S: A pointer to and SDL surface.

Prim: The name of an OpenGL primitive. One of:

  • GL_POINTS

  • GL_LINES

  • GL_LINE_LOOP

  • GL_LINE_STRIP

  • GL_TRIANGLES

  • GL_TRIANGLE_STRIP

  • GL_TRIANGLE_FAN

  • GL_QUADS

  • GL_QUAD_STRIP

  • GL_POLYGON

void sglVertex2f(float x, float y);

Specifies the values of a two dimensional vertex. SGL only supports 2D vertices because that is all that is needed to render polygonal fonts.

void sglEnd();

Called to mark the end of an SGL rendering request. Must match with a previous call to sglBegin().

void sglColor3f(float r, float g, float b);
void sglColor4f(float r, float g, float b, float a);

Set the drawing color. The color values are stored. Nothing is done with them at the time these functions are called. When drawing into an OpenGL surface a call to glColor4f() is made with these color values immediately before the call to glBegin(). When drawing into an SDL hardware or software surface SDL_MapRGBA() is used to convert the color values into a pixel value appropriate for the surface format and drawing is done with that pixel value.

The color values must all be in the range 0.0 to 1.0. If no alpha value is specified then an alpha value of 0.0 is used.

void sglSwapBuffers(SDL_Surface *s);

This function is a wrapper for SDL_Flip() and SDL_GL_SwapBuffers(). It is here to make writing test programs and demos easier. It just calls the correct routine based on the type of the surface.

void sglClearBuffer(SDL_Surface *s, float r, float g, float b, float a, float z);

This function clears the back buffer of a double buffered SDL surface. If the surface is an OpenGL surface with a Z-buffer the Z-buffer is cleared with the specified Z value. If not, Z is ignored. The same goes for the alpha value. If the buffer does not have an alpha channel then the alpha value is ignored. Otherwise the appropriate action is take to clear the buffer with a pixel value of the appropriate format based on the provided color values.

This is another function that is here to make testing the library and writing demos easier. I needed it so I figured you might need it too.



Copyright © 2003 Robert C. Pendleton. All rights reserved.