⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chapter04.html

📁 OpenGl红宝书
💻 HTML
📖 第 1 页 / 共 3 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-2">
   <META NAME="GENERATOR" CONTENT="Mozilla/4.07 [en] (Win98; I) [Netscape]">
   <META NAME="Author" CONTENT="Goran UnreaL Krajnovic">
   <TITLE>Chapter 4 - OpenGL Programming Guide (Addison-Wesley Publishing Company)</TITLE>
</HEAD>
<BODY BGCOLOR="#EFEFEF" LINK="#0000FF" VLINK="#551A8B" ALINK="#FF0000">

<DIV ALIGN=right><IMG SRC="figures/SGI_ID.gif" ALT="Silicon Graphics" NOSAVE HEIGHT=43 WIDTH=151 ALIGN=TEXTTOP></DIV>

<HR>
<H1>
Chapter 4<BR>
Display Lists</H1>
<B>Chapter Objectives</B>
<P>After reading this chapter, you'll be able to do the following:
<UL>Understand how clients and servers work together in a networked OpenGL
system
<BR>&nbsp;
<P>Understand how display lists can be used along with commands in immediate
mode to improve performance
<BR>&nbsp;
<P>Maximize performance by knowing how and when to use display lists</UL>
A display list is a group of OpenGL commands that have been stored for
later execution. When a display list is invoked, the commands in it are
executed in the order in which they were issued. Most OpenGL commands can
be either stored in a display list or issued in immediate mode, which causes
them to be executed immediately. You can freely mix immediate-mode programming
and display lists within a single program. The programming examples you've
seen so far have used immediate mode. This chapter discusses what display
lists are and how best to use them. It has the following major sections:
<UL>"An Example of Using a Display List" gives a brief example, showing
the basic commands for using display lists.
<BR>&nbsp;
<P>"Display-List Design Philosophy" explains when to use display lists.
<BR>&nbsp;
<P>"Creating and Executing a Display List" discusses in detail the commands
for creating and executing display lists.
<BR>&nbsp;
<P>"Managing Display Lists and Their Indices" explains how to let OpenGL
generate display-list indices for you automatically.
<BR>&nbsp;
<P>"Executing Multiple Display Lists" shows how to execute several display
lists in succession, using a small character set as an example.
<BR>&nbsp;
<P>"Encapsulating Mode Changes" tells you how to use display lists to switch
efficiently among different modes.</UL>

