GLvoid BuildFont(GLvoid) // Build Our Bitmap Font
{
HFONT font; // Windows Font ID
HFONT oldfont; // Used For Good House Keeping
base = glGenLists(96); // Storage For 96 Characters ( NEW )
Now for the fun stuff. We're going to create our font. We start off by specifying the size of the font. You'll notice it's a negative number. By putting a minus, we're telling windows to find us a font based on the CHARACTER height. If we use a positive number we match the font based on the CELL height.
font = CreateFont( –24, // Height Of Font ( NEW )
Then we specify the cell width. You'll notice I have it set to 0. By setting values to 0, windows will use the default value. You can play around with this value if you want. Make the font wide, etc.
0, // Width Of Font
Angle of Escapement will rotate the font. Unfortunately this isn't a very useful feature. Unless your at 0, 90, 180, and 270 degrees, the font usually gets cropped to fit inside it's invisible square border. Orientation Angle quoted from MSDN help Specifies the angle, in tenths of degrees, between each character's base line and the x-axis of the device. Unfortunately I have no idea what that means :(
0, // Angle Of Escapement
0, // Orientation Angle
Font weight is a great parameter. You can put a number from 0 – 1000 or you can use one of the predefined values. FW_DONTCARE is 0, FW_NORMAL is 400, FW_BOLD is 700 and FW_BLACK is 900. There are alot more predefined values, but those 4 give some good variety. The higher the value, the thicker the font (more bold).
FW_BOLD, // Font Weight
Italic, Underline and Strikeout can be either TRUE or FALSE. Basically if underline is TRUE, the font will be underlined. If it's FALSE it wont be. Pretty simple :)
FALSE, // Italic
FALSE, // Underline
FALSE, // Strikeout
Character set Identifier describes the type of Character set you wish to use. There are too many types to explain. CHINESEBIG5_CHARSET, GREEK_CHARSET, RUSSIAN_CHARSET, DEFAULT_CHARSET, etc. ANSI is the one I use, although DEFAULT would probably work just as well.
If you're interested in using a font such as Webdings or Wingdings, you need to use SYMBOL_CHARSET instead of ANSI_CHARSET.
ANSI_CHARSET, // Character Set Identifier
Output Precision is very important. It tells Windows what type of character set to use if there is more than one type available. OUT_TT_PRECIS tells Windows that if there is more than one type of font to choose from with the same name, select the TRUETYPE version of the font. Truetype fonts always look better, especially when you make them large. You can also use OUT_TT_ONLY_PRECIS, which ALWAYS trys to use a TRUETYPE Font.
OUT_TT_PRECIS, // Output Precision
Clipping Precision is the type of clipping to do on the font if it goes outside the clipping region. Not much to say about this, just leave it set to default.
CLIP_DEFAULT_PRECIS, // Clipping Precision
Output Quality is very important.you can have PROOF, DRAFT, NONANTIALIASED, DEFAULT or ANTIALIASED. We all know that ANTIALIASED fonts look good :) Antialiasing a font is the same effect you get when you turn on font smoothing in Windows. It makes everything look less jagged.
ANTIALIASED_QUALITY, // Output Quality
Next we have the Family and Pitch settings. For pitch you can have DEFAULT_PITCH, FIXED_PITCH and VARIABLE_PITCH, and for family you can have FF_DECORATIVE, FF_MODERN, FF_ROMAN, FF_SCRIPT, FF_SWISS, FF_DONTCARE. Play around with them to find out what they do. I just set them both to default.
FF_DONTCARE|DEFAULT_PITCH, // Family And Pitch
Finally… We have the actual name of the font. Boot up Microsoft Word or some other text editor. Click on the font drop down menu, and find a font you like. To use the font, replace 'Courier New' with the name of the font you'd rather use.
"Courier New"); // Font Name
Now we select the font we just created. oldfont will point to the selected object. We then build the 96 display lists starting at character 32 (which is a blank space). You can build all 256 if you'd like, just make sure you build 256 display lists using glGenLists. After that we select the object oldfont points to and then we delete the font object.
oldfont = (HFONT)SelectObject(hDC, font); // Selects The Font We Want
wglUseFontBitmaps(hDC, 32, 96, base); // Builds 96 Characters Starting At Character 32
SelectObject(hDC, oldfont); // Selects The Font We Want
DeleteObject(font); // Delete The Font
}
The following code is pretty simple. It deletes the 96 display lists from memory starting at the first list specified by 'base'. I'm not sure if windows would do this for you, but it's better to be safe than sorry :)
GLvoid KillFont(GLvoid) // Delete The Font List
{
glDeleteLists(base, 96); // Delete All 96 Characters ( NEW )
}
Now for my handy dandy GL text routine. You call this section of code with the command glPrint("message goes here"). The text is stored in the char string *fmt.
GLvoid glPrint(const char *fmt, …) // Custom GL "Print" Routine
{
The first line below creates storage space for a 256 character string. text is the string we will end up printing to the screen. The second line below creates a pointer that points to the list of arguments we pass along with the string. If we send any variables along with the text, this will point to them.
char text[256]; // Holds Our String
va_list ap; // Pointer To List Of Arguments
The next two lines of code check to see if there's anything to display? If there's no text, fmt will equal nothing (NULL), and nothing will be drawn to the screen.
if (fmt == NULL) // If There's No Text
return; // Do Nothing
The following three lines of code convert any symbols in the text to the actual numbers the symbols represent. The final text and any converted symbols are then stored in the character string called "text". I'll explain symbols in more detail down below.
va_start(ap, fmt); // Parses The String For Variables
vsprintf(text, fmt, ap); // And Converts Symbols To Actual Numbers
va_end(ap); // Results Are Stored In Text
We then push the GL_LIST_BIT, this prevents glListBase from affecting any other display lists we may be using in our program.
The command glListBase(base-32) is a little hard to explain. Say we draw the letter 'A', it's represented by the number 65. Without glListBase(base-32) OpenGL wouldn't know where to find this letter. It would look for it at display list 65, but if base was equal to 1000, 'A' would actually be stored at display list 1065. So by setting a base starting point, OpenGL knows where to get the proper display list from. The reason we subtract 32 is because we never made the first 32 display lists. We skipped them. So we have to let OpenGL know this by subtracting 32 from the base value. I hope that makes sense.
glPushAttrib(GL_LIST_BIT); // Pushes The Display List Bits ( NEW )
glListBase(base – 32); // Sets The Base Character to 32 ( NEW )
Now that OpenGL knows where the Letters are located, we can tell it to write the text to the screen. glCallLists is a very interesting command. It's capable of putting more than one display list on the screen at a time.