Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

2633

.pdf
Скачиваний:
6
Добавлен:
07.01.2021
Размер:
54.26 Mб
Скачать

Далее требуется описание прототипа функции WndProc. Функция

CreateGLWindow() вызывает функцию WndProc(), но WndProc()

описывается после CreateGLWindow: LRESULT CALL BACK

WndProc(HWND, UINT, WPARAM, LPARAM); // Прототип функции WndProc

Назначение следующей части кода заключается в изменении размеров OpenGL сцены всякий раз, когда будут изменены размеры окна (при условии, использовании оконного, а не полноэкранного режима). Размеры сцены OpenGL будут изменены в соответствии с шириной и высотой окна, в которое выводится изображение:

GLvoid ReSizeGLScene(GLsizei width, GLsizei height ) // Изменить размер и инициализировать окно GL

{

 

if(height == 0)

// Предотвращение деления на ноль

{

height = 1;

}

glViewport (0, 0, width, height); // Сброс текущей области вывода Следующие строки настраивают экран для перспективного вида.

Предметы с увеличением расстояния становятся меньше. Это придаёт реалистичность сцене. Охват перспективы составляет 45 градусов, угол поворота оси рассчитывается на основе ширины и высоты окна. Значения 0.1f, 100.0f – отправная и конечная точки для того, чтобы определить какая будет глубина у экрана.

Функция glMatrixMode(GL_PROJECTION) сообщает о том, что следующие две команды будут воздействовать на матрицу проекции. Матрица проекции отвечает за добавление в сцену перспективного вида. glLoadIdentity() – это функция работает подобно сбросу. Она восстанавливает выбранную матрицу в первоначальное состояние. Раз матрица проекции сброшена, необходимо вычислить перспективу для сцены. После вызова glLoadIdentity() происходит инициализация перспективного вида сцены. glMatrixMode(GL_MODELVIEW)

сообщает, что любые новые трансформации будут воздействовать на матрицу вида модели. Позже необходимо сбросить матрицу вида модели:

glMatrixMode(GL_PROJECTION);

//Выбор матрицы проекций glLoadIdentity();

//Сброс матрицы проекции

//Вычисление соотношения геометрических размеров для окна gluPerspective(45.0f,GLfloat)width/(GLfloat)height, 0.1f, 100.0f );

33

glMatrixMode(GL_MODELVIEW);

//Выбор матрицы вида модели glLoadIdentity();

//Сброс матрицы вида модели

}

Далее будут произведены все настройки для OpenGL: цвет для

очистки экрана, глубина буфера, плавное сглаживание цветов, и другое. Эта функция не должна быть вызвана до тех пор, пока OpenGL окно не будет создано:

int InitGL( GLvoid )

// Все установки касаемо OpenGL происходят здесь

{

В следующей строке разрешается сглаживание с плавным цветовым переходам:

glShadeModel( GL_SMOOTH );

// Разрешить плавное цветовое сглаживание Плавное цветовое сглаживание смешивает цвета вдоль всего

полигона и учитывает освещение:

Следующая строка устанавливает цвет, которым будет очищен экран. Все значения могут быть в диапазоне от 0.0f до 1.0f, при этом 0.0 самый темный, а 1.0 самый светлый. Первый аргумент в glClearColor – это интенсивность красного (Red), второй – зеленного (Green), третий – синего (Blue). Наибольшее значение – 1.0f, является самым ярким значением данного цвета. Последнее число - для Альфа (Прозрачность) значения.

Возможно получение различных цветов, смешивая три компоненты цвета. Поэтому, необходимо вызвать glClearColor(0.0f,0.0f,1.0f,0.0f). Для того чтобы сделать белый фон, Надо установить все цвета в (1.0f).

Черный – все компоненты цвета равны 0.0f: glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

// Очистка экрана в черный цвет Следующие три строки создают буфер глубины. Буфер глубины

указывает, как далеко объекты находятся от экрана и позволяет сортировать объекты для обрисовки, поэтому квадрат, расположенный под кругом не будет изображен поверх него:

glClearDepth( 1.0f ) ;// Разрешить очистку буфера глубины

glEnable( GL_DEPTH_TEST );

// Разрешить тест глубины

glDepthFunc( GL_LEQUAL );

// Тип теста глубины

glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); // Улучшение в вычислении перспективы