<HR>
<H2>
An Example of Using a Display List</H2>
A display list is a convenient and efficient way to name and organize a
set of OpenGL commands. For example, suppose you want to draw a circle
with 100 line segments. Without using display lists, you might write immediate-mode
code like this:
<PRE>drawCircle()
{
&nbsp;&nbsp; GLint i;
&nbsp;&nbsp; GLfloat cosine, sine;

&nbsp;&nbsp; glBegin(GL_POLYGON);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i=0;i&lt;100;i++){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cosine=cos(i*2*PI/100.0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sine=sin(i*2*PI/100.0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glVertex2f(cosine,sine);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp; glEnd();
}</PRE>
This method is terribly inefficient because the trigonometry has to be
performed each time the circle is rendered. Instead, you could save the
coordinates in a table, and then pull the coordinates out of the table
as needed:
<PRE>drawCircle()
{
&nbsp;&nbsp; GLint i;
&nbsp;&nbsp; GLfloat cosine, sine;
&nbsp;&nbsp; static GLfloat circoords[100][2];
&nbsp;&nbsp; static GLint inited=0;

&nbsp;&nbsp; if(inited==0){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inited=1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i=0;i&lt;100;i++){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; circcoords[i][0]=cos(i*2*PI/100.0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; circcoords[i][1]=sin(i*2*PI/100.0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp; }
&nbsp;&nbsp; glBegin(GL_POLYGON);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i=0;i&lt;100;i++)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glVertex2fv(&amp;circcoords[i][0]);
&nbsp;&nbsp; glEnd();
}</PRE>
Even with this improved method, you still incur a slight penalty from incrementing
and testing the variable<I> i</I>. What you really want to do is draw the
circle once and have OpenGL remember how to draw it for later use. This
is exactly what a display list is for, as shown in Example 4-1 .
<P><B>Example 4-1 : </B>Creating a Display List
<PRE>#define MY_CIRCLE_LIST 1

buildCircle()
{
&nbsp;&nbsp; GLint i;
&nbsp;&nbsp; GLfloat cosine, sine;

&nbsp;&nbsp; glNewList(MY_CIRCLE_LIST, GL_COMPILE);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glBegin(GL_POLYGON);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i=0;i&lt;100;i++){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cosine=cos(i*2*PI/100.0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sine=sin(i*2*PI/100.0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glVertex2f(cosine,sine);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glEnd();
&nbsp;&nbsp; glEndList();
}</PRE>
Note that the code for drawing a circle is bracketed by <B>glNewList()</B>
and <B>glEndList()</B>. As you might have guessed, these commands define
a display list. The argument MY_CIRCLE_LIST for <B>glNewList()</B> is an
integer index that uniquely identifies this display list. You can execute
the display list later with this <B>glCallList()</B> command:
<PRE>glCallList(MY_CIRCLE_LIST);</PRE>
A display list contains only OpenGL calls. Other calls - in Example 4-1
, the C functions <B>cos()</B> and <B>sin()</B> - aren't stored in the
display list. Instead, the coordinates and other variables (such as array
contents) are evaluated and copied into the display list with the values
they have when the list is compiled. After such a list has been compiled,
these values can't be changed. You can delete a display list and create
a new one, but you can't edit an existing display list.
<P>
<HR>
<H2>
Display-List Design Philosophy</H2>
OpenGL display lists are designed to optimize performance, particularly
over networks, but never at the expense of performance on a local machine.
A display list resides with the OpenGL server state, which in a networked
environment might be on a different machine than the host (or client state).
"What Is OpenGL?" discusses OpenGL's client-server model.
<P>To optimize performance, an OpenGL display list is a cache of commands
rather than a dynamic database. In other words, once a display list is
created, it can't be modified. If a display list were modifiable, performance
could be reduced by the overhead required to search through the display
list and to perform memory management. As portions of a modifiable display
list were changed, memory allocation and deallocation might lead to memory
fragmentation. Using display lists is typically at least as fast as using
immediate mode. Display lists can substantially increase performance -
particularly when you issue OpenGL routines across networks, since display
lists reside with the server and network traffic is minimized.
<P>Even locally, a display list might be more efficient since it can be
processed as it's created into a form that's more compatible with the graphics
hardware. The particular commands that are so optimized may vary from implementation
to implementation. For example, a command as simple as <B>glRotate*()</B>
might show a significant improvement if it's in a display list, since the
calculations to produce the rotation matrix aren't trivial (they can involve
square roots and trigonometric functions). In the display list, however,
only the final rotation matrix needs to be stored, so a display-list rotation
command can be executed as fast as the hardware can execute <B>glMultMatrix()</B>.
A sophisticated OpenGL implementation might even concatenate adjacent transformation
commands into a single matrix multiplication.
<P>Although you're not guaranteed that your OpenGL implementation optimizes
display lists for any particular uses, you know that execution of display
lists isn't slower than executing the commands contained within them. There
is some overhead, however, involved in jumping to a display list. If a
particular list is small, this overhead could exceed any execution advantage.
The most likely possibilities for optimization are listed below, with references
to the chapters where the topics are discussed.
<UL>Matrix operations (Chapter 3 ). Most matrix operations require OpenGL
to compute inverses. Both the computed matrix and its inverse might be
stored by a particular OpenGL implementation in a display list.
<BR>&nbsp;
<P>Raster bitmaps and images (Chapter 4 ). The format in which you specify
raster data isn't likely to be one that's ideal for the hardware. When
a display list is compiled, OpenGL might transform the data into the representation
preferred by the hardware. This can have a significant effect on the speed
of raster character drawing, since character strings usually consist of
a series of small bitmaps.
<BR>&nbsp;
<P>Lights, material properties, and lighting models (Chapter 6 ). When
you draw a scene with complex lighting conditions, you might change the
materials for each item in the scene. Setting the materials can be slow,
since it might involve significant calculations. If you put the material
definitions in display lists, these calculations don't have to be done
each time you switch materials, since only the results of the calculations
need to be stored; as a result, rendering lit scenes might be faster. See
"Encapsulating Mode Changes" for more details on using display lists to
change such values as lighting conditions.
<BR>&nbsp;
<P>Textures (Chapter 9 ). You might be able to maximize efficiency when
defining textures by compiling them into a display list, since the hardware
texture format might differ from the OpenGL format, and the conversion
can be done at display-list compile time rather than during display.
<BR>&nbsp;
<P>Polygon stipple patterns (Chapter 2 ).</UL>
Some of the commands to specify the properties listed here are context-
sensitive, so you need to take this into account to ensure optimum performance.
Most situations where this makes a difference involve pixel-transfer functions,
lighting models, and texturing. Since all these topics haven't been introduced
yet - they're covered in later chapters - the following example is a bit
contrived. Although the specifics of this example are very unlikely, it
illustrates an important principle that's discussed again in later chapters.
<P>Imagine an implementation of OpenGL that's optimized to perform matrix
transformations on vertices before storing them in a display list. If this
were true, the time needed to perform the transformations would occur before
rather than during display. Now suppose your code looked something like
this:
<PRE>glLoadMatrix(M);&nbsp;
glNewList(1, GL_COMPILE);&nbsp;
draw_some_geometric_objects();&nbsp;
glEndList();</PRE>
The vertices in the objects would be compiled into the display list after
having been transformed by matrix <B>M</B>. Suppose you invoke the display
list as follows:
<PRE>glLoadMatrix(N);
glCallList(1);</PRE>
In this case, the geometric objects should be drawn using matrix <B>N</B>,
but the data in the display list has been transformed by matrix <B>M</B>
before it was stored. Thus, the display list has to save two copies of
the original data (both the untransformed and the transformed vertices),
thereby wasting memory. In addition, the vertices undergo two transformations
when perhaps one would have sufficed. If instead you had defined the display
list as follows:
<PRE>glNewList(1, GL_COMPILE);&nbsp;
glLoadMatrix(M);&nbsp;
draw_some_geometry();&nbsp;
glEndList();</PRE>
then no extra data would have to be stored, and full optimization would
be possible. Of course, in this second case, you'd want to be sure that
matrix <B>M</B> was really the transformation matrix you wanted.
<P>Remember that display lists have some disadvantages. The <B>buildCircle()</B>
example in Example 4-1 requires storage for at least 200 floating-point
numbers, whereas the object code for the original <B>drawCircle()</B> routine
(in immediate mode) is probably a lot smaller than that. Another disadvantage
is the immutability of the contents of a display list. To optimize performance,
an OpenGL display list can't be changed, and its contents can't be read.
<P>
<HR>
<H2>
Creating and Executing a Display List</H2>
As you've already seen, <B>glNewList()</B> and <B>glEndList()</B> are used
to begin and end the definition of a display list, which is then invoked
by supplying its identifying index with <B>glCallList()</B>. In Example
4-2 , a display list is created in the <B>makeList()</B> routine. This
display list contains OpenGL commands to draw a red triangle. Then, in
the <B>display()</B> routine, the display list is executed ten times. In
addition, a line is drawn in immediate mode. Note that the display list
allocates memory to store the commands and the values of any necessary
variables.
<P><B>Example 4-2 : </B>Using a Display List: list.c
<PRE>#include &lt;GL/gl.h>
#include &lt;GL/glu.h>
#include "aux.h"

GLuint listName = 1;

void myinit (void)
{
glNewList (listName, GL_COMPILE);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glColor3f(1.0, 0.0, 0.0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glBegin (GL_TRIANGLES);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glVertex2f (0.0, 0.0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glVertex2f (1.0, 0.0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glVertex2f (0.0, 1.0);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glEnd ();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glTranslatef (1.5, 0.0, 0.0);
&nbsp;&nbsp;&nbsp; glEndList ();
&nbsp;&nbsp;&nbsp; glShadeModel (GL_FLAT);
}

void drawLine (void)
{
&nbsp;&nbsp;&nbsp; glBegin (GL_LINES);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glVertex2f (0.0, 0.5);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; glVertex2f (15.0, 0.5);
&nbsp;&nbsp;&nbsp; glEnd ();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -