Обработка событий клавиатуры и мыши
При использовании библиотеки GLAUX предполагается, что программа разработана в соответствии с некоторой структурой-макетом: сначала создается окно приложения, затем устанавливаются параметры OpenGL, регистрируются функции обратной связи и запускается функция главного цикла. Макет консольного приложения был приведен в предыдущей лекции (п.3) и с тех пор он используется во всех рассматриваемых примерах. Функции обратной связи реализуются программистом, а вызываются изнутри GLAUX. Большую часть времени программа проводит в главном цикле внутри функции auxMainLoop():
void auxMainLoop(void (CALLBACK* display)(void)) { вызвать функцию реакции на изменение размеров окна; вызвать функцию рисования сцены display();
while (не закрыто окно приложения) { if (изменен размер окна) вызвать функцию реакции на изменение размера окна; if (нажата клавиша) вызвать функцию обработки этой клавиши; if (нажата кнопка мыши) вызвать функцию обработки этой кнопки; if (было перемещение мыши при нажатой кнопке) вызвать функцию обработки перемещения мыши;
вызвать фоновую функцию; } }
Т.о., из главного цикла GLAUX могут вызываться функции обратной связи, в которых программист определил реакцию на некоторые внешние события. Эти функции обычно называются обработчиками событий. Чтобы GLAUX вызывала их, обработчики надо зарегистрировать до входа в главный цикл. Обработчик события от клавиатуры должен соответствовать прототипу: void CALLBACK FunctionName(void); где FunctionName – произвольное имя, выбираемое программистом. Для регистрации функции FunctionName() в качестве обработчика нажатия кнопки клавиатуры служит функция: void auxKeyFunc(int keyCode, void (CALLBACK* FunctionName)(void)); где keyCode – код клавиши (соответствующие константы хранятся в файле glaux.h, например, AUX_ESCAPE и AUX_A).
Прототип обработчика событий мыши отличается от клавиатурного обработчика: void CALLBACK FunctionName(AUX_EVENTREC* event); При вызове обработчика GLAUX передает ему информацию о произошедшем событии в параметре event типа AUX_EVENTREC. Эта структура имеет вид:
struct AUX_EVENTREC { GLint event; // Тип события: AUX_MOUSEDOWN, AUX_MOUSEUP, // или AUX_MOUSELOC GLint data[4]; // [0] горизонтальная координата мыши // [1] вертикальная координата мыши // [2] не используется // [3] код нажатой кнопки (AUX_LEFTBUTTON, // AUX_MIDDLEBUTTON или AUX_RIGHTBUTTON) };
Для регистрации обработчика события от мыши надо использовать функцию: void auxMouseFunc(int button, int action, void (CALLBACK* FunctionName)(AUX_EVENTREC*)); Параметр button задает кнопку, с которой связано событие: AUX_LEFTBUTTON (левая), AUX_MIDDLEBUTTON (средняя), AUX_RIGHTBUTTON (правая). Параметр action задает тип события: AUX_MOUSEDOWN (нажатие кнопки), AUX_MOUSEUP (отпускание кнопки), AUX_MOUSELOC (перемещение мыши при нажатой кнопке).
Пример обработки события от мыши: изменение цвета вращающегося объекта по нажатию левой кнопки мыши Перечислим изменения, которые необходимо внести в программу 2.1, чтобы по нажатию левой кнопки мыши цвет вращающегося чайника циклически изменялся в следующей последовательности: желтый, красный, зеленый, синий. 1) Надо добавить в программу описание глобальной переменной, в который будет храниться порядковый номер текущего цвета (0/1/2/3 – желтый/красный/зеленый/синий): int clr_number = 0; 2) Значение переменной clr_number надо учесть в функции рисования трехмерной сцены, чтобы перед рисованием чайника устанавливался соответствующий цвет: switch (clr_number) { case 0: glColor3f(0.5, 0.5, 0); break; case 1: glColor3f(1, 0, 0); break; case 2: glColor3f(0, 1, 0); break; case 3: glColor3f(0, 0, 1); break; default: glColor3f(1, 1, 1); break; } 3) В раздел прототипов надо внести прототип обработчика события от мыши: void CALLBACK mouse_leftbtn(AUX_EVENTREC* event); 4) В функции-обработчике выполняется изменение номера текущего цвета:
void CALLBACK mouse_leftbtn(AUX_EVENTREC* event) { if (++clr_number == 3) clr_number = 0; } 5) Перед входом в главный цикл GLAUX надо зарегистрировать обработчик события "нажатие левой кнопки мыши": auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN, mouse_leftbtn);
Композиция нескольких преобразований Для генерации анимационных изображений объектов, движущихся относительно друг друга, часто бывает удобно применять последовательность нескольких преобразований, параметры которых определяются текущим положением объектов. В данном параграфе показывается применение композиции нескольких преобразований для двух моделей: для простейшей модели солнечной системы (несколько объектов вращаются вокруг собственных осей и по орбитам вокруг солнца) и для модели манипулятора робота (при отображении манипулятора требуется выполнять преобразование координатных систем отдельных сегментов).
Модель солнечной системы Рассмотрим простейшую модель солнечной системы, которая состоит из солнца и одной планеты, движущейся по круговой орбите. Планета совершает полный оборот по орбите за 365 дней, а оборот вокруг своей оси за 24 часа. Оба тела рисуются в виде каркасных сфер, для отображения сцены применяется перспективная проекция (функция gluPerspective()). Угловое движение планеты по орбите и вокруг собственной оси учитывается с помощью функции glRotated(). Для размещения планеты на орбите применяется функция glTranslated(). Центр сферы, изображающей солнце, находится в начале координат. Вращение солнца вокруг собственной оси не показывается (хотя это легко сделать с помощью функции glRotated()). Для рисования планеты, обращающейся вокруг солнца (рис. 2.1), требуется выполнить несколько модельных преобразований. Рис. 2.1. Движение планеты по орбите и вокруг своей оси.
Для определения порядка модельных преобразований надо представить, что должно происходить с модельной системой координат. Сначала модельная система координат совпадает с мировой. В этом состоянии надо функцией glRotated() повернуть модельную систему координат относительно мировой системы на угол, соответствующий текущему положению планеты на орбите. Затем glTranslated() выполняет перенос модельной системы координат по радиусу орбиты. После этого выполняется еще один вызов glRotated(), поворачивающий модельную систему координат вокруг оси вращения планеты в соответствии с временем суток на планете. После выполнения всех трех преобразований, можно нарисовать планету.
Описанные преобразования выполняются в программе 2.2. Фоновой функции в этой программе нет, поэтому изменение времени производится клавишами курсора: увеличение/уменьшение времени суток с помощью стрелок вверх/вниз (на 1 час), дней – с помощью стрелок вправо/влево (на 1 день).
#include <windows.h> #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h>
void CALLBACK resize(int width, int height); void CALLBACK display(); void CALLBACK dayAdd(); void CALLBACK daySubtract(); void CALLBACK hourAdd(); void CALLBACK hourSubtract();
// Счетчики дней и часов int day_cnt = 0, hour_cnt = 0;
void main() { // Создание экранного окна auxInitDisplayMode(AUX_RGBA | AUX_DEPTH | AUX_DOUBLE); auxInitPosition(50, 10, 400, 400); auxInitWindow("Лекция 2, Программа 2.2");
// Включение ряда параметров OpenGL glEnable(GL_ALPHA_TEST); // Учет прозрачности glEnable(GL_DEPTH_TEST); // Удаление невидимых поверхностей glEnable(GL_COLOR_MATERIAL); glEnable(GL_BLEND); // Разрешение смешения цветов glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LIGHTING); // Учет освещения glEnable(GL_LIGHT0); // Включение нулевого источника света
// Задание положения и направления нулевого источника света float pos[4] = { 5, 5, 5, 1 }; float dir[3] = { -1, -1, -1 }; glLightfv(GL_LIGHT0, GL_POSITION, pos); glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dir);
// Регистрация обработчиков событий auxReshapeFunc(resize); auxKeyFunc(AUX_LEFT, daySubtract); auxKeyFunc(AUX_RIGHT, dayAdd); auxKeyFunc(AUX_UP, hourAdd); auxKeyFunc(AUX_DOWN, hourSubtract);
// Вход в главный цикл GLAUX auxMainLoop(display); }
void CALLBACK resize(int width, int height) { glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (float)width/(float)height, 1.0, 20.0);
gluLookAt(0,0,5, 0,0,0, 0,1,0);
glMatrixMode(GL_MODELVIEW); glLoadIdentity(); }
void CALLBACK display(void) { // Очистка буфера кадра glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0); glPushMatrix(); auxWireSphere(1.0); // Солнце glRotated((double)day_cnt*360.0/365.0, 0.0, 1.0, 0.0); glTranslated(2.0, 0.0, 0.0); glRotated((double)hour_cnt*360.0/24.0, 0.0, 1.0, 0.0); auxWireSphere(0.2); // Планета glPopMatrix();
// Копирование содержимого буфера кадра на экран glFlush(); auxSwapBuffers(); }
void CALLBACK dayAdd() { day_cnt = (day_cnt + 1) % 360;
}
void CALLBACK daySubtract() { day_cnt = (day_cnt - 1) % 360; }
void CALLBACK hourAdd() { hour_cnt = (hour_cnt + 1) % 24; }
void CALLBACK hourSubtract() { hour_cnt = (hour_cnt - 1) % 24; } Программа 2.2. Модель солнечной системы.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|