Вернуться наверх
aco.ifmo.ru photonic
вернуться в оглавление предыдущая глава предыдущий параграф следующий параграф следующая глава


Дисплейные списки


Интересным и очень эффективным механизмом при создании сцены являются списки. Это механизм, который позволяет запоминать последовательности команд OpenGL и выполнять их снова. Это может существенно повысить эффективность визуализации большого количества одинаковых объектов.

Каждый дисплейный список должен иметь идентификатор. Это может быть произвольное целое число, которое вы можете назначить сами. Во избежание конфликтов идентификаторов списков библиотека OpenGL рекомендует воспользоваться функцией

GLuint glGenLists(GLsizei range);

которая находит свободный идентификатор и возвращает его. В качестве аргумента функции указывается количество, следующих подряд, списков, для которых следует получить идентификаторы. Если свободных идентификаторов не осталось, то функция возвращает ноль.

Для того, чтобы начать формировать список, необходимо вызвать функцию

void glNewList (GLuint list, GLenum mode);

Первый аргумент задает идентификатор формируемого списка, а второй определяет будет ли список только сформирован (GL_COMPILE) или сразу же и отображен (GL_COMPILE_AND_EXECUTE). Далее могут следовать команды OpenGL которые требуется сохранить в списке. Не все команды могут быть в него включены.

Формирование списка заканчивается функцией:

void glEndList (void);

После формирования дисплейные списки сохраняются во внутренней структуре данных OpenGL-окна и будут удалены, когда окно будет закрыто или разрушено.

Для выполнения дисплейного списка используется команда:

void glCallList (GLuint list);

которая в качестве аргумента принимает идентификатор списка.

Вызов функции glCallList() можно осуществить в любом меcте программы, когда требуется выполнение сохраненных в списке команд.

Рассмотрим пример:

void Draw(void)
{
//Очистка цветового буфера
    glClear(GL_COLOR_BUFFER_BIT);

//Установка цвета отображения
    glColor3d(1.0, 1.0, 0.0);
//Рисование горизонтальной оси
    glBegin(GL_LINES);
        glVertex2d(-50., .0);
        glVertex2d(50., .0);

        for(int i=-50; i<50; i++)
        {
            glVertex2d(i, .0);
            if(i % 5)
            {
                glVertex2d(i, -1.);
            }
            else if(i % 10)
            {
                glVertex2d(i, -2.);
            }
            else
            {
                glVertex2d(i, -3.);
            }
        }
    
glEnd();
//Рисование вертикальной оси
    glBegin(GL_LINES);
        glVertex2d(.0, -50.);
        glVertex2d(.0, 50.);
        
for(int j=-50; j<50; j++)
        {
            glVertex2d(.0, j);
            if(j % 5)
            {
                glVertex2d(-1., j);
            }
            else if(j % 10)
            {
                glVertex2d(-2., j);
            }
            else
            {
                glVertex2d(-3., j);
            }
        }
    glEnd();
//Завершить выполнение команд
    glFlush();
}
int axis;

void Init(void)
{
//Формирование оси
    axis = glGenLists(1);
    if (axis != 0)
    {
    glNewList(axis, GL_COMPILE);
    glBegin(GL_LINES);
        glVertex2d(0., .0);
        glVertex2d(100., .0);

        for(int i=0.; i<97; i++)
        {
            glVertex2d(i, .0);
            if(i % 5)
            {
                glVertex2d(i, 1.);
            }
            else if(i % 10)
            {
                glVertex2d(i, 2.);
            }
            else
            {
            glVertex2d(i, 3.);
            }
        }
        glEnd();
//Формирование стрелки можно добавить позже
        glBegin(GL_LINE_STRIP);
            glVertex2d(97., 1.);
            glVertex2d(100.,.0);
            glVertex2d(97., -1.);
        glEnd();
        glEndList();
    }
}

void Draw(void)
{
//Очистка цветового буфера
    glClear(GL_COLOR_BUFFER_BIT);
//Установка цвета отображения
    glColor3d(1.0, 1.0, 0.0);

//Рисование горизонтальной оси
    glPushMatrix();
    glTranslated(-50.,0.,0.);
    glRotated(180.,1.,0.,0.);
    glCallList(axis);
    glPopMatrix();

//Рисование вертикальной оси
    glPushMatrix();
    glTranslated(0.,-50.,0.);
    glRotated(90.,0.,0.,1.);
    glCallList(axis);
    glPopMatrix();

//Завершить выполнение команд
glFlush();
}

Иногда удобно пользоваться списком, который начинается именно с нуля, а не с некоторого целого значения (например, если формируется список символов). Тогда используется функция

void glListBase(GLuint base);

которая позволяет задать базовое значение первого элемента списка, а точнее величину, которая будет добавляться ко всем номерам списка перед его вызовом.

Существует возможность выполнить сразу несколько посредством вызова одной функции

void glCallLists(GLsizei n, GLenum type, const GLvoid * lists);

Первый аргумент этой функции определяет количество списков, которые будут визуализироваться. Второй аргумент определяет тип значений в массиве номеров списков, который передаётся третим.

Ну и наконец, если список нужно изменить, или он больше не нужен, то необходимо применить функцию

void glDeleteLists(GLuint list, GLsizei range);

которая удалит range списков начиная list с из внутренней структуры данных OpenGL.