3D графика на основе OpenGL WinApi C++

Автор: | 05.02.2018

Описание шаблона приложения
Поверхностная модель. Списки. Стек матриц. OpenGL – машина состояний
Преобразование объекта
Построение вида
Перспективная и ортогональная проекции. Отсечение
Анимация
Режимы модели и проекции
Контрольные вопросы
Файлы-исходники приложения

Описание шаблона приложения

Изложение теории будет идти параллельно с практической реализацией на основе шаблона приложения для создания модели рупорной антенны.
Создайте проект WinAPI приложения на основе файлов-исходников.
По сравнению с шаблоном WinAPI приложения без использования OpenGL кроме основного файла main.cpp в проект были добавлены файл api.h (подключает библиотеки WinAPI и OpenGL) и файлы (engine.h, engine.cpp) для описания класса Engine. В классе Engine инкапсулированы функции, обеспечивающие описание модели объекта (Draw, DrawAxes, DrawModel) а также устанавливающие взаимосвязь контекста устройства Windows с контекстом воспроизведения OpenGL (функция SetWindowPixelFormat).

Базовая библиотека OpenGL установлена как часть операционной системы Windows. В файле api.h еще подключается  и вспомогательная библиотека GLUT. Файлы вспомогательной библиотеки   получите из архива glutdlls37beta.

Для запуска в отладочном режиме файлы glut.h и  glut32.lib разместите в директориях проекта там же, где и файлы-исходники.

При запуске программы локальная СК совпадает с глобальной СК.

Поверхностная модель. Списки. Стек матриц. OpenGL – машина состояний

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

Проволочная модель создается примитивами GL_LINE_LOOP, GL_LINES, поверхностная –GL_TRIANGLE_STRIP.

Геометрические примитивы (точка, линия, треугольник) определяются текущим цветом (RGB) и упорядоченным списком вершин между glBegin (тип примитива) и glEnd (), например:

glColor3d(1,0,0);
 glBegin(GL_LINES);
 glVertex3f (0,0,0);
 glVertex3f (0,0,1);
 glEnd();

В проволочной модели для отрисовки антенны использовался такой код:

glBegin(GL_LINE_LOOP);
        // v0-v1-v2-v3
        glVertex3f(0.4,0.2,0);
        glVertex3f(-0.4,0.2,0);
        glVertex3f(-0.4,-0.2,0);
        glVertex3f(0.4,-0.2,0);
glEnd();

glBegin(GL_LINE_LOOP);
        // v4-v5-v6-v7
        glVertex3f(0.2,0.1,-0.4);
        glVertex3f(-0.2,0.1,-0.4);
        ...

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

glBegin(GL_TRIANGLE_STRIP);
         // v2-v3-v6-v7-v10-v11
         glVertex3f(-0.4,-0.2,0);
         glVertex3f(0.4,-0.2,0);
         glVertex3f(-0.2,-0.1,-0.4);
         glVertex3f(0.2,-0.1,-0.4);
         glVertex3f(-0.2,-0.1,-0.8);
         glVertex3f(0.2,-0.1,-0.8);
glEnd();

Нижняя (правая) и верхняя (левая) грани антенны одинаковы по форме и отличаются лишь положением. Поэтому для их создания используются подпрограммы. Аналогом подпрограммы в OpenGL есть список. Пример определения и вызова списка, в котором задан отрезок, приводится ниже:

glNewList(1, GL_COMPILE);
 glColor3d(0,0,1);
 glBegin(GL_LINES);
 glVertex3f (0,0,0);
 glVertex3f (0,0,1);
 glEnd();
 glEndList();
 glCallList(1);

Перед повторным вызовом списка, которым определяется грань антенны, необходимо выполнить преобразование поворота. При этом, после каждого преобразования становится активной текущая (последняя) СК. Для возврата в исходную (глобальную) СК необходимо сохранять ее параметры в стеке матриц (команда glPushMatrix) и восстанавливать их (команда glPopMatrix). Пример:

glCallList(1);
 glPushMatrix();
 glRotatef(180.0, 0.0, 0.0, 1.0);
 glCallList(1);
 glPopMatrix();

Результат может быть таким (цвета как бы смешались):



Для того, чтобы не смешивались цвета поверхностей, необходимо включить состояние контроля за тестом глубины. Для этого используется команда glEnable(GL_DEPTH_TEST), в программе она закомментирована (см. функцию Engine::Init в файле engine.cpp).

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

Преобразование объекта

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


Для выполнения задания необходимо изменить положение антенны через элементарные аффинные преобразования.

