Вы помните, что подготовку контекста передачи
OpenGL надо рассматривать как некий обязательный
ритуал, в котором порядок действий определен. В
этой процедуре выделяют следующие шаги:
-
установка стиля окна;
-
обработка сообщения WM_ERASEBACKGROUND и
отказ от стирания фона;
-
установка pixel-формата;
-
создание контекста устройства (HDC) и
контекста передачи (HGLRC);
-
специфическая обработка сообщения WM_SIZE;
-
обработка сообщения WM_PAINT;
-
освобождение контекстов при закрытии окна.
Как было отмечено ранее, окнам, которые в своей
клиентской области используют контекст передачи
OpenGL, при создании следует задать биты стиля
WS_CLIPCHILDREN и ws_CLiPSiBLiNGS. Сделайте это
внутри существующего тела функции
PreCreateWindow класса cocview, добавив нужные
биты стиля к тем, что устанавливаются в
заготовке:
BOOL
COGView::PreCreateWindow(CREATESTRUCT& cs)
{
//======
Добавляем биты стиля,
нужные
OpenGL
cs.style |=
WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
return
CView::PreCreateWindow(cs);
}
Вы помните, что окно OpenGL не должно позволять
Windows стирать свой фон, так как данная
операция сильно тормозит работу конвейера. В
связи с этим введите в функцию обработки
WM_ERASEBKGND код, сообщающий системе, что
сообщение уже обработано:
BOOL
COGView::OnEraseBkgnd(CDC* pDC)
{
return
TRUE;
}
Окно OpenGL имеет свой собственный формат
пикселов. Нам следует выбрать и установить
подходящий формат экранной поверхности в
контексте устройства HDC, а затем создать
контекст передачи изображения (HGLRC). Для
описания формата пикселов экранной поверхности
используется структура PIXELFORMATDESCRIPTOR.
Выбор формата зависит от возможностей карты и
намерений разработчика. Мы зададим в полях этой
структуры такие настройки:
-
глубину цвета — 24;
-
тип буферизации — двойной;
-
схему образования цвета RGBA;
-
количество бит для буфера глубины — 32;
-
поддержку регулировки прозрачностью и другие
специфические настройки выключим.
В функцию OnCreate введите код подготовки окна
OpenGL. Работа здесь ведется со структурой
PIXELFORMATDESCRIPTOR. Кроме того, в ней
создается контекст m_hRC и устанавливается в
качестве текущего:
int
COGView::OnCreate(LPCREATESTROCT IpCreateStruct)
{
if
(CView::OnCreate(IpCreateStruct) == -1)
return -1;
PIXELFORMATDESCRIPTOR pfd = //
Описатель формата
{
sizeof(PIXELFORMATDESCRIPTOR), //
Размер структуры
1, //
Номер версии
PFD_DRAW_TO_WINDOW
| //
Поддержка
GDI
PFD_SUPPORT_OPENGL
| //
Поддержка
OpenGL
PFD_DOUBLEBUFFER,
//
Двойная буферизация
PFD_TYPE_RGBA, //
Формат RGBA, не палитра
24, // Количество плоскостей
//в каждом буфере цвета
24, 0, // Для
компонента Red
24, 0, // Для
компонента Green
24, 0, // Для
компонента Blue
24, 0, // Для
компонента Alpha
0, // Количество плоскостей
// буфера
Accumulation
0, // То же для
компонента Red
0, // для
компонента Green
0, // для
компонента Blue
0, // для
компонента Alpha
32, // Глубина 2-буфера
0, // Глубина
буфера Stencil
0, // Глубина
буфера Auxiliary
0, // Теперь игнорируется
0, // Количество плоскостей
0, // Теперь игнорируется
0, // Цвет прозрачной маски
0 // Теперь игнорируется };
//====== Добываем дежурный контекст
m_hdc = ::GetDC(GetSafeHwnd());
//====== Просим выбрать ближайший совместимый
формат
int
iD = ChoosePixelForraat(m_hdc, spfd);
if
( !iD )
{
MessageBoxC'ChoosePixelFormat: :Error") ;
return -1;
}
//======
Пытаемся установить этот формат
if
( ISetPixelFormat (m_hdc, iD, Spfd) )
{
MessageBox("SetPixelFormat::Error");
return
-1;
}
//======
Пытаемся создать контекст передачи
OpenGL
if
( !(m_hRC = wglCreateContext (m_hdc)))
{
MessageBox("wglCreateContext::Error");
return
-1;
}
//======
Пытаемся выбрать его в качестве текущего
if
( IwglMakeCurrent (m_hdc, m_hRC))
{
MessageBox("wglMakeCurrent::Error");
return
-1;
//======
Теперь можно посылать команды
OpenGL
glEnable(GL_LIGHTING);
// Будет освещение
//====== Будет только один источник света
glEnable(GL_LIGHTO);
//====== Необходимо учитывать глубину (ось Z)
glEnable(GL_DEPTH_TEST);
//====== Необходимо учитывать цвет материала
поверхности
glEnable(GL_COLOR_MATERIAL);
//======
Устанавливаем цвет фона
.
SetBkColor () ;
//====== Создаем изображение и запоминаем в
списке
DrawScene () ;
return
0;
}
Контекст передачи (rendering context) создается
функцией wglCreateContext с учетом выбранного
формата пикселов. Так осуществляется связь
OpenGL с Windows. Создание контекста требует,
чтобы обычный контекст существовал и был явно
указан в параметре wglCreateContext. HGLRC
использует тот же формат пикселов, что и НОС. Мы
должны объявить контекст передачи в качестве
текущего (current) и лишь после этого можем
делать вызовы команд OpenGL, которые производят
включение некоторых тумблеров в машине состояний
OpenGL. Вызов функции DrawScene, создающей и
запоминающей изображение, завершает обработку
сообщения. Таким образом, сцена рассчитывается
до того, как приходит сообщение о перерисовке
WM_PAINT. Удалять контекст передачи надо после
отсоединения его от потока. Это делается в
момент, когда закрывается окно представления.
Введите в тело заготовки OnDestroy следующие
коды:
void
COGView::OnDestroy(void)
{
//====== Останавливаем таймер анимации
KillTimer(1);
//====== Отсоединяем контекст от потока
wglMakeCurrent(0, 0); //======
Удаляем контекст
if
(m_hRC)
{
wglDeleteContext(m_hRC);
m_hRC = 0;
}
CView::OnDestroy()
;
}
Так же как и в консольном проекте OpenGL,
обработчик сообщения WM_SIZE должен заниматься
установкой прямоугольника просмотра (giviewport)
и мы, так же как и раньше, зададим его равным
всей клиентской области окна. -Напомним, что
конвейер OpenGL использует эту установку для
того, чтобы поместить изображение в центр окна и
растянуть или сжать его пропорционально размерам
окна. Кроме того, в обработке onSize с помощью
матрицы проецирования (GL_PROJECTION) задается
тип проекции трехмерного изображения на плоское
окно. Мы выбираем центральный или перспективный
тип проецирования и задаем при этом угол зрения
равным m_AngleView. В конструкторе ему было
присвоено значение в 45 градусов:
void
COGView::OnSize(UINT nType, int ex, int cy)
{
//======
Вызов родительской версии
CView::OnSize(nType,
ex, cy) ;
//======
Вычисление диспропорций окна
double
dAspect = cx<=cy ? double(cy)/ex : double(ex)/cy;
glMatrixMode (GL_PROJECTION)
;
glLoadldentity() ;
//======
Установка режима перспективной проекции
gluPerspective (m_AngleView,
dAspect, 0.01, 10000.);
//====== Установка прямоугольника просмотра
glViewport(0, 0, сх,
су);
} |