Подготовка окна



Подготовка окна

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



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