Функции аффинных преобразований закомментированы в программе (см. определение Engine::Draw в файле engine.cpp). Их необходимо не только раскомментировать, но и расположить в упорядоченной последовательности из 5 элементарных преобразований (см. рисунок выше). Примеры функций:

glTranslatef(0.0, 1.5, 0.0); // СК переносится на 1.5 вдоль Y
// СК поворачивается на 30 градусов вокруг оси x против часовой стрелки
glRotatef(30.0, 1.0, 0.0, 0.0);

Обратите внимание, что каждое последующее преобразование СК выполняется относительно текущей СК.

Построение вида

Вид определяется взаимным положением объектов и наблюдателя и плоскости проекций

Возможны 2-а способа получения вида на объект:

  • объекты перемещаются, наблюдатель неподвижен;
  • объекты неподвижны, наблюдатель перемещается.

Эти действия можно сравнить с фотосессией, при которой перемещаются как фотограф, так и фотомодели. Математически они описываются матрицами преобразований объекта и матрицей вида. Обе матрицы в конечном итоге перемножаются, а композиция матриц используется для перерасчета точек объектов сцены.
Выше мы рассмотрели 1-й способ получения вида, теперь рассмотрим 2-й. Матрица вида в OpenGL определяется функцией:

gluLookAt(eyeX, eyeY, eyeZ, atX, atY, atZ, upX, upY, upZ)


Параметры (eyex, eyey, eyez), параметры (atx, aty, atz) определяют начало и конец вектора наблюдения. Параметры (upx, upy ,upz) определяют поворот камеры. Если, например, камера не повернута, то задается значение (0,1,0). Параметры функции gluLookAt определяются относительно текущей СК. Поэтому, ее целесообразно использовать до преобразования всех объектов сцены, пока видовая матрица еще единичная.

Перспективная и ортогональная проекции. Отсечение

Задание. Установить центральную проекцию (функция gluPerspective). Найти функцию в программе и, меняя параметры функции, определить наиболее наглядный вид рупорной антенны.
Два вида проекций можно создавать в OpenGL – центральная и ортогональная.

Команды, которые задают способ проецирования, одновременно определяют объем, за пределами которого объекты отсекаются. В случае центрального проецирования это усеченная пирамида, при ортогональном проецировании – параллелепипед. Объем видимости определяется в СК, ось z которой проходит из точки наблюдения через центр сцены. Обе точки определяются командой gluLookAt. Сечение пирамиды в плоскости, проходящей через центр сцены, определяет размеры видового экрана.
Центральная проекция определяется функцией:

gluPerspective(fovy, aspect, zNear, zFar ),

где:
fovy определяет угол обзора (в градусах) пирамиды отсечения в горизонтальной плоскости;
aspect определяет отношение угла обзора в горизонтальной плоскости к углу обзора во фронтальной плоскости, одновременно этот параметр определяет отношение ширины к высоте для видового экрана.
zNear определяет расстояние от наблюдателя к ближней плоскости отсечения;
zFar определяет расстояние от наблюдателя к дальней плоскости отсечения.
Ортогональная проекция определяется функцией:

glOrtho(left, right, bottom, top, near, far),

где:
left, right определяют координаты влево и вправо для ближней плоскости отсечения
bottom, top определяют координаты вниз и вверх для ближней плоскости отсечения;
near, far определяют расстояния вдоль оси z до ближней и дальней плоскостей отсечения.

Анимация

Задание. Обеспечить возможность вращения антенны:

  • изменяя угол alpha при перемещении курсора мышки вправо (влево) и угол beta при движении вверх (вниз).
  • вокруг собственной оси (изменяется угол gamma) при движении курсора мышки и нажатой клавише Ctrl.
  • сканированием – одновременное вращение вокруг оси Y глобальной СК и вокруг собственной оси (ось z). Сканирование обеспечить при помощи таймера.

Для реализации заданий необходимо в класс Engine (см. файл engine.h) добавить переменные alpha, beta и gama. Эти переменные инициализируются при событии WM_CREATE:

engine->alpha=0, engine->beta=0, engine->gama=0;

При событиях WM_LBUTTONDOWN и WM_MOUSEMOVE этим переменным передаются перемещения курсора:

