Подготовка окна
Подготовка окна
Вы помните, что подготовку контекста передачи 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, сх, су);
}