Использование OpenGL

2 АРХИТЕКТУРА OPENGL

2.2 Особенности реализации OpenGL в ОС Windows

Как уже было отмечено ранее, для того чтобы оконная система смогла работать с OpenGL, необходимо произвести её инициализацию и сконфигурировать буфер фрейма. Обе эти операции выполняются вне OpenGL.

Кроме того, т. к. для системы Windows окно OpenGL ничем не отличается от "обычного" окна, то, например, для работы в полноэкранном режиме с разрешением экрана, отличающимся от установленного, необходимо воспользоваться соответствующими средствами GDI для изменения параметров всей системы и лишь потом переходить к инициализации окна. Эти шаги не так важны для полностью программных реализаций OpenGL (например, Microsoft OpenGL), однако являются критическими при использовании аппаратных ускорителей OpenGL. Это связано с тем, что аппаратная акселерация возможна только при определённых разрешениях экрана и глубине цвета в буфере кадра, если же требования аппаратного акселератора не выполняются, то библиотека автоматически перейдёт в стандартный режим программной эмуляции.

Во многих книгах по программированию 3D графики с помощью OpenGL авторы подробно рассматривают стандартную последовательность действий по инициализации стиля окна для OpenGL и заданию формата пикселей и, как правило, оставляют без внимания вопросы, связанные с выбором акселерированных режимов и установкой полноэкранного режима работы приложения.

2.2.1 Установка стиля окна OpenGL

OpenGL требует для своего окна наличия установленных стилей WS_CLIPCHILDREN и WS_CLIPSIBLINGS.

Для программы, использующей MFC это выглядит так:

BOOL CMyGLView::PreCreateWindow(CREATESTRUCT& cs) {
	cs.style|=(WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
	return Cview::PreCreateWindow(cs);
}

2.2.2 Установка формата пикселей

Прежде всего необходимо заполнить структуру PIXELFORMATDESCRIPTOR желаемыми параметрами контекста и с помощью функции ChoosePixelFormat послать системе запрос - поддерживает ли она его. Вот стандартная последовательность действий:

static PIXELFORMATDESCRIPTOR pfd = 	{
    sizeof(PIXELFORMATDESCRIPTOR),  // размер структуры
    1,                              // номер версии
    PFD_DRAW_TO_WINDOW   |          // поддержка вывода в окно
      PFD_SUPPORT_OPENGL |          // поддержка OpenGL
      PFD_DOUBLEBUFFER,             // двойная буферизация
    PFD_TYPE_RGBA,                  // цвета в режиме RGBA
    32,                             // 32 разряда на цвет
    0, 0, 0, 0, 0, 0,               // биты цвета игнорируются
    0,                              // не используется альфа параметр
    0,                              // смещение цветов игнорируются
    0,                              // буфер аккумулятора не используется
    0, 0, 0, 0,                     // биты аккумулятора игнорируются
    32,                             // 32-разрядный буфер глубины
    0,                              // буфер трафарета не используется
    0,                              // вспомогательный буфер не используется
    PFD_MAIN_PLANE,                 // основной слой
    0,                              // зарезервирован
    0, 0, 0                         // маски слоя игнорируются
};
    int pixelFormat;
    // Поддерживает ли система необходимый формат пикселей?
    if((pixelFormat = ::ChoosePixelFormat(hdc, &pfd)) == 0) {
	MessageBox("С заданным форматом пикселей работать нельзя");
	return FALSE;
    }

Вызов функции ChoosePixelFormat гарантирует, что OpenGL будет работать с форматом пикселей, поддерживаемых устройством, на которое будет осуществляться вывод изображения. После того, как найден формат пикселей, наиболее полно совпадающий с требуемым, нужно установить его в контексте устройства с помощью SetPixelFormat, например так:

if (::SetPixelFormat(hdc, pixelFormat, &pfd) == FALSE) {
	MessageBox("SetPixelFormat failed");
	return FALSE;
} else return TRUE;

Ещё две функции позволяют получить информацию о параметрах формата пикселей(функция DescribePixelFormat) и о текущем индексе формата пикселей (GetPixelFormat).

2.2.3 Установка текущего контекста воспроизведения

Функция wglCreateContext позволяет создавать новый контекст воспроизведения для устройства, дескриптор которого передаётся в качестве параметра.

Функция wglMakeCurrent устанавливает единственный текущий контекст воспроизведения потока. Как правило, обе эти функции вызываются в обработчике сообщения WM_CREATE окна OpenGL:

BOOL CMyGLView::OnCreate() {
   if (CView::OnCreate(lpCreateStruct) == -1)
   return -1;
   m_pDC = new CClientDC(this); // Формируем контекст рабочей области
   ASSERT(m_pDC != NULL);
   HDC hdc = m_pDC->GetSafeHdc(); // Получаем дескриптор контекста устройства
   ...
// Создаем контекст воспроизведения
   if((hrc = ::wglCreateContext(hdc)) == NULL) return -1;
// Делаем контекст воспроизведения текущим
   if(::wglMakeCurrent(hdc, hrc) == FALSE) return -1;
   return 0;
}

2.2.4 Завершение работы с OpenGL

Завершение работы состоит из двух этапов:

Вот пример типичного обработчика сообщения WM_DESTROY для окна OpenGL:

void CMyGLView::OnDestroy()  {
// Получаем текущий контекст воспроизведения
   HGLRC hrc = ::wglGetCurrentContext();
   ::wglMakeCurrent(NULL,  NULL);  // Перед удалением он не должен быть текущим
   if (hrc)::wglDeleteContext(hrc);// Удаляем контекст воспроизведения
   if (m_pDC) delete m_pDC;        // Удаляем контекст рабочей области
   CView::OnDestroy();
}

2.2.5 Инициализация полноэкранного приложения

При программировании приложений, не нуждающихся в стандартном оконном интерфейсе, например, игр, часто возникает необходимость перехода в полноэкранный режим работы. При использовании API DirectX эта задача решается достаточно просто, однако для работы с OpenGL в полноэкранном режиме необходимо пользоваться только стандартными средствами Windows (без DirectX).

Кратко последовательность действий при инициализации может выглядеть следующим образом (предполагается, что в программе задано желаемое разрешение и глубина цвета):

При закрытии приложения кроме нормального завершения работы OpenGL необходимо произвести работу по восстановлению предыдущего видеорежима:

Нужно учесть, что при переходе из HiColor режимов в TruColor или наоборот возможны случаи, когда по непонятным причинам библиотека Microsoft OpenGL некорректно распознаёт текущий режим и, как следствие, не может правильно инициализировать формат пикселей или создать контекст воспроизведения (завершаются неудачей вызовы функций ChoosePixelFormat, SetPixelFormat, wglCreateContext). Этот эффект не проявляется при работе с другими версиями библиотеки, например, 3dfx OpenGL или при работе под ОС Windows NT.