В этом шаге посмотрим как сделать две вещи:
Чесно говоря, я устал от этого MFC, захотелось сделать маленькую и шуструю программку. Поэтому я сделал этот шаг на API. Кроме того, как мне кажется, на MFC достаточно сложно сделать программу с максимальной производительностью. (собствено говоря ни одна игровая программа не использует MFC, OWL, VCL и т.д.) Хотя все это не имеет значения. Главное - это правильно подойти к поставленной задаче. Делать CAD систему на API неразумно, равно как и писать 3D шутер с MFC. Так что лучше всего уметь и так и так ;)
Ну ладно, теперь к нашим баранам. Сначала о списках. Список - это некоторый набор команд OpenGL, который можно создать один раз, например, перед началом работы программы, а потом им пользоваться вызывая его. По логике он аналогичен процедуре (или функции, как хотите). Отличие его от процедуры в том, что при формировании списка библиотека сохраняет его в каком-то своем, оптимизированном формате и вызовы списка приводят к значительно меньшим вычислительным затратам чем вызов функции, делающей тоже самое. Особенно хорошо это заметно на картах, где операции со списками реализованы аппаратно.
Давайте посмотрим как создать список:
void CalculateList() { CUBE_LIST = glGenLists(1); glNewList(CUBE_LIST, GL_COMPILE); DrawCube(); glEndList(); }
Для того, чтобы занести в список некоторую последовательность команд надо поместить их между командными скобками glNewList и glEndList. Первый аргумент команды glNewList - номер списка. Вы можете использовать большое количество списков в своей программе и каждый из них будет иметь свой номер. В принципе можно самому задавать числа, но для того чтобы избежать наложений рекомендуется использовать специальную команду, которая генерирует номера списков и первый номер возвращает в вашу переменную. В качестве аргумента она принимает количество номеров списков, которое вы хотите получить.
Например, запись CUBE_LIST = glGenLists(5) зарезервирует для вас 5 номеров списков и первый номер попадет в переменную CUBE_LIST. Посмотрите код функции DrawCube, он такой же как и в "Шаг 37 - "Симпатишный" кубик". Просто все команды рисования куба заносятся в список. Я выделил эти команды в отдельную функцию для того, чтобы в будущем вернуться к этому примеру (доработав его, конечно) и посмотреть количество fps в режиме со списками и без.
Но это потом. Сейчас посмотрим как использовать этот список:
GLvoid Draw() { static GLfloat rot = 0.0f; glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glColor3f (1.0, 1.0, 0.5); glCallList(CUBE_LIST); glRotatef(rot, 0.0f, 1.0f, 1.0f); glPushMatrix(); glLightfv(GL_LIGHT0, GL_POSITION, light0_Position); glTranslatef(light0_Position[0],light0_Position[1],light0_Position[2]); glScalef(0.1f, 0.1f, 0.1f); glCallList(CUBE_LIST); glPopMatrix(); rot+=1.0f; glPopMatrix(); SwapBuffers(hDC); }
В начале работы мы заталкиваем в стек текущую матрицу glPushMatrix(), чтобы не портить её ;). Устанавливаем цвет примитивов - glColor3f (1.0, 1.0, 0.5). Вызываем список для рисования большого куба - glCallList(CUBE_LIST). Поворачиваем модельную систему координат на угол rot относительно осей Y и Z. Опять прячем в стек уже повернутую систему координат - glPushMatrix().
Устанавливаем источник света в заданную позицию при помощи оператора:
glLightfv(GL_LIGHT0, GL_POSITION, light0_Position).
Переносим систему координат в ту точку где стоит источник света:
glTranslatef(light0_Position[0],light0_Position[1],light0_Position[2])
Масштабируем систему координат, т.е. уменьшаем в 10 раз по всем осям функцией glScalef(0.1f, 0.1f, 0.1f).
Вызываем список, т.е. опять рисуем кубик, но меньшего размера и в другом месте :) (glCallList(CUBE_LIST))
Восстанавливаем матрицу (glPopMatrix())
Увеличиваем угол (rot+=1.0f)
И восстанавливаем исходную матрицу (glPopMatrix())
Вот и все дела. Единственный момент, который мы еще не видели раньше - положение источника света. Все характеристики источников света (не только положение, но и его тип, интенсивность и т.д.) задаются при помощи одной команды glLightfv, где 1-й аргумент это имя источника, второй говорит какое свойство источника будет задано 3-м аргументом. В нашем случае есть глобальный массив light0_Position и он определяет где будет находится источник.
В проекте есть еще несколько вспомогательных функций, которые настраивают видовые координаты, включают режим освещения и сам источник света, включают буффер глубины и т.д., но все эти функции мы уже много раз писали в MFC проектиках. Поэтому посмотрите их в проекте. Сюда я не буду их вставлять.
Ну вот. Посмотрите на кубики, а я пока напишу текст к следующему шагу, где будет 2 источника света ;)