Инициализация OpenGL29.01.2000 Определения
Общий подходНезависимость от драйвераБудет хорошим стилем, если движок с самого начала не будет ориентирован на конкретный драйвер — OpenGL или Direct3D. Даже так: в будущем, возможно, придется дописать поддержку Direct3D. Чтобы избежать переписывания всего движка из-за смены драйвера, вполне естественной кажется мысль выделить объект "Графика", в котором и делать всю работу по взаимодействию с драйвером. Этот объект не должен "привязывать" программу к конкретному драйверу — все его внутренности должны быть надежно спрятаны. Также этот объект должен быть чисто интерфейсным — то есть не может быть больше двух экземпляров этого объекта. Это связано с чересчур сложной реализацией для OpenGL (OpenGL — процедурный), так что лучше и не пытаться... Цикл действийСамый простой способ рисования движущихся объектов заключается в том, чтобы в цикле выполнять следующие шаги: сначала стереть все с окна; затем нарисовать на нем все, что надо; изменить положение объектов для следующего кадра; повторить. Этот способ имеет недостаток: так как компьютер не рисует мгновенно, то между тем, как окно очистится, и тем, как нарисуется новое изображение, остается промежуток времени, в момент которого видно пустое окно. Поэтому человек, смотрящий на это окно, видит мерцание объектов. К тому же, поскольку ускорители не научились рисовать все мгновенно, пользователь будет видеть как программа постепенно, по частям, выводит следующий кадр. Чтобы избежать всего этого, умные компьютерщики придумали трюк с двойной буферизацией. Объект GraphicsКак и любой обычный объект, Graphics должен иметь конструктор. В конструктор будет передаваться идентификатор окна. Деструктор — дело обычное, в него передаваться не будет ничего. ;-) Чтобы начать рисование, программа должна спрашивать у Graphics: "я начну?" И, когда закончит рисовать кадр, программа скажет: "готово". Этот диалог программы с Graphics нужен из следующих соображений. Во-первых, перед тем, как рисовать кадр, экран должен быть очищен. Во-вторых буфер, в который происходит рисование, может быть занят другой программой (так бывает у Direct3D). "Готово" программа говорит для того, чтобы Graphics переключил буфера.
Заметьте: все функции кроме конструктора — виртуальные. Это сделано с расчетом на возможность написания еще одного объекта, поддерживающего Direct3D; тогда нужно будет всего лишь выделить абстрактный класс, и перегрузить все его функции в обоих потомках. А так как объект Graphics — всего один, то его данные будут находиться в том же модуле, где находится и реализация. КонструкторЕдинственное, что я хочу передавать в конструктор Graphics при инициализации — это идентификатор окна. Окно создается безразлично как, и если я хочу выводить какую-то графику, она должна выводиться в окно. Таким образом, объекту Graphics потребуется инициализировать OpenGL, пользуясь одним только идентификатором окна. Для драйвера OpenGL необходимо сделать следующую последовательность действий:
ДеструкторЗдесь все просто — установить "никакой" текущий контекст OpenGL, и удалить контексты в порядке, обратном от порядка создания.
Очистка и переключение буфераВ данном случае, для OpenGL, функция Begin всегда возвращает true. Это сделано для совместимости с Direct3D. Direct3D позволяет программе знать, если вывод графики чем-нибудь заблокирован. Таким образом программа может не рисовать, если ее все равно не видно. Перед переключением буферов вызывается функция glFinish(). Она ожидает, пока ускоритель прорисует все до конца, а потом завершается. Дело в том, что ускоритель может продолжать рисовать после того, как программа дала ему задание что-то нарисовать. Это сделано для того, чтобы программа, не ожидая когда ускоритель закончит рисование, занималась своими вычислениями. Перед переключением буферов необходимо, чтобы ускоритель дорисовал все, чтобы пользователь не видел, как он это делает. Если не использовать glFlush, то в полноэкранном режиме можно увидеть, как части трехмерного мира продолжают прорисовываться... Я наблюдал такое GLQuake — у меня RivaTNT2. Когда я запускал игру, все работало отлично, но если я переключался на другие задачи, а потом снова в GLQuake, то начинал видеть, как оружие и полоса статуса рисуются прямо поверх уже нарисованного мира...
Следующая страница: Цикл программы (c) 2000 Константин Михеев — проект "Elfish Engine" |