Планета знаний
Скачать 1.68 Mb.
|
2) Почему предпочтительнее использование связанных при- митивов? 9.3. Контрольные вопросы 129 3) Какая из двух команд выполняется OpenGL быстрее? g l V e r t e x 3 f ( 1 , 1 , 1 ) ; или float vct [ 3 ] = { 1 , 1 , 1 } ; glVertex3fv ( vct ) ; Часть III Создание приложений с OpenGL 131 Глава 10. OpenGL-приложения с помощью GLUT 10.1. Структура GLUT-приложения Далее будем рассматривать построение консольного прило- жения при помощи библиотеки GLUT. Эта библиотека обеспечи- вает единый интерфейс для работы с окнами вне зависимости от платформы, поэтому описываемая ниже структура приложения остается неизменной для операционных систем Windows, Linux и других. Функции GLUT могут быть классифицированы на несколько групп по своему назначению: € инициализация; € начало обработки событий; € управление окнами; € управление меню; € регистрация функций с обратным вызовом; 133 134 Глава 10. OPENGL-приложения с помощью GLUT € управление индексированной палитрой цветов; € отображение шрифтов; € отображение дополнительных геометрических фигур (тор, конус и др.). Инициализация проводится с помощью функции: g l u t I n i t ( int * argcp , char ** argv ) Переменная argcp есть указатель на стандартную перемен- ную argc , описываемую в функции main() , а argv указатель на параметры, передаваемые программе при запуске, который опи- сывается там же. Эта функция проводит необходимые начальные действия для построения окна приложения, и только несколько функций GLUT могут быть вызваны до нее. К ним относятся: glutInitWindowPosition ( int x , int y ) glutInitWindowSize ( int width , int height ) glutInitDisplayMode ( unsigned int mode) Первые две функции задают соответственно положение и размер окна, а последняя функция определяет различные режи- мы отображения информации, которые могут совместно зада- ваться с использованием операции побитового ѕилиї (ѕ | ї): GLUT_RGBA Режим RGBA. Используется по умолчанию, ес- ли не указаны режимы GLUT_RGBA или GLUT_INDEX GLUT_RGB То же, что и GLUT_RGBA GLUT_INDEX Режим индексированных цветов (использова- ние палитры). Отменяет GLUT_RGBA GLUT_SINGLE Окно с одиночным буфером. Используется по умолчанию. GLUT_DOUBLE Окно с двойным буфером. Отменяет GLUT_SINGLE 10.1. Структура GLUT-приложения 135 GLUT_STENCIL Окно с буфером маски. GLUT_ACCUM Окно с буфером-накопителем. GLUT_DEPTH Окно с буфером глубины. Это неполный список параметров для данной функции, од- нако для большинства случаев этого бывает достаточно. Работа с буфером маски и буфером накопления описана в главе 7. Функции библиотеки GLUT реализуют так называемый со- бытийно-управляемый механизм. Это означает, что есть некото- рый внутренний цикл, который запускается после соответству- ющей инициализации и обрабатывает одно за другим все собы- тия, объявленные во время инициализации. К событиям отно- сятся: щелчок мыши, закрытие окна, изменение свойств окна, передвижение курсора, нажатие клавиши и ѕпустоеї (idle) собы- тие, когда ничего не происходит. Для проведения периодической проверки совершения того или иного события надо зарегистри- ровать функцию, которая будет его обрабатывать. Для этого ис- пользуются функции вида: void glutDisplayFunc ( void (* func ) ( void ) ) void glutReshapeFunc ( void (* func ) ( int width , int height ) ) void glutMouseFunc ( void (* func ) ( int button , int state , int x , int y ) ) void glutIdleFunc ( void (* func ) ( void ) ) void glutMotionFunc ( void (* func ) ( int x , int y ) ) ; void glutPassiveMotionFunc ( void (* func ) ( int x , int y ) ) ; Параметром для них является имя соответствующей функ- ции заданного типа. С помощью glutDisplayFunc() задается функ- ция рисования для окна приложения, которая вызывается при необходимости создания или восстановления изображения. Для 136 Глава 10. OPENGL-приложения с помощью GLUT явного указания, что окно надо обновить, иногда удобно исполь- зовать функцию void glutPostRedisplay ( void ) Через glutReshapeFunc() устанавливается функция обработки изменения размеров окна пользователем, которой передаются новые размеры. glutMouseFunc() определяет функцию-обработчик команд от мыши, а glutIdleFunc() задает функцию, которая будет вызывать- ся каждый раз, когда нет событий от пользователя. Функция, определяемая glutMotionFunс() , вызывается, когда пользователь двигает указатель мыши, удерживая кнопку мы- ши. glutPassiveMotionFunc регистрирует функцию, вызываемую, если пользователь двигает указатель мыши и не нажато ни од- ной кпопки мыши. Контроль всех событий происходит внутри бесконечного цик- ла в функции void glutMainLoop ( void ) которая обычно вызывается в конце любой программы, исполь- зующей GLUT. Структура приложения, использующего анима- цию, будет следующей: #i n c l u d e void MyIdle ( void ) { /* Код , который меняет переменные , определяющие следующий кадр */ } ; void MyDisplay ( void ) { /* Код OpenGL, который отображает кадр */ 10.2. GLUT в среде MICROSOFT VISUAL C++ 6.0 137 /* После рисования переставляем буферы */ glutSwapBuffers ( ) ; } ; void main ( int argcp , char ** argv ) { /* Инициализация GLUT */ g l u t I n i t (&argcp , argv ) ; glutInitWindowSize (640 , 4 8 0 ) ; glutInitWindowPosition (0 , 0 ) ; /* Открытие окна */ glutCreateWindow ( "My OpenGL Application " ) ; /* Выбор режима: двойной буфер и RGBA цвета */ glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH) ; /* Регистрация вызываемых функций */ glutDisplayFunc ( MyDisplay ) ; glutIdleFunc ( MyIdle ) ; /* Запуск механизма обработки событий */ glutMainLoop ( ) ; } ; В случае , если приложение должно строить статичное изоб- ражение, можно заменить GLUT_DOUBLE на GLUT_SINGLE , так как одного буфера в этом случае будет достаточно, и убрать вызов функции glutIdleFunc() 10.2. GLUT в среде Microsoft Visual C++ 6.0 Перед началом работы необходимо скопировать файлы glut.h, glut32.lib glut32.dll в каталоги MSVC\Include\Gl, MSVC\Lib, Windows\System соответственно. Также в этих каталогах на- до проверить наличие файлов gl.h, glu.h, opengl32.lib, glu32.lib, opengl32.dll, glu32.dll, которые обычно входят в состав Visual C++ и Windows. При использовании команд из библиотеки 138 Глава 10. OPENGL-приложения с помощью GLUT GLAUX к перечисленным файлам надо добавить подключаемые файлы библиотеки glaux.h и glaux.lib. Для создания приложения надо выполнить следующие дей- ствия: € Создание проекта: для этого надо выбрать FileNew ProjectsWin32 Console Application, набрать имя проекта, OK. € В появившемся окне выбрать ѕAn empty projectї, Finish, OK. € Текст программы можно либо разместить в созданном тек- стовом файле (выбрав FileNewFilesText File), либо добавить файл с расширением *.c или *.cpp в проект (вы- брав ProjectAdd To ProjectFiles). € Подключить к проекту библиотеки OpenGL. Для этого на- до выбрать ProjectSettingsLink и в поле Object\library modules набрать названия нужных библиотек: opengl32.lib, glu32.lib, glut32.lib и, если надо, glaux.lib. € Для компиляции выбрать BuildBuild program.exe, для выполнения BuildExecute program.exe. € Чтобы при запуске не появлялось текстовое окно, надо вы- брать ProjectSettingsLink и в поле Project Options вме- сто ѕsubsystem:consoleї набрать ѕsubsystem:windowsї, и на- брать там же строку ѕ/entry:mainCRTStartupї. Когда программа готова, рекомендуется перекомпилировать ее в режиме ѕReleaseї для оптимизации по быстродействию и объему. Для этого надо выбрать BuildSet Active Conguration и отметить ѕ. . . -Win32 Releaseї, а затем заново подключить необ- ходимые библиотеки. 10.3. GLUT в среде MICROSOFT VISUAL C++ 2005 139 10.3. GLUT в среде Microsoft Visual C++ 2005 Перед началом работы необходимо скопировать файлы glut.h, glut32.lib и glut32.dll в каталоги MVS8\VC\PlatformSDK\Include, MVS8\VC\PlatformSDK\Lib, Windows\System соответственно. Также в этих каталогах надо проверить наличие файлов gl.h, glu.h, opengl32.lib, glu32.lib, opengl32.dll, glu32.dll, которые обыч- но входят в состав Visual C++ и Windows. При использовании команд из библиотеки GLAUX к перечисленным файлам надо добавить подключаемые файлы библиотеки glaux.h и glaux.lib. Для создания приложения надо выполнить следующие дей- ствия: € Создание проекта: для этого надо выбрать FileNew ProjectsWin32Win32 Console Application, набрать имя проекта, OK. € В появившемся окне во вкладке Application Settings вы- брать ѕConsole applicationї, ѕAn empty projectї, Finish. € Текст программы можно либо разместить в созданном текстовом файле (выбрав FileNewFilesVisual C++ C++File ), либо добавить файл с расширением *.c или *.cpp в проект (выбрав ProjectAdd To ProjectFiles). € Подключить к проекту библиотеки OpenGL. Для этого на- до выбрать ProjectPropertiesConguration Properties LinkerInput и в поле Additional dependencies набрать на- звания нужных библиотек: opengl32.lib, glu32.lib, glut32.lib и, если надо, glaux.lib. € Для компиляции выбрать Build program.exe, для выпол- нения DebugStart Debugging или DebugStart Without Debugging. 140 Глава 10. OPENGL-приложения с помощью GLUT € Чтобы при запуске программы не появлялось консольное текстовое окно, надо выбрать ProjectProperties Conguration PropertiesLinkerSystem и в поле SubSystem вместо ѕConsoleї выбрать ѕWindowsї. Пе- рейти в раздел LinkerAdvanced и в поле Entry Point написать ѕwmainCRTStartupї (без кавычек). Когда программа готова, рекомендуется перекомпилировать ее в режиме ѕReleaseї для оптимизации по быстродействию и объему. Для этого надо выбрать BuildConguration Manager и в поле ѕActive solution congurationї выбрать ѕReleaseї, а затем заново подключить необходимые библиотеки для этой конфигу- рации. 10.4. GLUT в среде Borland C++ Builder 6 Перед началом работы необходимо скопировать файлы glut.h, glut32.lib, glut32.dll в каталоги CBuilder6\Include\Gl, CBuilder6\Lib, Windows\System соответственно. Также в этих каталогах надо проверить наличие файлов gl.h, glu.h, opengl32.lib, glu32.lib, opengl32.dll, glu32.dll, которые обычно входят в состав Borland C++ и Windows. При этом надо учитывать, что оригинальные (для Microsoft Visual C++) версии файла glut32.lib c Borland C++ Builder 6 работать не будут, и следует использовать только совмести- мую версию. Чтобы создать такую версию, надо использовать стандартную программу 'implib', которая находится в каталоге СBuilder6\Bin. Для этого в командной строке надо выполнить команду implib glut32.lib glut32.dll которая создает нужный lib-файл из соответствующего dll-фай- ла. 10.5. GLUT в среде BORLAND C++ BUILDER 2006 141 Для создания приложения надо выполнить следующие дей- ствия: € Создание проекта: для этого надо выбрать FileNew OtherConsole Wizard, OK. € В появившемся окне выбрать Source Type С++, Console Application, сбросить опции ѕUse VCLї, ѕUse CLXї, ѕMulti Threadedї. Нажать ОК. € Текст программы можно либо разместить в созданном текстовом файле, либо удалить его из проекта (Project Remove From Project) и добавить файл с расширением *.c или *.cpp в проект (выбрав ProjectAdd To Project). € Сохраните созданный проект в желаемом каталоге (выбрав FileSave All). € Подключить к проекту библиотеку GLUT. Для этого надо выбрать ProjectAdd To Project и добавить файл glut32.lib € Для компиляции выбрать ProjectBuild . . . , для выполне- ния RunRun. Когда программа готова, рекомендуется перекомпилировать ее в режиме ѕReleaseї для оптимизации по быстродействию и объему. Для этого сначала надо выбрать ProjectOptions Compiler и нажать кнопку ѕReleaseї. 10.5. GLUT в среде Borland C++ Builder 2006 Перед началом работы необходимо скопиро- вать файлы glut.h, glut32.lib, glut32.dll в катало- ги Borland\BDS\4.0\Include\Gl, Borland\BDS\4.0\Lib, 142 Глава 10. OPENGL-приложения с помощью GLUT Windows\System соответственно. Также в этих каталогах надо проверить наличие файлов gl.h, glu.h, opengl32.lib, glu32.lib, opengl32.dll, glu32.dll, которые обычно входят в состав Borland C++ и Windows. При этом надо учитывать, что оригинальные (для Microsoft Visual C++) версии файла glut32.lib c Borland C++ Builder 6 работать не будут, и следует использовать только совмести- мую версию. Чтобы создать такую версию, надо использовать стандартную программу 'implib', которая находится в каталоге Borland\BDS\4.0\Bin. Для этого в командной строке надо вы- полнить команду implib glut32.lib glut32.dll которая создает нужный lib-файл из соответствующего dll-фай- ла. Для создания приложения надо выполнить следующие дей- ствия: € Создание проекта: для этого надо выбрать FileNew OtherConsole Application, OK. € В появившемся окне выбрать Source Type ѕС++ї, ѕConsole Applicationї, сбросить опции ѕUse VCLї, ѕMulti Threadedї. Нажать ОК. € Текст программы можно либо разместить в созданном текстовом файле, либо удалить его из проекта (Project Remove From Project) и добавить файл с расширением *.c или *.cpp в проект (выбрав ProjectAdd To Project). € Сохраните созданный проект в желаемом каталоге (выбрав FileSave All). € Подключить к проекту библиотеку GLUT. Для этого надо выбрать ProjectAdd To Project и добавить файл glut32.lib 10.5. GLUT в среде BORLAND C++ BUILDER 2006 143 € Для компиляции выбрать ProjectBuild . . . , для выполне- ния RunRun. Когда программа готова, рекомендуется перекомпилировать ее в режиме ѕReleaseї для оптимизации по быстродействию и объему. Для этого надо выбрать ProjectBuild Congurations и в списке ѕConguration nameї выбрать ѕRelease Buildї. Глава 11. Использование OpenGL в MFC и VCL Далее будем рассматривать принципы построение оконного приложения Windows с поддержкой OpenGL при помощи воз- можностей библиотек MFC (Microsoft Foundation Classes) и VCL (Visual Component Library). Поскольку Windows является многооконной операционной системой, основная задача приложения на этапе инициализа- ции ѕпривязатьї команды OpenGL к конкретному окну и со- здать для этого окна все вспомогательные буферы (буфер кадра, буфер глубины и т.п.). Сама библиотека не содержит средств для этого, поэтому каждая операционная система, поддерживающая OpenGL, предоставляет свои. Библиотека GLUT представля- ет унифицированный интерфейс для доступа к этой функцио- нальности, однако платой за унификацию является достаточно скромные возможности построения графического интерфейса пользователя, реализованные в GLUT. Для создания приложе- ний с развитым интерфейсом необходимо применять средства конкретной операционной системы для работы с OpenGL. Для инициализации и работы с OpenGL в Windows необхо- 145 146 Глава 11. Использование OPENGL в MFC и VCL димо выполнить следующие шаги: 1) инициализация (при создании окна); а) получение и установка контекста графического устрой- ства (см. п.11.1); б) установка пиксельного формата (п.11.2); в) получение и установка контекста рисования (п.11.3); 2) рисование с помощью OpenGL в окне; 3) освобождение контекстов (при удалении окна). 11.1. Контекст устройства Контекст устройства (device context) важный элемент гра- фики в среде ОС Windows. Контекст устройства указывает место отображения графических команд. Контекстом может быть окно программы на экране, принтер, или другое устройство, поддер- живающее графический вывод. Идентификатор контекста устройства это числовое значе- ние, знание которого позволяет направить графический вывод в нужный контекст. Перед началом рисования необходимо по- лучить это числовое значение, а после рисования нужно кон- текст освободить, т.е. вернуть используемые ресурсы в систему. Несоблюдение этого правила чревато такими последствиями как утечки памяти и прекращение нормальной работы программы. Поскольку нашей задачей является рисование в окне, кон- текст устройства hDC можно получить по идентификатору окна hWnd : HWND hWnd = <код получение идентификатора окна >; HDC hDC = GetDC(hWnd) ; Для освобождения контекста используется команда ReleaseDC : ReleaseDC (hWnd, hDC) ; 11.2. Установка формата пикселей 147 11.2. Установка формата пикселей После получения контекста устройств нужно установить фор- мат пикселей (pixel format) контекста. Это нужно для того, что- бы сообщить операционной системе, какие ресурсы необходимо выделить для данного контекста. Формат пикселей указывает, какие возможности OpenGL мы будем использовать: двойной буфер, буфер маски, буфер глубины, формат цвета и т.д. Чтобы установить формат пикселя, нужно заполнить струк- туру PIXELFORMATDESCRIPTOR и передать ее в текущий кон- текст: PIXELFORMATDESCRIPTOR pfd ; // обнуляем все только что созданной структуры ; ZeroMemory(&pfd , sizeof ( pfd ) ) ; // заполняем структуру pfd . nSize = sizeof ( pfd ) ; pfd . nVersion = 1 ; // флаги показывают , что мы будем использовать // дублирующую буферизацию OpenGL в этом окне Pfd . dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd . iPixelType = PFD_TYPE_RGBA; // полноцветный буфер цвета (8 бит на канал ) pfd . cColorBits = 2 4; // запрашиваем 16 бит на пиксель для буфера глубины pfd . cDepthBits = 1 6 ; pfd . iLayerType = PFD_MAIN_PLANE; int iFormat = ChoosePixelFormat (hDC, &pfd ) ; SetPixelFormat (hDC, iFormat , &pfd ) ; Рассмотрим подробнее функции, которые используются для установки формата пикселя: int ChoosePixelFormat ( HDC hdc , CONST PIXELFORMATDESCRIPTOR * ppfd ) ; 148 Глава 11. Использование OPENGL в MFC и VCL Эта функция позволяет по контексту графического устрой- ства найти пиксельный формат, максимально удовлетворяющий нашим требованиям, и возвращает его дескриптор. Например, если запрошен 24-битный буфер цвета, а контекст графического устройства предоставляет только 8-битный буфер, то функция возвратит формат пикселя с 8-битным буфером. Функция SetPixelFormat устанавливает формат пикселя в кон- текст графического устройства: BOOL SetPixelFormat ( HDC hdc , int iPixelFormat , CONST PIXELFORMATDESCRIPTOR * ppfd ) ; Поскольку мы используем контекст графического устройства с двойным буфером, OpenGL-рисование в контекст происходит в невидимое на экране место в памяти. Это необходимо для предотвращения мерцания. Для того, чтобы изображение появи- лось на экране, нужно вызвать следующую функцию: SwapBuffers ( hDC ) ; 11.3. Контекст рисования (render context) Контекст рисования определяет в какой контекст устройства будут направляться команды OpenGL. Например, если в про- грамме есть несколько окон OpenGL, то перед вызовом команд OpenGL необходимо указать окно, в которое будут направлены эти команды. С контекстом рисования ассоциировано текущее состояние OpenGL, текстуры, дисплейные списки и т.п. Создание контекста рисования hRC : HGLRC hRC; hRC = wglCreateContext (hDC) ; Перед использованием контекста необходимо сделать его те- кущим: 11.4. Класс GLRC 149 wglMakeCurrent (hDC, hRC) ; Далее можно свободно использовать команды OpenGL, не за- бывая вызывать SwapBuers после окончания рисования кадра. После использования контекста рисования его нужно освобо- дить (обычно перед освобождением соответствующего контекста устройства): wglDeleteContext (hRC) ; 11.4. Класс GLRC В п.Б.5 приведен пример класса GLRC , реализующий пере- численные операции. Цикл инициализации и рисования с исполь- зованием этого класса выглядит следующим образом: GLRC* m_pGLRC; // 1. инициализация окна m_pGLRC = new GLRC(hWnd) ; bool r e s = m_pGLRC?>Create ( ) ; i f ( ! r e s ) Error ( "Невозможно создать контекст OpenGL" ) ; // 2. рисование // ( обычно в обработчиках события WM_PAINT) bool r e s = m_pGLRC?>MakeCurrent ( ) ; i f ( ! r e s ) Error ( "Невозможно сделать контекст текущим" ) ; // команды OpenGL g l C l e a r (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) // завершение кадра m_pGLRC?>SwapBuffers ( ) ; 150 Глава 11. Использование OPENGL в MFC и VCL // 3. уничтожение окна // ( обычно в обработчиках события WM_DESTROY) m_pGLRC?>Destroy ( ) ; delete m_pGLRC; 11.5. Использование OpenGL c MFC Если при создании Windows-приложения используется биб- лиотека MFC, то необходимо встроить инициализацию, освобож- дение контекстов и рисование OpenGL в различные обработчики унаследованных классов MFC. Данная книга не является руко- водством по программированию с использованием MFC, поэтому ограничимся советами по использованию OpenGL с этой библио- текой: € Код инициализации и рисования теперь должен находиться в методах (или вызываться из этих методов) класса, уна- следованного от класса CWnd напрямую или косвенно. € Для инициализации OpenGL лучше всего использовать ме- тод OnCreate , для рисования OnPaint , OnUpdate , OnDraw или OnTimer (это зависит от разных факторов, например, от какого именно класса унаследован класс OpenGL-окна и что именно изображается). € Для предотвращения мерцания необходимо перегрузить обработчик сообщения WM_ERASEBKGND , иначе Windows будет заливать фон окна перед вызовом обработчика OnPaint € Для освобождения подойдет обработчик OnDestroy , а для обработки изменений размера окна OnSize € Получить идентификатор окна можно с помощью метода CWnd::GetSafeHwnd 11.5. Использование OPENGL C MFC 151 Пример класса окна, рисование в которое осуществляется при помощи OpenGL. class OpenGLWindow : public CWnd { public : OpenGLWindow ( ) ; // открытые члены класса private : // закрытые члены класса // сигнатуры этих методов определены заранее MFC // и должны выглядеть именно так afx_msg int OnCreate (LPCREATESTRUCT l p C rea teS tru c t ) ; afx_msg BOOL OnEraseBkgnd (CDC* pDC) ; afx_msg void OnPaint ( ) ; afx_msg void OnDestroy ( ) ; // объявление карты сообщений Windows DECLARE_MESSAGE_MAP( ) // класс для хранения контекстов OpenGL GLRC* m_pGLRC; } ; Реализация методов: // конструктор OpenGLWindow : : OpenGLWindow( ) : m_pGLRC(NULL) { } // заполнение карты сообщений BEGIN_MESSAGE_MAP(OpenGLWindow , CWnd) // стандартные макросы MFC ON_WM_CREATE( ) ON_WM_PAINT( ) 152 Глава 11. Использование OPENGL в MFC и VCL ON_WM_DESTROY( ) ON_WM_ERASEBKGND( ) END_MESSAGE_MAP( ) // в этом методе реализуем инициализацию afx_msg int OpenGLWindow : : OnCreate ( LPCREATESTRUCT l pCre at e St ruct ) { m_pGLRC = new GLRC( GetSafeHwnd ( ) ) ; bool r e s = m_pGLRC?>Create ( ) ; i f ( ! r e s ) return FALSE; return CWnd: : OnCreate ( l pC reat eS tru c t ) ; } // запрещаем заливку фона afx_msg BOOL OpenGLWindow : : OnEraseBkgnd (CDC* pDC) { return FALSE; } // здесь рисуем afx_msg void OpenGLWindow : : OnPaint ( ) { CWnd: : OnPaint ( ) ; // делаем текущим m_glRC?>MakeCurrent ( ) ; g l C l e a r (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ; // рисуем то, что хотим нарисовать <методы рисования OpenGL> 11.6. Использование OPENGL C VCL 153 m_glRC?>SwapBuffers ( ) ; } // здесь происходит освобождение ресурсов afx_msg void OpenGLWindow : : OnDestroy ( ) { m_glRC?>Destroy ( ) ; delete m_glRC; CWnd: : OnDestroy ( ) ; } 11.6. Использование OpenGL c VCL Использование OpenGL с VCL другой популярной биб- лиотекой для разработки Windows-приложений, отличается от предыдущего примера только деталям и названиями классов. Вот пример минимального кода на С++, который добавит OpenGL к форме (окну) VCL: class OpenGLForm : public TForm { public : __fastcall OpenGLForm(TComponent* owner ) ; // открытые члены класса private : // закрытые члены класса GLRC* m_pGLRC; // контекст устройства окна published : // сигнатуры этих методов определены заранее void __fastcall FormCreate ( TObject* sender ) ; void __fastcall FormDestroy ( TObject* sender ) ; 154 Глава 11. Использование OPENGL в MFC и VCL void __fastcall FormPaint ( TObject* sender ) ; } ; // конструктор __fastcall OpenGLForm : : OpenGLForm( TComponent* owner ) : TForm( owner ) , m_pGLRC(NULL) { } // в этом методе реализуем инициализацию void __fastcall OpenGLForm : : FormCreate ( TObject* sender ) { m_pGLRC = new GLRC( Handle ) ; bool r e s = m_pGLRC?>Create ( ) ; a s s e r t ( r e s ) ; } // здесь рисуем void __fastcall OpenGLForm : : FormPaint ( TObject* sender ) { // делаем текущим m_glRC?>MakeCurrent ( ) ; g l C l e a r (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ; // рисуем то, что хотим нарисовать <методы рисования OpenGL> m_glRC?>SwapBuffers ( ) ; } // здесь происходит деинициализация 11.6. Использование OPENGL C VCL 155 void __fastcall OpenGLForm : : FormDestroy ( ) { m_glRC?>Destroy ( ) ; delete m_glRC; } Глава 12. OpenGL в .NET В этом разделе рассматривается построение оконного прило- жения с поддержкой OpenGL на платформе Microsoft .NET. Несмотря на то, что OpenGL не имеет встроенной поддерж- ки в .NET, в настоящее время существует достаточно много ре- шений, позволяющих подключать OpenGL к .NET-программам. Мы рассмотрим работу с одной из них свободно-распространя- емой библиотекой Tao Framework. Tao Framеwork (http://www.taoframework.com) реализует про- межуточный уровень между .NET приложением и различными Win32-библиотеками, в частности GL, GLU, GLUT, WGL. 12.1. GLUT в среде Microsoft Visual C# 2005 Простейшим способом создания OpenGL-приложения с среде .NET можно считать использование библиотеки GLUT, доступ- ной через .NET-компоненту Tao.FreeGlut. Далее приводятся шаги, необходимые для создания консоль- ного .NET-приложения в среде Microsoft Visual C# 2005 на C# с GLUT и OpenGL: 157 158 Глава 12. OPENGL в .NET € Убедиться, что на машине установлен GLUT (glut32.dll ле- жит в Windows\System32). € Создание проекта консольного приложения: FileNew ProjectsVisual C#WindowsConsole Application, на- брать имя проекта, OK. € Добавление Tao к проекту: ProjectAdd Reference.NET, найти в списке ѕTao Framework OpenGL Binding For .NETї и ѕTao Framework FreeGLUT Binding For .NETї, выделить оба, ОК. Если компонент нет в списке, необходимо найти их в инсталляционном каталоге библиотеки Tao Framework и добавить через вкладку Browse. Программирование с использование GLUT и OpenGL в .NET на C# практически не отличается от варианта для Win32 и C++. Ниже приведен пример простой программы, аналогичной приме- ру из п.2.5: Программа 12.1. Простой пример OpenGL в C#. using Tao . FreeGlut ; using Tao . OpenGl ; namespace gl_glut_net { class Program { private static int Width = 512; private static int Height = 512; public const int CubeSize = 200; static void Display ( ) { int l e f t , right , top , bottom ; 12.1. GLUT в среде MICROSOFT VISUAL C# 2005 159 l e f t = ( Width ? CubeSize ) / 2 ; r i g h t = l e f t + CubeSize ; bottom = ( Height ? CubeSize ) / 2 ; top = bottom + CubeSize ; Gl . gl Cl e a rC o l o r ( 0 . 7 f , 0 . 7 f , 0 . 7 f , 1 ) ; Gl . g l C l e a r ( Gl .GL_COLOR_BUFFER_BIT) ; Gl . glColor3ub (255 , 0 , 0 ) ; Gl . glBegin ( Gl .GL_QUADS) ; Gl . g l V e r t e x 2 f ( l e f t , bottom ) ; Gl . g l V e r t e x 2 f ( l e f t , top ) ; Gl . g l V e r t e x 2 f ( right , top ) ; Gl . g l V e r t e x 2 f ( right , bottom ) ; Gl . glEnd ( ) ; Gl . g l F i n i s h ( ) ; } static void Reshape ( int w, int h) { Width = w; Height = h ; Gl . glViewport (0 , 0 , w, h ) ; Gl . glMatrixMode ( Gl .GL_PROJECTION) ; Gl . g lLo ad Identity ( ) ; Gl . glOrtho (0 , w, 0 , h , ?1.0 , 1 . 0 ) ; Gl . glMatrixMode ( Gl .GL_MODELVIEW) ; Gl . glLo ad Ide nt it y ( ) ; } static void Keyboard ( byte key , int x , int y ) 160 Глава 12. OPENGL в .NET { const int ESCAPE = 2 7 ; i f ( key == ESCAPE) Glut . glutLeaveMainLoop ( ) ; } static void Main ( s t r i n g [ ] args ) { Glut . g l u t I n i t ( ) ; Glut . glutInitDisplayMode ( Glut .GLUT_RGB) ; Glut . glutInitWindowSize ( Width , Height ) ; Glut . glutCreateWindow ( "Red square example" ) ; Glut . glutDisplayFunc ( Display ) ; Glut . glutReshapeFunc ( Reshape ) ; Glut . glutKeyboardFunc ( Keyboard ) ; Glut . glutMainLoop ( ) ; } } } Обратите внимание, что все команды и константы GL, GLU и GLUT находятся в пространствах имен Gl , Glu и Glut , соответ- ственно. 12.2. Использование OpenGL в WindowsForms OpenGL в WindowsForms требует инициализации, аналогич- ной рассмотренной для библиотек MFC и VCL (см. п.11). В Tao Framework уже реализован простой класс окна OpenGL Tao.Platform.Windows.SimpleOpenGlControl Рассмотрим последовательность действий, необходимую для 12.2. Использование OPENGL в WINDOWSFORMS 161 создания простого оконного приложения в WindowsForms и с поддержкой OpenGL: € Создание проекта приложения: FileNewProjectsVisual C#WindowsWindows Application, набрать имя проек- та, OK. € Добавление Tao к проекту: ProjectAdd Reference.NET, найти в списке ѕTao Framework OpenGL Binding For .NETї и ѕTao Framework Windows Platform API Binding For .NETї, выделить оба, ОК. Если компонент нет в списке, необходи- мо найти их в инсталляционном каталоге библиотеки Tao Framework и добавить через вкладку Browse. € Чтобы удобно создать окно OpenGL, необходимо добавить соответствующий объект на панель инструментов. Для этого нужно в контекстном меню панели ѕToolboxї вы- брать пункт ѕChoose Items...ї, в появившемся списке най- ти ѕSimpleOpenGLControlї, поставить галочку около него, ОК. € Добавление окна OpenGL на форму: на панели ѕToolboxї найдите ѕSimpleOpenGLControlї и перетащите на форму приложения. Окно должно заполняться черным цветом. € Инициализация OpenGL: в конструкторе формы после вы- зова InitializeComponent() добавить вызов функции создания контекста simpleOpenGlControl1.InitializeContexts() Функции рисования OpenGL можно добавлять в обработчик события Paint окна OpenGL (не путать с Paint формы). Часть IV Приложения 163 Приложение А. Примитивы библиотек GLU и GLUT Рассмотрим стандартные команды построения примитивов, которые реализованы в библиотеках GLU и GLUT. Чтобы построить примитив из библиотеки GLU, надо сна- чала создать указатель на quadric-объект с помощью коман- ды gluNewQuadric() , а затем вызвать одну из команд gluSphere() , gluCylinder() , gluDisk() , gluPartialDisk() . Рассмотрим эти команды отдельно: void gluSphere ( GLUquadricObj * qobj , GLdouble radius , GLint s l i c e s , GLint s t a c k s ) Эта функция строит сферу с центром в начале координат и радиусом radius . При этом число разбиений сферы вокруг оси z задается параметром slices , а вдоль оси z параметром stacks void gluCylinder ( GLUquadricObj * qobj , GLdouble baseRadius , GLdouble topRadius , GLdouble height , GLint s l i c e s , GLint s t a c k s ) 165 166 Приложение А. Примитивы библиотек GLU и GLUT Данная функция строит цилиндр без оснований (кольцо), продольная ось параллельна оси z, заднее основание имеет ра- диус baseRadius , и расположено в плоскости z = 0, переднее основание имеет радиус topRadius и расположено в плоскости z = height . Если задать один из радиусов равным нулю, то будет построен конус. Параметры slices и stacks имеют аналогичный смысл, что и в предыдущей команде. void gluDisk ( GLUquadricObj * qobj , GLdouble innerRadius , GLdouble outerRadius , GLint s l i c e s , GLint loops ) Функция строит плоский диск (круг) с центром в начале ко- ординат и радиусом outerRadius . Если значение innerRadius отлич- но от нуля, то в центре диска будет находиться отверстие ради- усом innerRadius . Параметр slices задает число разбиений диска вокруг оси z, а параметр loops число концентрических колец, перпендикулярных оси z. void g l u P a r t i a l D i s k ( GLUquadricObj * qobj , GLdouble innerRadius , GLdouble outerRadius , GLint s l i c e s , GLint loops , GLdouble startAngle , GLdouble sweepAngle ) ; Отличие этой команды от предыдущей заключается в том, что она строит сектор круга, начальный и конечный углы ко- торого отсчитываются против часовой стрелки от положитель- ного направления оси y и задаются параметрами startAngle и sweepAngle . Углы измеряются в градусах. Команды, проводящие построение примитивов из библиоте- ки GLUT, реализованы через стандартные примитивы OpenGL 167 и GLU. Для построения нужного примитива достаточно произ- вести вызов соответствующей команды. void g l u t S o l i d S p h e r e ( GLdouble radius , GLint s l i c e s , GLint s t a c k s ) void glutWireSphere ( GLdouble radius , GLint s l i c e s , GLint s t a c k s ) Команда glutSolidSphere() строит сферу, а glutWireSphere() каркас сферы радиусом radius. Остальные параметры те же, что и в предыдущих командах. void glutSolidCube ( GLdouble s i z e ) void glutWireCube ( GLdouble s i z e ) Команды строят куб или каркас куба с центром в начале координат и длиной ребра size. void glutSolidCone ( GLdouble base , GLdouble height , GLint s l i c e s , GLint s t a c k s ) void glutWireCone ( GLdouble base , GLdouble height , GLint s l i c e s , GLint s t a c k s ) Эти команды строят конус или его каркас высотой height и радиусом основания base, расположенный вдоль оси z. Основа- ние находится в плоскости z = 0. void g lut S o l id T o rus ( GLdouble innerRadius , GLdouble outerRadius , GLint nsides , GLint r i n g s ) void glutWireTorus ( GLdouble innerRadius , GLdouble outerRadius , GLint nsides , GLint r i n g s ) Эти команды строят тор или его каркас в плоскости z = 0. Внутренний и внешний радиусы контролируются параметрами 168 Приложение А. Примитивы библиотек GLU и GLUT innerRadius и outerRadius . Параметр nsides задает число сторон в кольцах, составляющих ортогональное сечение тора, а rings число радиальных разбиений тора. void glutSolidTetrahedron ( void ) void glutWireTetrahedron ( void ) Эти команды строят тетраэдр (правильную треугольную пи- рамиду) или его каркас, при этом радиус описанной сферы во- круг него равен 1. void glutSolidOctahedron ( void ) void glutWireOctahedron ( void ) Эти команды строят октаэдр или его каркас, радиус описан- ной вокруг него сферы равен 1. void glutSolidDodecahedron ( void ) void glutWireDodecahedron ( void ) Эти команды строят додекаэдр или его каркас, радиус опи- санной вокруг него сферы равен квадратному корню из трех. void g l u t S o l i d I c o s a h e d r o n ( void ) void glutWireIcosahedron ( void ) Эти команды строят икосаэдр или его каркас, радиус описан- ной вокруг него сферы равен 1. Правильное построение перечисленных примитивов возмож- но при удалении невидимых линии и поверхностей, для че- го надо включить соответствующий режим вызовом команды glEnable(GL_DEPTH_TEST) Приложение Б. Демонстрационные программы Б.1. Пример 1: Простое GLUT-приложение Этот простой пример предназначен для демонстрации струк- туры GLUT-приложения и простейших основ OpenGL. Резуль- татом работы программы является случайный набор цветных прямоугольников, который меняется при нажатии левой кнопки мыши. С помощью правой кнопки мыши можно менять режим заливки прямоугольников. Программа Б.1. Простой пример OpenGL. #include #include #i f d e f random #undef random #endif #define random (m) ( float ) rand ( ) *m/RAND_MAX 169 |