ディスプレイ リスト
コマンドを保存する
OpenGL が単純なグラフィックスライブラリではなく
クライアント/サーバー型のプロトコル・コマンドであることを理解すると
OpenGL のコマンドは、Windows のグラフィックなどに使われる
メタファイルのような、描画のための一連の情報に類似していることに気づきます
すると、誰もが、コマンドを保存して、後に再生する方法はないかと考え、
あるいは、そうすることによって実行速度の向上を図ろうとすることでしょう
実は、OpenGL にはコマンドを保存し、自由に再生する機能が存在します
この機能のことをディスプレイ・リストと呼んでいます
ディスプレイ・リストを作成するには glNewList() で保存を開始します
その後、保存するコマンドを実行し、最後に glEndList() で終了します
これらの関数の間に実行された OpenGL コマンドは、リストして保存されます
(もちろん、OpenGL コマンド以外は保存されたりしない)
void glNewList(GLuint list , GLenum mode);
void glEndList(void);
list にはディスプレイ・リストを識別するための 0 以外の正の整数を指定します
mode は、コマンドの保存と実行の関係を決定するための定数を指定します
GL_COMPILE を指定すれば、コマンドは実行されずにリストに保存されますが
GL_COMPILE_AND_EXECUTE を指定すれば、同時にコマンドが実行されます
コマンドの保存が終われば、glCallList() で実行できます
もちろん、一度保存したディスプレイ・リストは何度も実行できます
void glCallList(GLuint list);
list には、実行するディスプレイ・リストの識別子を指定します
これは、glNewList() 関数の list に渡した値に対応しています
ただし、ディスプレイ・リストに保存することができないコマンドも存在します
まず考えられるのは、クライアント制御に使われるコマンドです
glEnableClientState() など、クライアントの設定を変更するものは保存できません
また、値を返すことが目的の glGet*() 系のコマンドも無意味です
以下に、ディスプレイ・リストに保存することができないコマンドを列挙します
- glColorPointer()
- glDeleteList()
- glDisableClientState()
- glEdgeFlagPOinter()
- glEnableClientState()
- glFeedbackBuffer()
- glFinish()
- glFlush()
- glGenLists()
- glGet()
- glIndexPointer()
- glInterleavedArrays()
- glIsEnabled()
- glIsList()
- glNormalPointer()
- glPixelStore()
- glReadPixels()
- glRenderMode()
- glSelectBuffer()
- glTexCoordPointer()
- glVertexPointer()
これらのコマンドは、クライアントの設定にかかわるものか
または、サーバーの状態を取得することが目的のコマンドなので
ディスプレイ・リストに保存することはできないと定められています
#include <windows.h>
#include <GL/gl.h>
#include <GL/glut.h>
#define DISP_LIST_INDEX 1
void disp( void ) {
float f;
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
for(f = 0 ; f < 1 ; f += 0.1) {
glColor3f(f , 0 , 0);
glCallList(DISP_LIST_INDEX);
}
glPopMatrix();
glFlush();
}
void setDispList( void ) {
glNewList(DISP_LIST_INDEX , GL_COMPILE);
glBegin(GL_POLYGON);
glVertex2f(-1.2 , -0.9);
glVertex2f(0.6 , -0.9);
glVertex2f(-0.3 , 0.9);
glEnd();
glTranslatef(0.1 , 0 , 0);
glEndList();
}
int main(int argc , char ** argv) {
glutInit(&argc , argv);
glutInitWindowSize(400 , 300);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);
glutCreateWindow("Kitty on your lap");
glutDisplayFunc(disp);
setDispList();
glutMainLoop();
return 0;
}
このプログラムでは、setDispList() 関数でディスプレイ・リストを作成し
それを、disp() 関数が呼び出されたときに描画するというものです
このとき、for() ループで何度も同じディスプレイ・リストを呼び出しています
その結果、図を見てわかるように、三角形が連続して表示されています
ディスプレイ・リストの識別はインデックスで行われますが
すでに識別子が使われている場合、新しいリストの作成には失敗します
この問題を回避するには glGenLists() を使います
GLuint glGenLists(GLsizei range);
この関数は、連続した空のディスプレイ・リストを生成します
range には生成するディスプレイ・リストの数を指定します
関数は利用可能な値 n を取得し、n + range - 1 までのリストを生成します
そして、連続したディスプレイ・リストの先頭の識別値 n を返します
何らかの理由で生成できなかった場合は、必ず 0 を返します
何らかの識別値がすでに利用されているかどうかを知りたい場合
glIsList() 関数を使うことで調べることができます
GLboolean glIsList(GLuint list);
list で指定した値がすでに使われている場合は GL_TRUE が返ります
そうでなければ GL_FALSE を返します
ディスプレイ・リストが不要になれば glDeleteLists() で削除できます
ディスプレイ・リストを削除すれば、その識別値は再び使用することができます
void glDeleteLists(GLuint list , GLsizei range);
list には削除するディスプレイ・リストの先頭の識別値を指定します
range には、list を先頭に削除するディスプレイ・リストの数を指定します