📄 chapter04.html
字号:
occurs when display-list indices correspond to meaningful values. For example,
if you're creating a font, each display-list index might correspond to
the ASCII value of a character in that font. To have several such fonts,
you would need to establish a different initial display-list index for
each font. You can specify this initial index by using <B>glListBase()</B>
before calling <B>glCallLists()</B>. void <B>glListBase</B>(GLuint <I>base</I>);
<P>Specifies the offset that's added to the display-list indices in <B>glCallLists()</B>
to obtain the final display-list indices. The default display-list base
is 0. The list base has no effect on <B>glCallList()</B>, which executes
only one display list, or on <B>glNewList()</B>.
<P>void <B>glCallLists</B>(GLsizei <I>n</I>, GLenum <I>type</I>, const
GLvoid *<I>lists</I>);
<P>Executes <I>n</I> display lists. The indices of the lists to be executed
are computed by adding the offset indicated by the current display-list
base (specified with <B>glListBase()</B>) to the signed integer values
in the array pointed to by <I>lists</I>.
<P>The <I>type</I> parameter indicates the data type and the "stride" (or
size) of each element in the array of indices. It's usually one of these
constants: GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT,
GL_UNSIGNED_INT, or GL_FLOAT. It can also be GL_2_BYTES, GL_3_BYTES, or
GL_4_BYTES, in which case sequences of two, three, or four bytes are shifted
and added together, byte by byte, to calculate the display-list offset,
using this algorithm:
<PRE>/* b = 2, 3, or 4; bytes are numbered 0, 1, 2, 3 in array */
offset = 0;
for (i = 0; i < b; i++) {
offset = offset << 8;
offset += byte[i];
}
index = offset + listbase;</PRE>
This means that for multiple-byte data, as bytes are taken from the array
in order, the highest-order data comes first.
<P>As an example of the use of multiple display lists, look at the program
fragments in Example 4-7 taken from the full program in Example 4-8 . This
program draws characters with a stroked font (a set of letters made from
line segments). The routine <B>initStrokedFont()</B> sets up the display-list
indices for each letter so they correspond with their ASCII values.
<P><B>Example 4-7 : </B>Defining Multiple Display Lists
<PRE>void initStrokedFont(void)
{
GLuint base;
base = glGenLists (128);
glListBase(base);
glNewList(base+'A', GL_COMPILE);
drawLetter(Adata); glEndList();
glNewList(base+'E', GL_COMPILE);
drawLetter(Edata); glEndList();
glNewList(base+'P', GL_COMPILE);
drawLetter(Pdata); glEndList();
glNewList(base+'R', GL_COMPILE);
drawLetter(Rdata); glEndList();
glNewList(base+'S', GL_COMPILE);
drawLetter(Sdata); glEndList();
glNewList(base+' ', GL_COMPILE); /* space character */
glTranslatef(8.0, 0.0, 0.0); glEndList();
}</PRE>
The <B>glGenLists()</B> command allocates 128 contiguous display-list indices.
The first of the contiguous indices becomes the display-list base. A display
list is made for each letter; each display-list index is the sum of the
base and the ASCII value of that letter. In this example, only a few letters
and the space character are created.
<P>After the display lists have been created, <B>glCallLists()</B> can
be called to execute the display lists. For example, you can pass a character
string to the subroutine <B>printStrokedString()</B>:
<PRE>void printStrokedString(GLbyte *s)
{
GLint len = strlen(s);
glCallLists(len, GL_BYTE, s);
}</PRE>
The ASCII value for each letter in the string is used as the offset into
the display-list indices. The current list base is added to the ASCII value
of each letter to determine the final display-list index to be executed.
The output produced by Example 4-8 is shown in Figure 4-1 .
<P><IMG SRC="figures/stroke.gif" ALT="[IMAGE]" >
<P><B>Figure 4-1 : </B>Example of a Stroked Font That Defines the Characters
A, E, P, R, S
<BR>
<BR>
<P><B>Example 4-8 : </B>Using Multiple Display Lists to Define a Stroked
Font: stroke.c
<PRE>#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
#define PT 1
#define STROKE 2
#define END 3
typedef struct charpoint {
GLfloat x, y;
int type;
} CP;
CP Adata[] = {
{ 0, 0, PT}, {0, 9, PT}, {1, 10, PT}, {4, 10, PT},
{5, 9, PT}, {5, 0, STROKE}, {0, 5, PT}, {5, 5, END}
};
CP Edata[] = {
{5, 0, PT}, {0, 0, PT}, {0, 10, PT}, {5, 10, STROKE},
{0, 5, PT}, {4, 5, END}
};
CP Pdata[] = {
{0, 0, PT}, {0, 10, PT}, {4, 10, PT}, {5, 9, PT},
{5, 6, PT}, {4, 5, PT}, {0, 5, END}
};
CP Rdata[] = {
{0, 0, PT}, {0, 10, PT}, {4, 10, PT}, {5, 9, PT},
{5, 6, PT}, {4, 5, PT}, {0, 5, STROKE}, {3, 5, PT},
{5, 0, END}
};
CP Sdata[] = {
{0, 1, PT}, {1, 0, PT}, {4, 0, PT}, {5, 1, PT}, {5, 4, PT},
{4, 5, PT}, {1, 5, PT}, {0, 6, PT}, {0, 9, PT}, {1, 10, PT},
{4, 10, PT}, {5, 9, END}
};
void drawLetter(CP *l)
{
glBegin(GL_LINE_STRIP);
while (1) {
switch (l->type) {
case PT:
glVertex2fv(&l->x);
break;
case STROKE:
glVertex2fv(&l->x);
glEnd();
glBegin(GL_LINE_STRIP);
break;
case END:
glVertex2fv(&l->x);
glEnd();
glTranslatef(8.0, 0.0, 0.0);
return;
}
l++;
}
}
void myinit (void)
{
GLuint base;
glShadeModel (GL_FLAT);
base = glGenLists (128);
glListBase(base);
glNewList(base+'A', GL_COMPILE); drawLetter(Adata);
glEndList();
glNewList(base+'E', GL_COMPILE); drawLetter(Edata);
glEndList();
glNewList(base+'P', GL_COMPILE); drawLetter(Pdata);
glEndList();
glNewList(base+'R', GL_COMPILE); drawLetter(Rdata);
glEndList();
glNewList(base+'S', GL_COMPILE); drawLetter(Sdata);
glEndList();
glNewList(base+' `, GL_COMPILE);
glTranslatef(8.0, 0.0, 0.0); glEndList();
}
char *test1 = "A SPARE SERAPE APPEARS AS";
char *test2 = "APES PREPARE RARE PEPPERS";
void printStrokedString(char *s)
{
GLsizei len = strlen(s);
glCallLists(len, GL_BYTE, (GLbyte *)s);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glPushMatrix();
glScalef(2.0, 2.0, 2.0);
glTranslatef(10.0, 30.0, 0.0);
printStrokedString(test1);
glPopMatrix();
glPushMatrix();
glScalef(2.0, 2.0, 2.0);
glTranslatef(10.0, 13.0, 0.0);
printStrokedString(test2);
glPopMatrix();
glFlush();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 440, 120);
auxInitWindow (argv[0]);
myinit ();
auxMainLoop(display);
}</PRE>
<HR>
<H2>
Encapsulating Mode Changes</H2>
You can use display lists to organize and store groups of commands to change
various modes or set various parameters. When you want to switch from one
group of settings to another, using display lists might be more efficient
than making the calls directly, since the settings might be cached in a
format that matches the requirements of your graphics system.
<P>Display lists are likely to be more efficient when you're switching
between multiple texture maps, for example. (Texture mapping is described
in Chapter 9 .) Suppose you have two different textures that are fairly
large, as textures tend to be, but that both of them fit into texture memory.
Without display lists, you would have to load the data for the first texture,
use it to draw some objects, wait for the second texture to be loaded into
memory, and then use it for drawing. When you want to switch back to the
first texture, it would have to be loaded into memory again rather than
being plucked out of texture memory. There's no way for OpenGL to know
that it's already been stored without the display-list mechanism to provide
a "handle" to identify it. With display lists, both textures can be loaded
into texture memory once and then used as often as necessary without having
to be reloaded.
<P>Another case where display lists are likely to be more efficient than
immediate mode is for switching among various lighting, lighting-model,
and material-parameter settings. (These topics are discussed in Chapter
6 .) You might also use display lists for stipple patterns, fog parameters,
and clipping-plane equations. In general, you're guaranteed that executing
display lists is at least as fast as making the relevant calls directly,
but remember that some overhead is involved in jumping to a display list.
<P>Example 4-9 shows how to use display lists to switch among three different
line stipples. First, you call <B>glGenLists()</B> to allocate a display
list for each stipple pattern and create a display list for each pattern.
Then, you use <B>glCallList()</B> to switch from one stipple pattern to
another.
<P><B>Example 4-9 : </B>Using Display Lists for Mode Changes
<PRE>GLuint offset;
offset = glGenLists (3);
glNewList (offset, GL_COMPILE);
glDisable (GL_LINE_STIPPLE);
glEndList ();
glNewList (offset+1, GL_COMPILE);
glEnable (GL_LINE_STIPPLE);
glLineStipple (1, 0x0F0F);
glEndList ();
glNewList (offset+2, GL_COMPILE);
glEnable (GL_LINE_STIPPLE);
glLineStipple (1, 0x1111);
glEndList ();
#define drawOneLine(x1,y1,x2,y2) glBegin(GL_LINES); \
glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd();
glCallList (offset);
drawOneLine (50.0, 125.0, 350.0, 125.0);
glCallList (offset+1);
drawOneLine (50.0, 100.0, 350.0, 100.0);
glCallList (offset+2);
drawOneLine (50.0, 75.0, 350.0, 75.0);</PRE>
<HR>
<A HREF="chapter03.html">[Previous chapter]</A> <A HREF="chapter05.html">[Next
chapter]</A>
<HR>
See the <A HREF="about.html">About</A> page for copyright, authoring
and distribution information.
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -