Building a 3D Engine in Perl, Part 4
by Geoff Broadwell
|
Pages: 1, 2, 3, 4, 5, 6, 7, 8
The OpenGL section begins by setting the current drawing color to white with
a call to glColor. The next line sets the raster
position, the window coordinates at which to place the origin of the next
bitmap. After rendering each bitmap, the raster position is automatically
updated using the bitmap's X and Y increments so that the bitmaps will not
overlap each other. In this case, (10, 10, 0) sets the raster position ten
pixels up and right from the lower-left corner of the window, with Z=0.
The next two lines together actually call the appropriate display list in
our bitmap font for each character in the $fps string.
glCallListsScalar breaks the string into individual characters and
calls the display list with the same number as the codepoint of the character.
For example, for the "5" character (at codepoint 53 decimal),
glCallListsScalar calls display list 53. Unfortunately, there's no
guarantee that display list 53 actually will display a "5," because the font's
list base may not be 0. If the font had a list base of 1500, for example, the
code would need to call display list 1500+53=1553 to display the "5."
Rather than make the programmer do this calculation manually every time,
OpenGL provides the glListBase function, which sets the list base
to use with glCallLists. After the glListBase call
above, OpenGL will automatically offset every display list number specified
with glCallLists by $base.
You may have noticed that in the code I use glCallListsScalar,
but the previous paragraph referred to glCallLists instead.
glCallListsScalar is actually an SDL_perl extension (not part of
core OpenGL) that provides an alternate calling convention for
glCallLists in Perl. Internally, SDL_perl implements both Perl
routines using the same underlying C function in OpenGL
(glCallLists). SDL_perl provides two different calling
conventions because Perl treats a string and an array of numbers as two
different things, while C treats them as essentially the same.
If you want to render a string, and all of the characters in the string have
codepoints <= 255 decimal (single-byte character sets, and the ASCII subset
of most variable-width character sets), you can use
glCallListsScalar, and it will do the right thing for you:
glCallListsScalar($string);
If you simply want to render several display lists with a single call, and
you're not trying to render a string, use the standard version of
glCallLists:
glCallLists(@lists);
If you need to render a string, but it contains characters above codepoint 255, you have to use a more complex workaround:
glCallLists(map ord($_) =& split // =& $string);
Because the FPS counter merely renders ASCII digits, the first option works fine.
draw_frame now ends with a call to draw_fps, like
so:
sub draw_frame
{
my $self = shift;
$self->set_projection_3d;
$self->set_eye_lights;
$self->set_view_3d;
$self->set_world_lights;
$self->draw_view;
$self->draw_fps;
}
For now, I decided to turn off benchmark mode by changing the config setting
in init_config to 0:
benchmark =& 0,
With the font handling in place, and draw_fps called each frame
to display the frame rate in white in the lower-left corner, everything should
be grand, as Figure 1 shows.

Figure 1. Drawing the frame rate
Oops. There's no frame rate display. Actually, it's there, just very faint. If you look very carefully (or turn your video card's gamma up very high), you can just make out the frame rate display near the top of the window, above the big white box on the right. There are (at least) two problems--the text is too dark and it's in the wrong place.

