📄 chapter04.html
字号:
void display(void)
{
GLuint i;
glClear (GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 1.0, 0.0);
for (i = 0; i < 10; i++)
glCallList (listName);
drawLine ();
glFlush ();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
gluOrtho2D (0.0, 2.0, -0.5 * (GLfloat) h/(GLfloat) w,
1.5 * (GLfloat) h/(GLfloat) w);
else
gluOrtho2D (0.0, 2.0 * (GLfloat) w/(GLfloat) h, -0.5,
1.5);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 400, 50);
auxInitWindow (argv[0]);
myinit ();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}</PRE>
The <B>glTranslatef()</B> routine in the display list alters the position
of the next object to be drawn. Without it, calling the display list twice
would just draw the triangle on top of itself. The <B>drawLine()</B> routine,
which is called in immediate mode, is also affected by the ten <B>glTranslatef()</B>
calls that precede it. Thus, if you call transformation commands within
a display list, don't forget to take the effect of those commands into
account later in your program.
<P>Only one display list can be created at a time. In other words, you
must eventually follow <B>glNewList()</B> with <B>glEndList()</B> to end
the creation of a display list before starting another one. As you might
expect, calling <B>glEndList()</B> without having started a display list
generates the error GL_INVALID_OPERATION. void <B>glNewList</B> (GLuint
<I>list</I>, GLenum <I>mode</I>);
<P>Specifies the start of a display list. OpenGL routines that are called
subsequently (until <B>glEndList()</B> is called to end the display list)
are stored in a display list, except for a few restricted OpenGL routines
that can't be stored. (Those restricted routines are executed immediately,
during the creation of the display list.) The <I>list</I> parameter is
a unique positive integer that identifies the display list. The possible
values for the <I>mode</I> parameter are GL_COMPILE and GL_COMPILE_AND_EXECUTE.
Use GL_COMPILE if you don't want the following OpenGL commands executed
as they're placed in the display list; to cause the commands to be executed
immediately as well as placed in the display list for later use, specify
GL_COMPILE_AND_EXECUTE.
<P>void <B>glEndList</B> (void);
<P>Marks the end of a display list.
<H3>
What's Stored in a Display List</H3>
When you're building a display list, only the values for expressions are
stored in the list. Thus, if values in an array are subsequently changed,
for example, the display-list values don't change. In the following code
fragment, the display list contains a command to set the current color
to black (0.0, 0.0, 0.0). The subsequent change of the value of the <I>color_vector</I>
array to red (1.0, 0.0, 0.0) has no effect on the display list because
the display list contains the values that were in effect when it was created.
<PRE>GLfloat color_vector[3]={0.0,0.0,0.0};
glNewList(1,GL_COMPILE);
glColor3fv(color_vector);
glEndList();
color_vector[0]=1.0;</PRE>
Not all OpenGL commands can be stored and executed from within a display
list. Generally, commands that pass parameters by reference or that return
a value can't be stored in a display list, since the list might be called
outside the scope of where the parameters are originally defined. If such
commands are called when making a display list, they're executed immediately
and aren't stored in the display list. Here are the OpenGL commands that
aren't stored in a display list (also, note that <B>glNewList()</B> generates
an error if it's called while you're creating a display list). Some of
these commands haven't been described yet; you can look in the index to
see where they're discussed.
<P>glDeleteLists() glIsEnabled()
<P>glFeedbackBuffer() glIsList()
<P>glFinish() glPixelStore()
<P>glFlush() glReadPixels()
<P>glGenLists() glRenderMode()
<P>glGet*() glSelectBuffer()
<P>To understand more clearly why these commands can't be stored in a display
list, remember that when you're using OpenGL across a network, the client
may be on one machine and the server on another. After a display list is
created, it resides with the server, so the server can't rely on the client
for any information related to the display list. If querying commands,
such as <B>glGet*() </B>or <B>glIs*()</B>, were allowed in a display list,
the calling program would be surprised at random times by data returned
over the network. Without parsing the display list as it was sent, the
calling program wouldn't know where to put the data. Thus, any command
that returns a value can't be stored in a display list. Other routines
- such as <B>glFlush()</B> and <B>glFinish()</B> - can't be stored in a
display list because they depend on information about the client state.
Finally, commands that change a state value maintained by the client can't
be stored in a display list.
<H3>
Executing a Display List</H3>
After you've created a display list, you can execute it by calling <B>glCallList()</B>.
Naturally, you can execute the same display list many times, and you can
mix calls to execute display lists with calls to perform immediate-mode
graphics, as you've already seen. void <B>glCallList</B> (GLuint <I>list</I>);
<P>This routine executes the display list specified by <I>list</I>. The
commands in the display list are executed in the order they were saved,
just as if they were issued without using a display list. If <B>list</B>
hasn't been defined, nothing happens.
<P>Since a display list can contain calls that change the value of OpenGL
state variables, these values change as the display list is executed, just
as if the commands were called in immediate mode. The changes to OpenGL
state persist after execution of the display list is completed. In Example
4-2 , the changes to the current color and current matrix made during the
execution of the display list remain in effect after it's been called,
as shown in Example 4-3 .
<P><B>Example 4-3 : </B>Persistence of State Changes after Execution of
a Display List
<PRE>glNewList(listIndex,GL_COMPILE);
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(0.0,0.0);
glVertex2f(1.0,0.0);
glVertex2f(0.0,1.0);
glEnd();
glTranslatef(1.5,0.0,0.0);
glEndList();</PRE>
Sometimes you want state changes to persist, but other times you want to
save the values of state variables before executing a display list and
then restore these values after the list has executed. Use <B>glPushAttrib()</B>
to save a group of state variables and <B>glPopAttrib()</B> to restore
the values when you're ready for them. (See Appendix B for more information
about these commands.) To save and restore the current matrix, use <B>glPushMatrix()</B>
and <B>glPopMatrix()</B> as described in "Manipulating the Matrix Stacks."
To restore the state variables in Example 4-3 , you might use the code
shown in Example 4-4 .
<P><B>Example 4-4 : </B>Restoring State Variables within a Display List
<PRE>glNewList(listIndex,GL_COMPILE);
glPushMatrix();
glPushAttrib(GL_CURRENT_BIT);
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(0.0,0.0);
glVertex2f(1.0,0.0);
glVertex2f(0.0,1.0);
glEnd();
glTranslatef(1.5,0.0,0.0);
glPopAttrib();
glPopMatrix();
glEndList();</PRE>
Thus, if you used this kind of a display list that restores values, the
code in Example 4-5 would draw a green, untranslated line. With the display
list in Example 4-3 that doesn't save and restore values, the line drawn
would be red, and its position would be translated.
<P><B>Example 4-5 : </B>Using a Display List That Restores State Variables
<PRE>void display(void)
{
GLint i;
glClear (GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 1.0, 0.0);
for (i = 0; i < 10; i++)
glCallList (listIndex);
drawLine ();
glFlush ();
}</PRE>
You can call <B>glCallList()</B> from anywhere within a program, as long
as its OpenGL context is still active. A display list can be created in
one routine and executed in a different one, since its index uniquely identifies
it. Also, there is no facility to save the contents of a display list into
a data file, nor a facility to create a display list from a file. In this
sense, a display list is designed for temporary use. Also, a display list
is destroyed when its OpenGL context is destroyed.
<H3>
Hierarchical Display Lists</H3>
You can create a <I>hierarchical display list</I>, which is a display list
that executes another display list, by calling <B>glCallList()</B> between
a <B>glNewList()</B> and <B>glEndList()</B> pair. A hierarchical display
list is useful for an object that's made of components, especially if some
of those components are used more than once. For example, this is a display
list that renders a bicycle by calling other display lists to render parts
of the bicycle:
<PRE>glNewList(listIndex,GL_COMPILE);
glCallList(handlebars);
glCallList(frame);
glTranslatef(1.0,0.0,0.0);
glCallList(wheel);
glTranslatef(3.0,0.0,0.0);
glCallList(wheel);
glEndList();</PRE>
To avoid infinite recursion, there's a limit on the nesting level of display
lists; the limit is at least 64, but it might be higher, depending on the
implementation. To determine the nesting limit for your implementation
of OpenGL, call
<PRE>glGetIntegerv(GL_MAX_LIST_NESTING, GLint *data);</PRE>
OpenGL allows you to create a display list that calls another list that
hasn't been created yet. Nothing happens when the first list calls the
second, undefined one.
<P>You can use a hierarchical display list to approximate an editable display
list by wrapping a list around several lower-level lists. For example,
to put a polygon in a display list while allowing yourself to be able to
easily edit its vertices, you could use the code in Example 4-6 .
<P><B>Example 4-6 : </B>Using a Hierarchical Display List
<PRE>glNewList(1,GL_COMPILE);
glVertex3f(v1);
glEndList();
glNewList(2,GL_COMPILE);
glVertex3f(v2);
glEndList();
glNewList(3,GL_COMPILE);
glVertex3f(v3);
glEndList();
glNewList(4,GL_COMPILE);
glBegin(GL_POLYGON);
glCallList(1);
glCallList(2);
glCallList(3);
glEnd();
glEndList();</PRE>
To render the polygon, call display list number 4. To edit a vertex, you
need only recreate the single display list corresponding to that vertex.
Since an index number uniquely identifies a display list, creating one
with the same index as an existing one automatically deletes the old one.
Keep in mind that this technique doesn't necessarily provide optimal memory
usage or peak performance, but it's acceptable and useful in some cases.
<P>
<HR>
<H2>
Managing Display Lists and Their Indices</H2>
So far, we've used an arbitrary positive integer as a display-list index.
This could be dangerous in practice because you might accidentally choose
an index that's already in use, thereby overwriting an existing display
list. To avoid accidental deletions, use <B>glGenLists()</B> to generate
an unused index and <B>glIsList()</B> to determine whether a specific index
is in use. You can explicitly delete a specific display list or a range
of lists with <B>glDeleteLists()</B>. GLuint <B>glGenLists</B>(GLsizei
<I>range</I>);
<P>Allocates <I>range</I> number of contiguous, previously unallocated
display-list indices. The integer returned is the index that marks the
beginning of a contiguous block of empty display-list indices. The returned
indices are all marked as empty and used, so subsequent calls to <B>glGenLists()</B>
don't return these indices until they're deleted. Zero is returned if the
requested number of indices isn't available, or if <I>range</I> is zero.
<P>GLboolean <B>glIsList</B>(GLuint <I>list</I>);
<P>Returns TRUE if <I>list</I> is already used for a display list and FALSE
otherwise.
<P>In the following example, a single index is requested, and if it proves
to be available, it's used to create a new display list:
<PRE>listIndex=glGenLists(1);
if(listIndex!=0) {
glNewList(listIndex,GL_COMPILE);
...
glEndList();
}</PRE>
The command <B>glDeleteLists()</B> deletes a contiguous group of display
lists, thereby making their indices available again. void <B>glDeleteLists</B>(GLuint
<I>list</I>, GLsizei <I>range</I>);
<P>Deletes <I>range</I> display lists, starting at the index specified
by <I>list</I>. An attempt to delete a list that has never been created
is ignored.
<P>
<HR>
<H2>
Executing Multiple Display Lists</H2>
OpenGL provides an efficient mechanism to execute several display lists
in succession. This mechanism requires that you put the display-list indices
in an array and call <B>glCallLists()</B>. An obvious use for such a mechanism
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -