1.1 管理显示列表
上面我们直接使用了CUBELIST这个事先定义好的整数来作为显示列表的名字,这种做法在显示列表数目不多时还可以适用。一旦显示列表的数目增多,使用这种方法来管理显示列表就会带来两个问题,一是定义的管理比较麻烦,容易出错;二是一旦创建显示列表使用的名字不小心重复了已经使用的显示列表,则先创建的显示列表就随之失效了。因此,在创建显示列表时,我们有必要采用更加安全的方法。利用glGenLists(),glIsList(),glDeleteLists()这些函数,我们创建的显示列表就会更加健壮。
glGenLists()会生成一组连续的空的显示列表,其原型如下:
GLuint glGenLists(
GLsizei range
);
其中range表示这一组显示列表的数目。当range取0,或者没有可供产生的显示列表组,或者函数调用出现了错误,则函数返回0,此时也表示没有创建成功。
glGenLists()创建显示列表组成功时返回第一个显示列表的名字,虽然显示列表是UINT类型的,但是实际最多可以创建2147483647(2^31-1)个显示列表。
由于创建的显示列表组是连续的,glGenLists()首先检查有哪些值已经被占用,然后从最小的值开始建立连续的显示列表。例如,如果8已经被占用,glGenLists(10)要创建10个显示列表,则生成的显示列表范围是9~18;如果是glGenLists(7)创建7个显示列表,则从最小的1开始到7是生成的结果。
glIsList()判断某个值是否被作为显示列表占用,避免使用了已经占用的值来创建新的显示列表。glList()只有一个参数,是用来检查是否是显示列表的值,返回TRUE表示该值已经作为显示列表被占用,反之返回FALSE。
当显示列表已经不需要时,还可以使用glDeleteLists()删除显示列表,其原型如下:
void glDeleteLists(
GLuint list,
GLsizei range
);
其中list是要删除的显示列表序列的第一个,range是要删除的显示列表的数目。例如glDeleteLists(9,10)表示删除9~18这10个显示列表。当范围中的某些值不是显示列表时,glDeleteLists()将会忽略。
下面我们来重新创建两个显示列表,其中list是一个GLuint类型的全局变量。
GLuint list;
void CreateLists()
{
list = glGenLists(2); //产生两个显示列表,
if(list)
{
glNewList(list, GL_COMPILE); //创建第一个显示列表
for(int i=0; i<10; i++) //绘制10个立方体
{
glPushMatrix() ;
glRotatef(36*i,0.0,0.0,1.0) ;
glTranslatef(10.0,0.0,0.0) ;
DrawCube();
glPopMatrix();
}
glEndList(); //第一个显示列表创建完毕
glNewList(list+1, GL_COMPILE); //创建第二个显示列表
for(i=0; i<20; i++) //绘制20个三棱椎
{
glPushMatrix() ;
glRotatef(18*i,0.0,0.0,1.0) ;
glTranslatef(15.0,0.0,0.0) ;
DrawPyramid(); //DrawPyramid()在前面的章节中有介绍
glPopMatrix();
}
glEndList(); //第二个显示列表创建完毕
}
}
glInit()不变,glMain()如下:
void glMain()
{
static int angle =0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); //加载单位矩阵
glTranslatef(0.0f, 0.0f, -40.0f);
glRotated(angle, 1, 1, 1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, g_Texture[0]); // 选择纹理
glCallList(list); //调用执行第一个显示列表
glDisable(GL_TEXTURE_2D); //不带纹理
glCallList(list+1); //调用执行第二个显示列表
angle++;
SwapBuffers(g_hDC);
}
程序运行效果如图6-2所示,除了10个带纹理的立方体外,还有20个三棱椎同时围绕XYZ轴旋转。
图6-2 多个显示列表