34

Если необходимо узнать, прошла ли инициализация как положено, необходимо проверить возвращаемое значение на true и false:

return true;

// Инициализация прошла успешно

}

 

В следующей секции содержится весь код для рисования. Возвращение значения true говорит о том, что в этой части не

возникло никаких проблем. Если, по каким-либо причинам, необходимо остановить выполнение программы надо добавить строчку return false перед return true, таким образом, происходит сообщение программе, что в части кода, выполняющего рисование, произошла ошибка – произойдёт выход из программы:

int DrawGLScene( GLvoid ) // Здесь будет происходить вся прорисовка

{

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Очистить экран и буфер глубины

glLoadIdentity();

// Сбросить текущую матрицу

return true;

// Прорисовка прошла успешно

}

 

Следующая часть

кода вызывается только перед выходом из

программы. Задача KillGLWindow() – освободить Контекст Рендеринга (hRC), Контекст Устройства (hDC) и, наконец, дескриптор окна (hWnd). Если программа неспособна удалить какую-нибудь часть из контекстов окна, появится окно (Message Box) с соответствующим сообщением об ошибке. Чем их больше будет создано (Message Box-ов), тем проще будет найти ошибку:

GLvoid KillGLWindow(GLvoid) // Корректное разрушение окна

{

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

if( fullscreen ) //Программа в полноэкранном режиме?

{

Далее используется ChangeDisplaySettings(NULL,0) для возврата рабочего стола в первоначальное состояние. Передача NULL в первом параметре и 0 во втором принуждает окно использовать параметры, хранящиеся в регистре окна (устанавливая разрешение, битовую глубину, частоту обновления экрана и другое по умолчанию),

35

действительно восстанавливая первоначальное состояние рабочего стола:

ChangeDisplaySettings (NULL, 0);

// Если да, то переключение обратно в оконный режим

ShowCursor( true ); // Показать курсор мышки

}

Код, приведённый ниже проверяет, существует ли Контекст

Рендеринга (hRC):

 

if( hRC )

// Существует ли Контекст Рендеринга?

{

 

Если его нет,

то программа переходит на часть кода,

расположенную ниже и проверяющие существует ли Контекст Устройства (hDC). Если код существует, код ниже проверит, возможно ли освободить его (отсоединить RC от DC):

if( !wglMakeCurrent(NULL, NULL)) // Возможно ли освободить RC и DC?

{

Если невозможно уничтожить контексты RC и DC, выскочит сообщение об ошибке, это позволит понять, что контексты не уничтожены. NULL в функции MessageBox() означает, что у сообщения не будет родительского окна. Текст справа от NULL – текст, который будет содержать сообщение:

MessageBox(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);

}

"SHUTDOWN ERROR" – это текст, который будет содержаться в заголовке окна-сообщения.

Потом следует удалить Контекст Рендеринга. Если это не возможно выскочит соответствующее сообщение:

if(!wglDeleteContext(hRC))

// Возможно ли удалить RC?

{

 

Если невозможно удалить Контекст Рендеринга код, приведённый ниже, выведет окно-сообщение позволяющее понять, что его удаление невозможно. hRC будет установлено в NULL:

MessageBox( NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION );

}

 

hRC = NULL;

// Установить RC в NULL

}

 

Теперь следует проверить, имеет ли программа Контекст Устройства, и если это так, то производим его уничтожение:

36

if(hDC && !ReleaseDC(hWnd, hDC)) // Возможно ли уничтожить

DC?

{

MessageBox(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);

hDC=NULL; // Установить DC в NULL

}

Если это невозможно окно-сообщение выведет соответствующее сообщение и hDC будет установлен в NULL.

Теперь необходимо проверить, есть ли дескриптор окна, а если есть, пробуем уничтожить окно, используя DestroyWindow(hWnd). Если это невозможно окно-сообщение выведет соответствующее сообщение и hWnd будет установлен в NULL:

if(hWnd && !DestroyWindow(hWnd)) // Возможно ли уничтожить окно?

{

MessageBox(NULL, "Could Not Release hWnd.", "SHUTDOWN

ERROR", MB_OK | MB_ICONINFORMATION);

 

 

 

hWnd = NULL;

// Установить hWnd в NULL

 

}

 

 

 

 

Последнее, что

необходимо сделать так

это

разрегистрировать

(операция, обратная регистрации) класс окна:

 

 

 

if(!UnregisterClass("OpenGL", hInstance)

//

Возможно

ли

разрегистрировать класс

 

 

 

{

 

 

 

 

MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN

ERROR", MB_OK | MB_ICONINFORMATION);

 

 

 

hInstance=NULL;

// Установить hInstance в NULL

 

}

 

 

 

 

}

Это позволяет корректным образом уничтожить окно и открыть другое без получения сообщения об ошибке "Windows Class already registered" (Класс окна уже зарегистрирован).

Таким образом, функция возвращает BOOL (true или false), всего она получает пять аргументов: Заголовок Окна, Ширину Окна, Высоту Окна, Число Битов (16/24/32), и флаг режима (true для полноэкранного или false для оконного). Возвращаем логическую переменную, которая говорит о том, возможно ли создать окно.

Следующая секция кода создаёт OpenGL окно:

BOOL CreateGLWindow(LPCWSTR title, int width, int height, int bits, bool fullscreenflag)

{

37

GLuint PixelFormat; // Хранит результат после поиска Переменная wc будет использоваться для хранения структуры

класса окна. Структура класса содержит информацию о данном окне. Изменяя различные поля класса, есть возможность изменить вид окна и его поведение. Каждому окну соответствует определённый класс:

WNDCLASS wc;

// Структура класса окна

 

dwExStyle и dwStyle будут хранить расширенную и обычную

информацию о стиле окна.

 

 

 

DWORD dwExStyle;

// Расширенный стиль окна

 

DWORD dwStyle;

// Обычный стиль окна

 

Следующие пять строк кода устанавливают значения координат

левого верхнего и правого нижнего угла прямоугольника (окна):

RECT WindowRect;

// Grabs Rectangle Upper Left / Lower

Right Values

 

 

 

WindowRect.left=(long)0;

// Установить левую составляющую в 0

WindowRect.right=(long)width; //

Установить

правую

составляющую в Width

 

 

 

WindowRect.top=(long)0;

// Установить верхнюю составляющую

в 0

 

 

 

WindowRect.bottom=(long)height;

// Установить

нижнюю

составляющую в Height

Следует использовать эти значения для выравнивания окна так, чтобы область, в которой происходит рисование, имела такое разрешение, какое желаемо. Обычно, если создаётся окно 1024х768, границы окна занимают некоторую часть разрешения.

В следующей строке кода присваивается глобальной переменной fullscreen значение переменной fullscreenflag:

fullscreen=fullscreenflag; // Устанавка значения глобальной переменной fullscreen

Стили CS_HREDRAW и CS_VREDRAW принуждают перерисовать окно всякий раз, когда оно перемещается. CS_OWNDC создает скрытый DC для окна:

hInstance = GetModuleHandle(NULL);

// Считывание дескриптора нашего приложения wc.style = CS_HREDRAW|CS_VREDRAW| CS_OWNDC;

//Перерисовка при перемещении и создании скрытого DC wc.lpfnWndProc = (WNDPROC) WndProc;

//Процедура обработки сообщений

wc.cbClsExtra = 0;

//Нет дополнительной информации для окна wc.cbWndExtra = 0;

//Нет дополнительной информации для окна

38

wc.hInstance = hInstance;

// Устанавление дескриптора

wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Загрузка иконки по умолчанию wc.hCursor= LoadCursor(NULL, IDC_ARROW);

//Загрузка указателя мышки wc.hbrBackground = NULL;

//Фон не требуется для GL wc.lpszMenuName = NULL;

//Меню в окне не будет wc.lpszClassName = "OpenGL";

//Устанавка имя классу

Это означает, что DC не используется совместно несколькими приложениями. WndProc – процедура, которая перехватывает сообщения для программы. Дополнительной информации для нашего окна нет, поэтому заполняем два этих (cbClsExtra и cbWndExtra) поля нулями.

Далее надо зарегистрировать класс. Если возникнет какая-либо проблема или ошибка, выскочит соответствующее окно-сообщение:

if(!RegisterClass(&wc))

// Пытаемся зарегистрировать класс

окна

 

 

{

 

 

MessageBox( NULL, "Failed To Register The Window Class.",

"ERROR", MB_OK | MB_ICONEXCLAMATION );

return false;

// Выход и возвращение функцией значения false

}

 

 

Далее необходимо проверить формат программы:

if(fullscreen)

// Полноэкранный режим?

{

 

 

Далее необходимо убедиться, что ширина и высота, которые используются в полноэкранном режиме те же самые, что и ширина и высота, которую планировали создать в окне, и, что тоже очень важно, установка полноэкранного режима должна происходить перед созданием окна. В коде очищается память для хранения видео настроек и устанавливается ширина, высота и глубина цвета, которые необходимы:

DEVMODE dmScreenSettings; // Режим устройства memset(&dmScreenSettings,0,sizeof

(dmScreenSettings));

// Очистка для хранения установок

dmScreenSettings.dmSize=sizeof

 

(dmScreenSettings);

// Размер структуры Devmode

dmScreenSettings.dmPelsWidth = width;

// Ширина экрана

39

dmScreenSettings.dmPelsHeight = height;

// Высота экрана

 

dmScreenSettings.dmBitsPerPel = bits;

// Глубина цвета

 

dmScreenSettings.dmFields=DM_BITSPERPEL|M_PELSWIDTH

|

DM_PELSHEIGHT;

//Режим Пикселя

 

Далее в коде подается запрос на установление полноэкранного режима:

// Попытка установить выбранный режим и получить результат. if(ChangeDisplaySettings(&dmScreenSettings,

CDS_FULLSCREEN) ! = DISP_CHANGE_SUCCESSFUL)

{

Вся информация о ширине, высоте и глубине цвета хранится в dmScreenSettings. В строке ниже функция ChangeDisplaySettings пробует переключить экран в режим, настройки которого хранятся в dmScreenSettings. Строка CDS_FULLSCREEN убирает панель управления.

Если режим не установлен будет задействован следующий код, если соответствующий полноэкранный режим не существует, выскочит окно-сообщение предлагающее два варианта: запустить приложение в оконном режиме или выйти:

// Если переключение в полноэкранный режим невозможно, будет предложено два варианта: оконный режим или выход.

if( MessageBox( NULL, "The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?",

"Проект GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES

)

{

Если пользователь решил, использовать оконный режим – переменной fullscreen присвоится значение false и выполнение программы продолжится:

fullscreen = false; // Выбор оконного режима(fullscreen = false)

}

else

{

Если пользователь решил выйти из приложения выскочит окно с сообщением о закрытие программы:

// Выскакивающее окно, сообщающее пользователю о закрытие

окна.

MessageBox(NULL, "Program Will Now Close.", "ERROR", MB_OK | MB_ICONSTOP);

return false; // Выход и возвращение функцией false

}

}

40

}

Функция вернёт false, что сообщит программе, что создание окна не завершилось успехом.

Так как данный код мог вызвать ошибку инициализации полноэкранного режима, и пользователь мог решить запускать программу всё же в оконном режиме, следует проверить ещё раз значение переменной fullscreen (true или false) перед тем, как устанавливается режим экрана/окна:

if(fullscreen)

// Полноэкранный режим?

{

 

Теперь необходимо запретить использование указателя мышки, так как в случае, если программа не является интерактивной, правилом хорошего тона является сокрытия указателя мышки в полноэкранном режиме:

dwExStyle = WS_EX_APPWINDOW; // Расширенный стиль окна

dwStyle = WS_POPUP;

// Обычный стиль окна

ShowCursor( false );

// Скрыть указатель мышки

}

 

else

 

{

 

Если используется оконный режим, вместо полноэкранного режима, следует добавить WS_EX_WINDOWEDGE в расширенный стиль. Это придаст окну более объёмный вид. Для обычного стиля задается параметр WS_OVERLAPPEDWINDOW вместо WS_POPUP. WS_OVERLAPPEDWINDOW создаёт окно с заголовком, границы для регулировки размера, оконное меню и кнопки для сворачивания/разворачивания:

dwExStyle = WS_EX_APPWINDOW|EX_WINDOWEDGE; // Расширенный стиль окна

dwStyle = WS_OVERLAPPEDWINDOW;// Обычный стиль окна

}

Строка ниже, регулирует наше окно в зависимости от того, какой стиль окна мы создаем. Настройка сделает окно таким, какие параметры ему были заданны. Обычно границы перекрывают часть окна.

Используя функцию AdjustWindowRectEx указывается, чтобы ни одна часть окна OpenGL не была перекрыта границами, вместо этого будут созданы дополнительные пиксели специально для рамки границ: AdjustWindowRectEx(&WindowRect, dwStyle, false, dwExStyle):

// Подбирает окну подходящие размеры На полноэкранный режим эта операция никак не повлияет.

В следующей секции кода происходит создание окна и проверка создано ли оно должным образом:

41

if(!(hWnd = CreateWindowEx(dwExStyle,

// Расширенный стиль

для окна

 

 

 

 

_T("OpenGL"),

// Имя класса

 

title,

// Заголовок окна

 

WS_CLIPSIBLINGS |

// Требуемый стиль для окна

WS_CLIPCHILDREN |.

// Требуемый стиль для окна

dwStyle,

// Выбираемые стили для окна

0, 0,

// Позиция окна

 

WindowRect.right-WindowRect.left,

//

Вычисление

подходящей

ширины

 

 

 

 

WindowRect.bottom-WindowRect.top,

 

//

Вычисление

подходящей высоты

 

 

 

 

NULL,

// Нет родительского

 

NULL,

// Нет меню

 

hInstance,

// Дескриптор приложения

NULL)))

//

Не

передаём

ничего до

WM_CREATE (???)

 

 

 

 

Происходит передача CreateWindowEx() всех параметров, в которых она нуждается:

определённый ранее расширенный стиль;

имя класса (которое должно быть тем самым, что Вы использовали, когда регистрировали класс окна);

заголовок окна;

обычный стиль окна;

X левого угла окна;

Y левого угла окна;

ширина окна;

высота окна;

родительское окно;

дескриптор меню;

дескриптор приложения;

дополнительные данные.

Далее создается проверка, создано ли окно правильно. Если окно было создано, hWnd будет хранить дескриптор окна. Если же окно не было создано – код ниже вызовет всплывающее сообщение об ошибке и

программа завершится.

 

{

 

KillGLWindow();

// Восстановить экран

MessageBox( NULL, "Window Creation Error.", "ERROR", MB_OK |

MB_ICONEXCLAMATION );

 

return false;

// Вернуть false

42

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]