Next is the RenderFontmethod, which displays a string of text using the selected bitmap font at a specified raster position: void CGfxOpenGL::RenderFontint xPos, int yPos, unsigned int b
Trang 1setting up the bitmap font for use with Windows through the wglUseFontBitmaps()
func-tion, the CreateBitmapFont()method returns the base ID for the character display list
Next is the RenderFont()method, which displays a string of text using the selected bitmap
font at a specified raster position:
void CGfxOpenGL::RenderFont(int xPos, int yPos, unsigned int base, char *str)
{
if ((base == 0) || (!str)) return;
TheRenderFont()method is very simple in that it verifies the base ID and string it receives
before setting the raster position and rendering the text display list Finally, we have the
ReleaseFont()method, which simply cleans up the font display list:
void CGfxOpenGL::ReleaseFont(unsigned int base)
{
if (base != 0) glDeleteLists(base, 96);
}
The rest of the code uses these functions to display the screenshot shown in Figure 11.1
The example is set up in orthographic projection We recommend orthographic
projec-tion when rendering with bitmap fonts because it enables you to specify the raster
posi-tion coordinates in window coordinates, and you don’t need to worry about the
perspective projection affecting the raster position
That’s all for bitmap fonts! Let’s look at another technique for putting text on the screen:
outline fonts
Outline Fonts
Outline fonts are very similar to the bitmap fonts we just discussed, but they are much
more fun to play around with! Outline fonts define characters in a font as a series of lines
and curves, which means they can be scaled up and down without a loss in quality With
Trang 2OpenGL, you can move outline font text around the screen in 3D, give the font text somethickness, and essentially turn any font on the current system into a 3D font with all thefunctionality of other 3D objects.
To use outline fonts, you first need to declare an array of 256 GLYPHMETRICSFLOATvariables,which hold information about the placement and orientation of a glyph in a charactercell TheGLYPHMETRICSFLOATstructure is a special structure created specifically for using textwith OpenGL It is defined as:
typedef struct _GLYPHMETRICSFLOAT { // gmf FLOAT gmfBlackBoxX;
You’ll pass the GLYPHMETRICSFLOATvariable you create to the wglUseFontOutlines()function
This function creates a set of display lists, one for each glyph of the current outline font,which you can use to render text to the screen This function is defined as:
BOOL wglUseFontOutlines(
HDC hdc, // device context of the outline font DWORD first, // first glyph to be turned into a display list DWORD count, // number of glyphs to be turned into display lists DWORD listBase, // specifies the starting display list
FLOAT deviation, // specifies the maximum chordal deviation from the
// true outlines FLOAT extrusion, // extrusion value in the negative-z direction int format, // specifies line segments or polygons in display lists LPGLYPHMETRICSFLOAT lpgmf // address of buffer to receive glyph metric data );
Creation of the outline font is essentially the same as the bitmap font with the addition ofthese two items For instance, compare the CreateBitmapFont()function we showed earlierwith this CreateOutlineFont()function:
unsigned int CreateOutlineFont(char *fontName, int fontSize, float depth) {
HFONT hFont; // windows font unsigned int base;
base = glGenLists(256); // create storage for 256 characters
if (stricmp(fontName, “symbol”) == 0)
Chapter 11 ■ Displaying Text254
Trang 3{ hFont = CreateFont(fontSize, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
SYMBOL_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_DONTCARE | DEFAULT_PITCH, fontName);
} else { hFont = CreateFont(fontSize, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_DONTCARE | DEFAULT_PITCH, fontName);
}
if (!hFont) return 0;
SelectObject(g_HDC, hFont);
wglUseFontOutlines(g_HDC, 0, 255, base, 0.0f, depth, WGL_FONT_POLYGONS, gmf);
return base;
}
As you can see, this function is very similar to the CreateBitmapFont()method we showed
earlier, but there are a few differences The first difference you might notice is the addition
of the depth parameter, which is used by the wglUseFontOutlines()function to define the
length of the outline font text along the z-axis (or essentially the depth of the font) The
next difference is that you create 256 display lists instead of 96 This is because you
want to provide support for all the 256 available ASCII codes And lastly, you use the
wglUseFontOutlines()function to finalize the setup of the outline fonts for OpenGL
Displaying outline font text is exactly the same as displaying bitmap font text Because you
used all 256 ASCII codes when initializing the outline font, here is how the display code
On the CD included with this book you will find the OutlineFont example for Chapter 11
This example renders text as an outline font to the window and rotates it A screenshot is
shown in Figure 11.2
Trang 4The majority of the code for this example is the same as the BitmapFont example, so wewill focus only on the RenderFont()method because it is the most different:
void CGfxOpenGL::RenderFont(float xPos, float yPos, float zPos, unsigned int base, char *str)
{ float length = 0.0;
if ((base == 0) || (!str)) return;
// center the text for (int idx = 0; idx < (int)strlen(str); idx++) // find length of text {
length += gmf[str[idx]].gmfCellIncX; // increase length by character’s width }
glTranslatef(-length/2.0f, yPos, zPos);
Trang 5TheRenderFont()method includes some code that centers the text on the point in space to
which the text is being drawn This is accomplished through a loop that goes through each
character in the text string that you are displaying During each iteration of the loop, you
add the character’s width, which you obtain from the GLYPHMETRICSFLOATvariable, to a
vari-able that stores the sum of all the characters’ widths You then translate your coordinate
system along the negative x-axis by half the total length of the text string, resulting in the
text being centered on the (xPos,yPos, zPos) point in 3D space.
Also, the glRotatef()calls you see in the method are there only for demonstration
pur-poses and should not be in the RenderFont()method during normal use
You can also texture map outline fonts since they are constructed of polygons Instead of
trying to figure out the texture coordinates on your own, you can use OpenGL’s automatic
texture-coordinate generation functionality to texture map the text You can find more
information on texture-coordinate generation in Chapter 9, “More on Texture Mapping.”
Using glFont
glFontis both a program executable and an API with source code that takes any Windows
TrueType font and turns it into an OpenGL texture.glFontdetermines the appropriate
texture coordinates and displays text with correct spacing and size on an OpenGL
quadri-lateral Its design is not for 3D text, but rather for 2D text for use in games and other
graphics applications where 3D text is overkill
You can find glFonton the CD included with this book, or you can get it from the glFont
Web site at http://students.cs.byu.edu/~bfish/glfont.php
The Executable
The program included with glFontis glFont.exe, which is a simple-to-use program for
creating font textures that the glFontAPI code can read and display The process for using
Trang 64 Generate the texture.
5 Save the texture to a GLF file
Explore and experiment!
Summary
In this chapter you learned how to display and position 2D text with bitmap fonts usingthe wglUseFontBitmaps() function and display lists You also learned how to display andposition 3D text with outline fonts using the wglUseFontOutlines()function Finally, weintroduced the glFontOpenGL font library, which you can use and modify to suit yourtext rendering purposes
What You Have Learned
■ ThewglUseFontBitmaps()function generates bitmap fonts from the font files loaded
on the execution system
Chapter 11 ■ Displaying Text258
Trang 7■ Display lists can be used to render each character of a font.
■ When rendering bitmap fonts, you should use an orthographic perspective tion to simplify positioning the text
projec-■ ThewglUseFontOutlines()function creates a set of display lists, one for each glyph
of the current outline font
■ TheGLYPHMETRICSFLOATstruct is used when creating outline fonts This struct isincluded particularly for rendering text with OpenGL
■ You can texture map outline fonts and specify texture coordinates with the matic texture coordinate generation functionality provided with OpenGL
auto-■ glFontis both a program executable and an API with source code that takes anyWindows TrueType font and turns it into an OpenGL texture
Review Questions
1 What “wiggle” function is used to create bitmap fonts?
2 What “wiggle” function is used to create outline fonts?
3 How do you texture map outline fonts?
Trang 8This page intentionally left blank
Trang 9OpenGL Buffers
chapter 12
We’ve been discussing buffers is some form for quite some time now but
haven’t really taken the time to discuss them in detail For instance, we’veused the color and depth buffers in nearly every example thus far for func-tions such as double-buffering and hidden surface removal In this chapter, we’ll extend
beyond these basic functionalities while also looking at two more buffers, called the
sten-cil buffer and the accumulation buffer
In this chapter, you’ll learn:
■ What the framebuffer is
■ What general operations can be performed on buffers
■ How to use the alpha test, color masking, and logic ops
■ How to use the depth buffer
■ How to use the stencil buffer
■ How to use the accumulation buffer
What Is an OpenGL Buffer?
There are several buffers in OpenGL that you can use and manipulate, but just what exactly
is a buffer? Simply put, a buffer is a set of sequential locations in memory In OpenGL, a
buffer is section of memory that is used to represent some aspect of the display For
exam-ple, the color buffer stores RGBA data for each pixel on the screen or window
All the buffers in a system are collectively referred to as the framebuffer So with OpenGL,
the color buffer, depth buffer, stencil buffer, and accumulation buffer combine to give you
Trang 10a single framebuffer When you operate on any OpenGL buffer, you are operating on theframebuffer.
Before discussing individual buffer types, we’ll first look at a couple of operations thatapply to all of the buffers: clearing and scissoring
Clearing the Buffers
The most basic operation you can perform on a buffer is to clear out the previous tents This is done using glClear():
con-void glClear(GLbitfield mask);
You’ve already seen this in action in all ofthe demos presented so far, so it shouldlook familiar The mask parameter is thebitwise logical ORof a combination of thevalues listed in Table 12.1
Each buffer has a default value, and whenyou clear it, each element in the buffer isset to that value As with most areas ofOpenGL, you can set the default clearvalues to your own custom values You do so with the following APIs:
void glClearColor(GLclampf red, GLclampf green, GLclampf green, GLclampf alpha);
void glClearDepth(GLclampd depth);
void glClearStencil(GLint i);
void glClearAccum(GLclampf red, GLclampf green, GLclampf green, GLclampf alpha);
TheGLclamptypes are used for parameters that are internally clamped to fall within 0.0 and1.0 The default values for all buffers are 0, except for the depth buffer, which is 1.0, cor-responding to the value that represents elements that are farthest away from the camera
Scissor Boxes
OpenGL allows you to define a scissor box that limits rendering to a sub-region of the
screen When scissoring is enabled, any pixel writes outside of the box are ignored Thisapplies to not only color values, but depth, stencil, and accumulation buffer values as well
Scissoring is one of the few operations that also affect the operation ofglClear(); when it
is enabled, only pixels inside of the scissor box will be cleared
You can enable scissoring by passing GL_SCISSOR_TESTto glEnable() The size of the scissorbox is defined using:
void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
Chapter 12 ■ OpenGL Buffers262
Table 12.1 Clear Mask Values
GL_COLOR_BUFFER_BIT RGBA color buffer
GL_DEPTH_BUFFER_BIT Depth buffer
GL_STENCIL_BUFFER_BIT Stencil buffer
GL_ACCUM_BUFFER_BIT Accumulation buffer
Trang 11Thexandyvalues correspond to the screen coordinates of the lower left corner of the box
(the lower left corner of the screen is at (0, 0)) widthandheightare the dimensions of the
box in pixels The scissor box is set to the size of the window when a rendering context is
first attached to it
The following code shows an example of setting up a scissor box such as that shown in
Figure 12.1
glEnable(GL_SCISSOR_TEST);
glScissor(200, 250, 240, 180);
The Color Buffer
The color buffer stores RGBA data for each pixel on the screen Almost everything discussed
in this book relates to the color buffer in some way There are a few operations in addition
to those that we’ve already discussed that affect the color buffer on a per-fragment basis,
and those will be described in this section
Alpha Test
Every incoming fragment has an alpha value associated with it Even if you don’t specify
it yourself, it gets set to the default value of 1 The alpha test can be used to discard
frag-ments based on their alpha value Practical applications for this include being able to
dis-card transparent components of images
Figure 12.1 An example of a scissor box.
Trang 12For example, say you are using the image in Figure12.2 for billboarding, in which you apply the image
as a texture to a screen-oriented quad to cheaplyfake a 3D cactus When applying the texture map,you would want to draw only the pixels that make
up the cactus Drawing the black area around itwould ruin the effect Alpha testing is the best way
to do this
The first step is to initialize the texture with priate values, such as an alpha of 0 in the blackareas and 1 everywhere else The next step is toenable the alpha test, which you would do with:
appro-glEnable(GL_ALPHA_TEST);
Then you need to set up the alpha function The alpha function controls exactly how thecomparison is done It is specified by using:
void glAlphaFunc(GLenum func, GLclampf reference);
funcis an enumeration specifying the comparison function Valid values are listed in Table12.2 The incoming fragment alpha is compared against the referencevalue Continuingwith the cactus example, setting up the alpha function as follows would reject the blackpixels (with an alpha of 0) and accept everything else
glAlphaFunc(GL_GREATER, 0.0);
The alpha test is an easy to use tool that has many practical applications in games
Chapter 12 ■ OpenGL Buffers264
Table 12.2 Alpha Test Functions
Function Description
GL_NEVER Never pass, regardless of the fragment or reference alpha values.
GL_ALWAYS Always pass, regardless of the fragment or reference alpha values This is the default.
GL_LESS Pass if the fragment alpha is less than the reference value.
GL_LEQUAL Pass if the fragment alpha is less than or equal to the reference value.
GL_EQUAL Pass if the fragment alpha is equal to the reference value.
GL_GEQUAL Pass if the fragment alpha is greater than or equal to the reference value.
GL_GREATER Pass if the fragment alpha is greater than the reference value.
GL_NOTEQUAL Pass if the fragment alpha not equal to the reference value.
Figure 12.2 An image used as a
billboard texture
Trang 13Color Masking
OpenGL allows you to disable writing to specific color channels This can be used to
cre-ate some interesting effects For example, some multipass rendering algorithms require
you to modify the depth buffer without actually writing color values Another use might
be to disable writing to everything but the green channel to create a cheap night vision
effect
This is known as color masking, and it is controlled through the following API:
void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
PassingGL_FALSEas the red,green, blue, or alphaparameter will disable writes for that
chan-nel.GL_TRUEis used to enable writes By default, all of the channels are enabled, as you’d
expect
The color mask affects all operations that may potentially modify the color buffer,
includ-ing clears
Logical Operations
OpenGL allows you to create some
interest-ing effects by performinterest-ing logical operations
between the incoming fragment and the
value in the color buffer These are executed
as bitwise logical operations between each
of the individual red, green, blue, and alpha
components of the two colors The
result-ing value is then stored in the color buffer
Logic ops are enabled by passing
GL_COLOR_LOGIC_OP to glEnable() You can
specify which specific operation to perform
by using:
void glLogicOp(GLenum op);
op can be any of the enumerants listed in
Table 12.3, where the fragment color is
rep-resented as s, the value in the color buffer is
d, and the resulting color is c The notation
used corresponds to the C/C++ notation
for bitwise operations
Table 12.3 Logical Operations
GL_AND c = s & d GL_AND_REVERSE c = s & (~d)