16.2.1 创建显示列表
OpenGL提供类似于绘制图元的结构即glBegin()与glEnd()的形式创建显示列表,其相应的函数为:
void glNewList(GLuint list,GLenum mode);
说明一个显示列表的开始,其后的OpenGL函数存入显示列表中,直至调用结束表的函数(见下面)。参数list是一个正整数,它标志唯一的显示列表。参数mode的可能值有GL_COMPILE和GL_COMPILE_AND_EXECUTE。若要使后面的函数语句只存入而不执行,则用GL_COMPILE;若要使后面的函数语句存入表中且按瞬时方式执行一次,则用GL_COMPILE_AND_EXECUTE。
void glEndList(void);
标志显示列表的结束。
注意
:并不是所有的OpenGL函数都可以在显示列表中存储且通过显示列表执行。一般来说,用于传递参数或返回数值的函数语句不能存入显示列表,因为这张表有可能在参数的作用域之外被调用;如果在定义显示列表时调用了这样的函数,则它们将按瞬时方式执行并且不保存在显示列表中,有时在调用执行显示列表函数时会产生错误。以下列出的是不能存入显示列表的OpenGL函数:
glDeleteLists() glIsEnable()
glFeedbackBuffer() glIsList()
glFinish() glPixelStore()
glGenLists() glRenderMode()
glGet*() glSelectBuffer()
16.2.2 执行显示列表
在建立显示列表以后就可以调用执行显示列表的函数来执行它,并且允许在程序中多次执行同一显示列表,同时也可以与其它函数的瞬时方式混合使用。显示列表执行的函数形式如下:
void glCallList(GLuint list);
执行显示列表。参数list指定被执行的显示列表。显示列表中的函数语句按它们被存放的顺序依次执行;若list没有定义,则不会产生任何事情。下面举出一个应用显示列表的简单例子:
例16-1 显示列表例程
(
displist.c
)
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void drawLine(void);
void CALLBACK display(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
GLuint listName = 1;
void myinit (void)
{
glNewList (listName, GL_COMPILE);
glColor3f (1.0, 0.0, 0.0);
glBegin (GL_TRIANGLES);
glVertex2f (0.0, 0.0);
glVertex2f (1.0, 0.0);
glVertex2f (0.0, 1.0);
glEnd ();
glTranslatef (1.5, 0.0, 0.0);
glEndList ();
glShadeModel (GL_FLAT);
}
void drawLine (void)
{
glColor3f(1.0,1.0,0.0);
glBegin (GL_LINES);
glVertex2f (0.0, 0.5);
glVertex2f (5.0, 0.5);
glEnd ();
}
void CALLBACK display(void)
{
GLuint i;
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (0.0, 1.0, 0.0);
glPushMatrix();
for (i = 0; i <5; i++)
glCallList (listName);
drawLine ();
glPopMatrix();
glFlush ();
}
void CALLBACK 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();
}
void main(void)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (10, 200, 400, 50);
auxInitWindow ("Display List");
myinit ();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
以上程序运行结果是显示五个显示列表中定义的红色三角形,然后再绘制一条非表中的黄色线段。
16.3、管理显示列表
在上一节例子中,我们使用了一个正整数作为显示列表的索引。但是在实际应用中,一般不采用这种方式,尤其在创建多个显示列表的情况下。如果这样做,则有可能选用某个正在被占用的索引,并且覆盖这个已经存在的显示列表,对程序运行造成危害。为了避免意外删除,可以调用函数glGenList()来产生一个没有用过的显示列表,或调用glIsList()来决定是否指定的显示列表被占用。此外,在管理显示列表的过程中,还可调用函数glDeleteLists()来删除一个或一个范围内的显示列表。下面分别介绍这些函数:
GLuint glGenList(GLsizei range);
分配range个相邻的未被占用的显示列表索引。这个函数返回的是一个正整数索引值,它是一组连续空索引的第一个值。返回的索引都标志为空且已被占用,以后再调用这个函数时不再返回这些索引。若申请索引的指定数目不能满足或range为0则函数返回0。
GLboolean glIsList(GLuint list);
询问显示列表是否已被占用的情况。若索引list已被占用,则函数返回TURE;反之,返回FAULSE。
void glDeleteLists(GLuint list,GLsizei range);
删除一组连续的显示列表,即从参数list所指示的显示列表开始,删除range个显示列表,并且删除后的这些索引重新有效。若删除一个没有建立的显示列表则忽略删除操作。
当建立一个与已经存在的显示列表索引相同的显示列表时,OpenGL将自动删除旧表。这一节举个例子来说,如果将上一节程序/***.c*/中所创建的显示列表改为以下代码:
listIndex=glGenLists(1);
if(listIndex!=0)
{
glNewList(listIndex,GL_COMPILE);
...
glEndList();
}
glNewList(1,GL_COMPILE);
glVertex3fv(v1);
glEndList();
glNewList(2,GL_COMPILE);
glVertex3fv(v2);
glEndList();
glNewList(3,GL_COMPILE);
glVertex3fv(v3);
glEndList();
glNewList(4,GL_COMPILE);
glBegin(GL_POLYGON);
glCallList(1);
glCallList(2);
glCallList(3);
glEnd();
glEndList();
这样,要绘制三角形就可以调用显示列表4了,即调用glCallList(4);要编辑顶点,只需重新建立相应的该顶点显示列表。