case WM_LBUTTONDOWN:
 mouse_point.x = LOWORD(lParam); // Координаты в системе окна
 mouse_point.y = HIWORD(lParam);
 break;
 case WM_MOUSEMOVE:
 if (UINT(wParam) & MK_LBUTTON)
 {
 if (UINT(wParam) & MK_CONTROL) {
 engine->gama += LOWORD(lParam) - mouse_point.x;
 engine->gama += HIWORD(lParam) - mouse_point.y;
 } else {
 engine->alpha += LOWORD(lParam) - mouse_point.x;
 engine->beta += HIWORD(lParam) - mouse_point.y;
 }
 mouse_point.x = LOWORD(lParam); // Координаты в системе окна
 mouse_point.y = HIWORD(lParam)
 InvalidateRect(hWnd, NULL, FALSE);
 }
 break;

Добавьте в файл engine.h описание структуры _Point:

#ifndef _POINT
 struct _Point
 {
 double x, y;
 };
 #define _POINT
 #endif

Объявите в файле main.cpp глобальную переменную:

 _Point mouse_point;

В определение функции Draw (файл engine.cpp) введите описание преобразований вращения с параметрами-переменными:

 glTranslatef(0.0, 0.15, 0.0);
 glRotatef(alpha, 0.0, 1.0, 0.0);
 glRotatef(30.0, 0.0, 1.0, 0.0);
 glRotatef(beta, 1.0, 0.0, 0.0);
 glRotatef(-60.0, 1.0, 0.0, 0.0);
 glTranslatef(0.0, 0.0, 1.10);
 glRotatef(gama, 0.0, 0.0, 1.0);
 glRotatef(20.0, 0.0, 0.0, 1.0);

Обратите внимание, что при использовании параметров-переменных должна сохраняться та же последовательность преобразований, что и без них.

Для обеспечения сканирования антенны необходимо создать таймер (подробнее см. раздел Анимация изображения):

SetTimer(hWnd,TIMER_2SEC,2000,NULL); // интервал две секунды

Не забудьте в заголовке файла main.cpp определить идентификатор таймера:

const unsigned int TIMER_2SEC = 1; // идентификатор таймера

При вызове события таймера значения переменной углов изменяются с определенным шагом.

case WM_TIMER: // обработка сообщения WM_TIMER
 engine->alpha = engine->alpha + 5.0;
 … 
InvalidateRect(hWnd, NULL, FALSE); //вызов события WM_PAINT
break;

Обеспечьте возможность запуска вращения антенны при нажатии на клавишу P (пуск) и остановку – при нажатии на клавишу S (stop). Пример оформления события нажатия на клавишу приводится ниже:

case WM_KEYDOWN:
 int KeyPressed;
 KeyPressed = int(wParam);
 if (KeyPressed == int('P'))
 { ...
 }
 break;

Работа таймера прекращается функцией:

KillTimer (hWnd,TIMER_2SEC); // уничтожение таймера

Дополнительное задание: добавьте к модели антенны ось, на которой она держится.

Режимы модели и проекции

Выше были описаны процессы моделирования сцены и создание проекции с отсечением. Моделирование сцены осуществлялось 2-я способами – через преобразования объекта и определение вида. Оба способа используют одни и те же базовые матричные преобразования, только для определения вида используется обратная матрица. В конечном итоге матрицы перемножаются, и сцена описывается одной матрицей (матрицей «модель-вид»).
Механизм моделирования проекции с отсечением несколько другой. Поэтому, при моделировании изображения используются матрица «модель-вид» и матрица проекции.
Для работы с матрицами предусмотрены 2-а режима, которые переключаются командой glMatrixMode:

glMatrixMode(GL_PROJECTION) – активен режим проекции;
 glMatrixMode(GL_MODELVIEW) – активен режим модели.

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

Контрольные вопросы:

  1. Параметры команд определения матрицы преобразований объекта (glTranlsate, glRotate, glScale).
  2. Глобальная и локальная СК. Относительно какой СК происходит следующее преобразование – текущей или глобальной? Как сохранить текущую СК?
  3. Параметры команды определения матрицы вида (gluLookAt). Когда целесообразно использовать эту команду?
  4. Модель центральной и ортогональной проекции. В какой СК определяется объем отсечения? Как определяются размеры окна изображения? Как определяется начало текущей СК в окне изображения? Как определяется положение осей текущей СК на изображении?
  5. Параметры команд gluPerspective и glOrtho.
  6. Чем обусловлено использование режимов проекции и модели?
  7. Для чего используются списки команд OpenGL
  8. OpenGL — машина состояний. Что это означает?

Файлы-исходники приложения

Header Files

api.h

#include <windows.h> // Заголовочный файл для использования функций Windows
#ifndef __API__
#define __API__
#pragma comment( lib, "glut32.lib" ) // Подключается библиотека glut32.lib
#include "glut.h" // Заголовочный файл библиотеки glut32
#endif
// Файлы glut.h и glut32.lib размещаются в директории проекта, 
// там же, где и файлы-исходники (.cpp) с заголовочными файлами (.h)

