|
||||||||||||||||||||||||
Программирование GLUT: окна и анимация
Время создания: 26.09.2019 16:39
Автор: Miguel Angel Sepulveda, Vladas Lapinskas
Текстовые метки: opengl, glut, инициализация, настройка, основной цикл, анимация, цикл простоя, цикл отрисовки
Раздел: Компьютер - Программирование - Компьютерная графика
Запись: xintrea/mytetra_syncro/master/base/1569505163rzqcft7r4c/text.html на raw.github.com
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
ВведениеПо замыслу разработчиков, спецификация OpenGL была создана независимой от какой-либо конкретной системы управления окнами. В результате мы получили переносимый, рационализированный и эффективный интерфейс к библиотеке двух- и трехмерного рендеринга. Конкретная система управления окнами должна сама позаботится об открытии и отображении окон. Библиотека OpenGL взаимодействует с оконной системой через дополнительные библиотеки, например, библиотека GLX описывает взаимодействие между OpenGL и системой X-Window. Библиотека набора утилит OpenGL (GLUT, от GL Utility Toolkit) - это интерфейс для программистов, создающих на языках ANSI C и FORTRAN приложения OpenGL, не зависящие от системы управления окнами. Библиотека была написана Mark J. Kilgard и закрыла собой огромную брешь, оставленную спецификацией OpenGL. Благодаря разработчикам GLUT мы имеем возможность использовать единый интерфейс для работы с окнами независимо от платформы. Приложения OpenGL, использующие GLUT могут быть с легкостью перенесены с платформы на платформу, без многочисленных переделок исходного кода. GLUT значительно облегчает написание кода приложений и дополняет библиотеку OpenGL. Библиотека GLUT относительно невелика и легка в изучении. Библиотека хорошо разработана и дополнена замечательной документацией. Таким образом, посвящать этому вопросу отдельную серию статей на LinuxFocus представляется излишним. Мы советуем каждому серьезному разработчику прочитать документацию, предоставленную автором. Цель этой регулярной колонки, посвященной GLUT, в том, чтобы шаг за шагом на примерах ознакомить читателя с библиотекой и ее использованием, в дополнение к серии статей по OpenGL в этом журнале. Мы так же надеемся, что внесем посильный вклад и дадим повод большему числу программистов присоединиться к союзу OpenGL-Linux. В любом случае, собственная копия авторской документации по GLUT послужит хорошим справочником. Программный интерфейс GLUT представляет собой конечный автомат (state machine), как и сам OpenGL. Это значит, что GLUT содержит ряд переменных состояния, которые изменяются во время исполнения приложения. Начальные состояния машины GLUT были выбраны с таким расчетом, чтобы удовлетворять большинству приложений. Программа может изменять значения этих переменных состояния, для удовлетворения специфических требований. Каждый раз при вызове функции GLUT меняют свое поведение в зависимости от значений переменных состояния. Функции GLUT просты и требуют минимума параметров. Они не возвращают указателей, а единственными указателями в параметрах функций являются указатели на текстовые строчки и дескрипторы шрифтов. Функции GLUT могут быть классифицированы на несколько групп согласно своей функциональности:
В этой статье мы ознакомимся с некоторыми функциями инициализации, обработки событий и управления окнами, которые необходимы для запуска простейшей программы OpenGL. ИнициализацияКаждая программа OpenGL, использующая GLUT, должна начинаться с инициализации GLUT-машины. Все функции инициализации имеют префикс glutInit-. Главная инициализирующая функция называется glutInit: glutInit позаботится об инициализации переменных состояния GLUT и откроет сессию с системой управления окнами. Есть всего лишь несколько функций, которые могут быть вызваны перед glutInit; это только те функции, которые имеют префикс glutInit-. Данные функции могут быть использованы для установки начального состояния окна. Например: Есть еще одна функция, которая присутствует практически во всех приложениях OpenGL, glutInitDisplayMode():
Не беспокойтесь, если некоторые из указанных режимов кажутся Вам незнакомыми, рано или поздно мы опишем их все. Давайте обратимся к нескольким примерам. Первый - простая инициализация для приложения с одним кадром: #include <GL/glut.h> void main(int argcp, char **argv){ /* Установка размеров и положения окна */ /* Выбор режима окна: /* Инициализация первоначального состояния GLUT */ .....немного кода; }; Второй - пример анимационной программы: #include <GL/glut.h> void main(int argcp, char **argv){ /* Установка размеров и положения окна */ /* Выбор режима окна: /* Инициализация первоначального состояния GLUT */ .....еще немного кода; }; Мы будем возвращаться к этим двум примерам по мере того, как будем узнавать GLUT все глубже. Главное различие примеров в том, что во втором случае окно инициализируется в режиме двойного буфера, что идеально для анимации, так как устраняет эффект мерцания при смене кадров в анимационной последовательности. Обработка событийКак мы уже упоминали выше, GLUT представляет собой конечный автомат (буквально - машину состояний). Теперь мы покажем, что GLUT разработан и как событийно-управляемый механизм. Это означает, что есть некоторый таймер или последовательный цикл, который запускается после соответствующей инициализации и обрабатывает, один за другим, все события, объявленные GLUT во время инициализации. К событиям относятся: щелчок мыши, закрытие окна, изменение свойств окна, передвижение курсора, нажатие клавиши, и даже довольно любопытное "пустое" (idle) событие, когда ничего не произошло! Каждое из возможных событий должно быть зарегистрировано в одной из переменных состояния GLUT для того, чтобы по таймеру или в последовательном цикле происходила периодическая проверка вызова пользователем того или иного события. Оставим на потом, какие вызываемые функции и события разрешены в GLUT. Для нас сейчас важно, что после регистрации всех требуемых событий в нашем приложении, мы должны вызвать процедуру обработки событий в GLUT, а именно - glutMainLoop(). Эта функции никогда не возвращается, наша программа по существу входит в бесконечный цикл. В каждом приложении OpenGL функция main() должна заканчиваться вызовом glutMainLoop(). Например, в заготовке нашего примера с анимацией: #include <GL/glut.h> void main(int argcp, char **argv){ /* Инициализация GLUT */ /* Открытие окна */ /* Выбор режима: /* Регистрация вызываемых функций */ /* Запуск механизма обработки событий */ Заметьте, что я добавил в код вызов функции, которую нигде ранее не упоминал. Это - одна из функций управления окнами GLUT, glutCreateWindow(char **name). Вот что мне особенно нравится в философии OpenGL и GLUT - достаточно взглянуть на название функции, чтобы понять, что она делает! (Create Window - создать окно). Функция позаботится о передаче указаний открыть окно для приложения OpenGL нижестоящей системе управления окнами. Окно будет иметь заголовок, который передается в качестве строкового параметра функции. В системе X-Window этот заголовок появится в левом верхнем углу заголовка окна. Секция управления окнами GLUT включает в себя много других функций, к которым нам время от времени придется обращаться. Сейчас же нам достаточно этой одной функции. Я также изменил порядок следования инициализационных функций, чтобы показать, что они могут быть помещены и после вызова glutInit(). Вернемся к событиям... Я хочу представить две вызываемые функции, которые фундаментальны в любой анимационной программе. Первая - glutDisplayFunc, которая устанавливает функцию рисования для текущего окна, вторая - glutIdleFunc, которая устанавливает функцию обработки пустого события. Обе регистрационные функции в качестве параметра используют функции типа void *(void). К примеру, мы напишем дополнительно две вызываемые функции к нашей заготовке анимационной программы, void MyDisplay(void), которая позаботится о вызове инструкций OpenGL для отрисовки собственно сцены в окне, и void MyIdle(void), которая будет вызываться каждый раз, когда нет событий от пользователя, другими словами - всегда, когда механизм обработки событий GLUT проходит в очередной раз бесконечный цикл (glutMainLoop()) и не находит ни одного нового события, он обращается к MyIdle. Почему я должен регистрировать вызываемую функцию для пустого события в анимационной программе? Потому что если мы желаем изменить какое-либо из изображений (кадров), показываемых во время анимации, независимо от действий пользователя, должна существовать функция (вызываемая функция пустого события) которая будет вызываться так часто в течении работы приложения OpenGL, чтобы изменять кадры прежде, чем они будут отрисованы функцией MyDisplay(). Пример анимацииНаконец, перед Вами заготовка анимационной программы: void MyIdle(void){ void MyDisplay(void){ void main(int argcp, char **argv){ /* Инициализация GLUT */ /* Открытие окна */ /* Выбор режима: /* Регистрация вызываемых функций */ /* Запуск механизма обработки событий */ Заметьте, что в конце функции MyDisplay я добавил вызов новой функции GLUT, glutSwapBuffers(). (Swap Buffers - обмен буферов). Это очень полезно при анимации. Мы используем окно с двойной буферизацией, один буфер отображаемый и второй - спрятанный. В таком режиме инструкции OpenGL по рисованию изображений всегда применяются к спрятанному буферу. Вызов функции glutSwapBuffers обменивает буфера, отображая окно целиком после того, как оно уже сформировано. Эта технология обычна в компьютерной анимации, так как не позволяет человеческому глазу видеть, как линия за линией формируется кадр. Данного материала достаточно для того, чтобы начать писать собственное приложение OpenGL. Мы опустили только инструкции OpenGL в функции MyDisplay, которые собственно занимаются рисованием... но это уже другая история ;-). В следующей статье по программированию GLUT мы углубимся в функциональные возможности секции управления окнами в GLUT, например - как можно открыть несколько сцен внутри одного окна. Мы изучим также использование меню, включая особенности переносимости. |
||||||||||||||||||||||||
Так же в этом разделе:
|
||||||||||||||||||||||||
|
||||||||||||||||||||||||
|