Open GL
de301fb4

Windows-приложение - Win32 Application


Достоинством является непосредственное взаимодействие с WinAPI. Начальная инициализация несколько усложняется, но зато вы имеете полноценное windows-приложение. Такой тип приложения подходит для написания серьезных больших программ. Кто-нибудь, конечно, скажет, что приложение непереносимо. Вам нужно написать работающее приложение для windows, а не неработающее, но переносимое приложение.
По поводу переносимости, хочу заметить следующее. В стандарте по языку Си сказано, что код на языке Си может быть платформенно независимым и платформенно зависимым. Из этого следует, что для обеспечения переносимости большой программы, вам придется делать несколько вариантов и затачивать ее под конкретные платформы. Код, относящийся к OpenGL, практически переносим. Непереносима только начальная инициализация. Конечно, вы можете попробовать Java-приложение, но тут возникают свои сложности. Так что, выбор за вами.
Создайте проект Win32 Application. Инструкции смотри в предыдущем разделе. Только имена дайте win и win.c. Теперь будем писать файл win.c. Внесите комментарии, заголовочные файлы и функции display и resize, см. предыдущий раздел. Из функций display и resize уберите слово CALLBACK. А в функции display замениете auxSwapBuffers() на

glFinish(); SwapBuffers(wglGetCurrentDC());

После включения заголовочных файлов объявите следующие глобальные переменные.

HWND hWnd; HGLRC hGLRC; HDC hDC;

Теперь вставьте код функции, которая устанавливает параметры контекста воспроизведения OpenGL.

int SetWindowPixelFormat() { int m_GLPixelIndex; PIXELFORMATDESCRIPTOR pfd; pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 32; pfd.cRedBits = 8; pfd.cRedShift = 16; pfd.cGreenBits = 8; pfd.cGreenShift = 8; pfd.cBlueBits = 8; pfd.cBlueShift = 0; pfd.cAlphaBits = 0; pfd.cAlphaShift = 0; pfd.cAccumBits = 64; pfd.cAccumRedBits = 16; pfd.cAccumGreenBits = 16; pfd.cAccumBlueBits = 16; pfd.cAccumAlphaBits = 0; pfd.cDepthBits = 32; pfd.cStencilBits = 8; pfd.cAuxBuffers = 0; pfd.iLayerType = PFD_MAIN_PLANE; pfd.bReserved = 0; pfd.dwLayerMask = 0; pfd.dwVisibleMask = 0; pfd.dwDamageMask = 0; m_GLPixelIndex = ChoosePixelFormat( hDC, &pfd); if(m_GLPixelIndex==0) // Let's choose a default index. { m_GLPixelIndex = 1; if(DescribePixelFormat(hDC,m_GLPixelIndex,sizeof(PIXELFORMATDESCRIPTOR),&pfd)==0) return 0; } if (SetPixelFormat( hDC, m_GLPixelIndex, &pfd)==FALSE) return 0; return 1; }


Информацию о структуре PIXELFORMATDESCRIPTOR смотрите в справочнике. Я пользуюсь MSDN. Сейчас MSDN входит в MS Developer Studio. Редактировать параметры этой структуры вам вряд ли придется. А если придется, то я не смогу тут описать все. Перевести справочник я, конечно, могу, но это вам вряд ли поможет. Книга не предназначена для этого. Здесь рассматриваются конкретные примеры и упражнения.

Теперь напишем функцию обработки сообщений нашего окна.

LRESULT CALLBACK WindowFunc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) { float pos[4] = {3,3,3,1}; float dir[3] = {-1,-1,-1}; PAINTSTRUCT ps; switch(msg) { // сообщение WM_CREATE приходит // один раз при создании окна case WM_CREATE: // получаем контекст устройства нашего окна hDC = GetDC(hWnd); // устанавливаем параметры контекста воспроизведения OpenGL SetWindowPixelFormat(); // создаем контекст воспроизведения OpenGL hGLRC = wglCreateContext(hDC); // делаем его текущим wglMakeCurrent(hDC, hGLRC); // далее см. предыдущий раздел glEnable(GL_ALPHA_TEST); glEnable(GL_DEPTH_TEST); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glLightfv(GL_LIGHT0, GL_POSITION, pos); glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dir); break; // это сообщение приходит при уничтожении окна case WM_DESTROY: // удаляем созданный выше // контекст воспроизведения OpenGL if (hGLRC) { wglMakeCurrent(NULL, NULL); wglDeleteContext(hGLRC); } // освобождаем контекст устройства нашего окна ReleaseDC(hWnd, hDC); PostQuitMessage(0); break; // это сообщение приходит всякий раз, // когда нужно перерисовать окно case WM_PAINT: BeginPaint(hWnd, &ps); display(); EndPaint(hWnd, &ps); break; case WM_SIZE: resize( LOWORD(lParam), HIWORD(lParam) ); break; default: return DefWindowProc(hWnd,msg,wParam,lParam); } return 0; }

И последнее, осталось написать функцию WinMain.

int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR str,int nWinMode) { MSG msg; WNDCLASS wcl; wcl.hInstance=hThisInst; wcl.lpszClassName = "OpenGLWinClass"; wcl.lpfnWndProc = WindowFunc; wcl.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wcl.hIcon = NULL; wcl.hCursor = LoadCursor(NULL,IDC_ARROW); wcl.lpszMenuName = NULL; wcl.cbClsExtra = 0; wcl.cbWndExtra = 0; wcl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); RegisterClass(&wcl); hWnd = CreateWindow( "OpenGLWinClass", "Win API Template", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 200, 150, 400, 420, HWND_DESKTOP, NULL, hThisInst, NULL); ShowWindow(hWnd,nWinMode); UpdateWindow(hWnd); while(1) { while( PeekMessage(&msg,NULL,0,0,PM_NOREMOVE) ) if(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } else return 0; display(); } return 0; }

OpenGL требует свойства WS_CLIPCHILDREN и WS_CLIPSIBLINGS для окна в Windows. Поэтому были добавлены эти свойства при создании окна в функцию Createwindow. Также обратите внимание, что функция display вызывается в бесконечном цикле. Она вызывается, когда в очереди сообщений окна нет ничего. Эта же функция вызывается, когда нужно отрисовать окно заново - обработчик WM_PAINT.


Исходный файл смотрите . Исполняемый файл .


Содержание раздела