engine.h

#include "api.h"
#ifndef __ENGINE
#define __ENGINE
class Engine {
 GLsizei Height, Width;
 GLvoid DrawAxes(GLvoid); // Отрисовка осей
 GLvoid DrawModel(GLvoid); // Отрисовка модели
public:
 GLvoid Resize(GLsizei width, GLsizei height); // Функция, вызываемая при изменении размеров окна
 GLvoid Init(GLvoid); // Функция, для задания начальных параметров
 GLvoid Draw(GLvoid); // Отрисовка (render) сцены 
 int SetWindowPixelFormat(HDC hDC); //функция, которая устанавливает параметры контекста воспроизведения OpenGL 
};
#endif

Source Files

main.cpp

//#include<windows.h>
#include "engine.h"
HWND hWnd;
HGLRC hGLRC;
HDC hDC;
Engine *engine;

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)
{
case WM_CREATE:
engine = new Engine();
hDC = GetDC(hWnd); // получаем контекст устройства нашего окна
engine->SetWindowPixelFormat(hDC); // устанавливаем параметры контекста воспроизведения OpenGL
hGLRC = wglCreateContext(hDC); // создаем контекст воспроизведения OpenGL
wglMakeCurrent(hDC, hGLRC); // делаем его текущим
engine->Init();
break;
case WM_DESTROY:
if (hGLRC) 
{ // удаляем созданный выше контекст воспроизведения OpenGL
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hGLRC);
} // освобождаем контекст устройства нашего окна
ReleaseDC(hWnd, hDC);
PostQuitMessage(0);
break;
case WM_PAINT:
BeginPaint(hWnd, &ps);
engine->Draw();
EndPaint(hWnd, &ps);
break;
case WM_SIZE:
engine->Resize( LOWORD(lParam), HIWORD(lParam) );
break; 
case WM_ERASEBKGND:
 return 1;
break;
default:
return DefWindowProc(hWnd,msg,wParam,lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hThisInst,HINSTANCE hPrevInst,LPSTR str,int nWinMode)
{
MSG msg;
WNDCLASS wcl;
wcl.hInstance=hThisInst;
wcl.lpszClassName = (LPCWSTR) "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((LPCWSTR) "OpenGLWinClass",L"Win32 OpenGL 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(); // функция display вызывается в бесконечном цикле, причем, когда в очереди сообщений окна нет ничего.
}
return 0;
}

engine.cpp

#include "engine.h"
GLvoid Engine::Resize(GLsizei width, GLsizei height){
 if (height == 0) 
 {
 height = 1; 
 }
 glViewport(0, 0, width, height); // Устанавливается область просмотра
 Height = height;
 Width = width;
 //glDepthRange(0, 1); //Глубина каждой точки записывается в z-буфер
 //с помощью которого OpenGL удаляет невидимые линии и поверхности
}

GLvoid Engine::Init(GLvoid){
 glClearColor(0.85f, 0.85f, 1.0f, 1.0f); // Устанавливается синий фон
 //glClearDepth(1.0f); // Устанавливается значение для
 // заполнения буфера глубины по умолчанию
 //glEnable(GL_DEPTH_TEST); // Включается тест глубины
 //glDepthFunc(GL_LEQUAL); // Устанавливается значение, используемое
 // в сравнениях при использовании
 // буфера глубины
//glShadeModel(GL_SMOOTH); // Включается плавное затенение
 //glEnable(GL_LINE_SMOOTH); // Включается сглаживание линий
 //glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // Выбирается самый качественный
 // режим сглаживания для линий
 //glEnable(GL_BLEND); // Включается смешение цветов, необходимое
 //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // для работы сглаживания и задается
 // способ смешения
}

GLvoid Engine::Draw(GLvoid) 
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Очищается буфер кадра и буфер глубины
 // Текущая матрица сбрасывается на единичную
 glMatrixMode(GL_PROJECTION); // Действия будут производиться с матрицей проекции
 glLoadIdentity();
 //glTranslatef(0.0, 0.5, 0.0); 
 //glFrustum(-1, 1, -1, 1, 3, 10); // Устанавливается перспективная проекция
 gluPerspective (30, 1, 3, -3); // Устанавливается перспективная проекция 
 //glOrtho(-1, 1, -1, 1, 3, 10); // Устанавливается ортогональная проекция 
 //gluOrtho2D(-10, 10, -10, 10); // Устанавливается ортогональная проекция
