OpenGL显示列表(Display List)是由一组预先存储起来的留待以后调用的OpenGL函数语句组成的,当调用这张显示列表时就依次执行表中所列出的函数语句。
使用显示列表可以提高绘制效率,节省计算机的处理资源。但OpenGL显示列表被设计成命令高速缓存,而不是动态数据库缓存。也就是说,一旦建立了显示列表,就不能修改它。(因为若显示列表可以被修改,则显示列表的搜索、内存管理的执行等开销会降低性能。)并且由于调用显示列表时程序本身也有一些开销,尤其是当一个显示列表太小会导致系统开销超过列表的优越性,所以并不是只要调用显示列表就能优化程序性能。
使用显示列表一般有四个步骤:分配显示列表编号、创建显示列表、调用显示列表、销毁显示列表。
为了避免自己定义的显示列表重复导致覆盖,使用glGenLists函数来自动分配一个没有使用的显示列表编号。
GLuint WINAPI glGenLists(
GLsizei range
);
glGenLists函数有一个参数range,表示要分配range个连续的未使用的显示列表编号。返回的是分配的若干连续编号中最小的一个。
例如:glGenLists(3);如果返回20,则表示分配了20、21、22这三个连续的编号。如果函数返回零,表示分配失败。可以使用glIsList函数判断一个编号是否已经被用作显示列表。
创建显示列表实际上就是把各种OpenGL函数的调用装入到显示列表中。使用glNewList开始装入,使用glEndList结束装入。
void WINAPI glNewList(
GLuint list,
GLenum mode
);
glNewList有两个参数:
调用一个显示列表使用glCallList函数,只有一个参数,即要调用的显示列表的编号,例如glCallList(10);可以调用编号为10的显示列表。
使用glCallLists函数,有3个参数:
使用glCallLists前,可以用glListBase函数来设置一个偏移量。假设偏移量为k,且glCallLists中要求调用的显示列表编号依次为l1, l2, l3, …,则实际调用的显示列表为l1+k, l2+k, l3+k, …。
void WINAPI glDeleteLists(
GLuint list,
GLsizei range
);
使用glDeleteLists来销毁一串编号连续的显示列表。例如:使用glDeleteLists(20, 4);
将销毁20,21,22,23这四个显示列表。
下方ListTest类中Init函数创建了一个显示列表,并把绘制三角形并进行贴图的工作装入其中;Draw函数调用这个显示列表。
#pragma once
#include //根据OpenGL编程指南, 在包含"gl.h"头文件时, 要先包含"windows.h", 因为在gl.h里使用了windows.h中定义的标识符
#include
#include
#include
#include "texture.h" //用来加载贴图纹理,可参考前文
class ListTest
{
private:
int list = 0;
public:
void Init();
void Draw();
};
#include "ListTest.h"
void ListTest::Init()
{
if (list == 0)
{
list = glGenLists(1); //分配显示列表编号
glNewList(list, GL_COMPILE); //创建显示列表
Texture texture;
texture.Init("C:\\Users\\***\\Downloads\\272.bmp");
glEnable(GL_TEXTURE_2D);//开启纹理
glBindTexture(GL_TEXTURE_2D, texture.textureId);
glBegin(GL_TRIANGLES);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-0.2f, -0.2f, -1.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(0.2f, -0.2f, -1.0f);
glTexCoord2f(0.5f, 1.0f);
glVertex3f(0.0f, 0.2f, -1.0f);
glEnd();
glEndList();
}
}
void ListTest::Draw()
{
glCallList(list); //调用显示列表
}