glMatrixMode(GL_MODELVIEW); // Действия будут производиться с матрицей модели
 glLoadIdentity(); 
 gluLookAt (5, 5, 5, 0, 0, 0, 0, 1, 0); //Определяется вид ( Mview )
 DrawAxes(); //рисуются оси камеры
//Определяется матрица модели (Mmodel)
 //glTranslatef(0.0, 0.0, 8.0); // Система координат переносится на 8 единиц вглубь сцены 
 //glRotatef(-90.0, 1.0, 0.0, 0.0); // и поворачивается на 30 градусов вокруг оси x,
 //glRotatef(90.0, 0.0, 1.0, 0.0); // а затем на 20 градусов вокруг оси y
 //glRotatef(40.0, 0.0, 0.0, 1.0); // а затем на 40 градусов вокруг оси z
 //определена матрица ( Mview * Mmodel)
 //определена матрица (Mprojection*Mview * Mmodel)
// МОДЕЛИРОВАНИЕ
 //Рисуются оси модели (антенны)
 glPushMatrix();
 glScalef(0.5, 0.5, 0.5); // Масштабирование по осям
 DrawAxes(); 
 glPopMatrix();
 //glScalef(2, 2, 2); // Масштабирование по осям
//рисуется модель (антенна) 
 DrawModel(); 
SwapBuffers(wglGetCurrentDC());
}GLvoid Engine::DrawAxes(GLvoid) // Отрисовка осей
{
glColor3d(1,0,0);
 glBegin(GL_LINES); 
 glVertex3f (0,0,0); 
 glVertex3f (1,0,0); 
 glEnd();
glColor3d(0,1,0);
glBegin(GL_LINES); 
 glVertex3f (0,0,0); 
 glVertex3f (0,1,0); 
 glEnd();
glColor3d(0,0,1);
glBegin(GL_LINES); 
 glVertex3f (0,0,0); 
 glVertex3f (0,0,1); 
 glEnd();
 }
//antena v9-------v8
//     v5------v4 | 
//  v1--|-----v0| |
//  |   |     | |v11
//  |  v6-----|-v7
//  |         |
// v2--------v3
GLvoid Engine::DrawModel(GLvoid) // Отрисовка модели
{
 glColor3d(0,0,0);
glBegin(GL_LINE_LOOP);
 // v0-v1-v2-v3
 glVertex3f(0.4,0.2,0);
 glVertex3f(-0.4,0.2,0);
 glVertex3f(-0.4,-0.2,0);
 glVertex3f(0.4,-0.2,0);
glEnd();
glBegin(GL_LINE_LOOP);
 // v4-v5-v6-v7
 glVertex3f(0.2,0.1,-0.4);
 glVertex3f(-0.2,0.1,-0.4);
 glVertex3f(-0.2,-0.1,-0.4);
 glVertex3f(0.2,-0.1,-0.4);
glEnd();
glBegin(GL_LINE_LOOP);
 // v8-v9-v10-v11
 glVertex3f(0.2,0.1,-0.8);
 glVertex3f(-0.2,0.1,-0.8);
 glVertex3f(-0.2,-0.1,-0.8);
 glVertex3f(0.2,-0.1,-0.8);
glEnd();
glBegin(GL_LINE_STRIP);
 // v0-v4-v8
 glVertex3f(0.4,0.2,0);
 glVertex3f(0.2,0.1,-0.4);
 glVertex3f(0.2,0.1,-0.8);
glEnd();
glBegin(GL_LINE_STRIP);
 // v1-v5-v9
 glVertex3f(-0.4,0.2,0);
 glVertex3f(-0.2,0.1,-0.4);
 glVertex3f(-0.2,0.1,-0.8);
glEnd();

glBegin(GL_LINE_STRIP);
 // v2-v6-v10
 glVertex3f(-0.4,-0.2,0);
 glVertex3f(-0.2,-0.1,-0.4);
 glVertex3f(-0.2,-0.1,-0.8);
glEnd();
glBegin(GL_LINE_STRIP);
 // v3-v7-v11
 glVertex3f(0.4,-0.2,0);
 glVertex3f(0.2,-0.1,-0.4);
 glVertex3f(0.2,-0.1,-0.8);
glEnd();
}
// код функции, которая устанавливает параметры контекста воспроизведения OpenGL. 
int Engine::SetWindowPixelFormat(HDC hDC)
{
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;
// Передается на рассмотрение системе, выбранный нами формат пикселей. Функция просматривает в контексте устройства - hdc наиболее подходящий формат пикселей и выбирает его
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;
}


Автор: Николай Свирневский

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *