Введение обработчиков сообщений
}
Отметьте, что прототип функции обработки отличается от того, который принят в MFC. Там он имеет вид af x_msg BOOL OnEraseBkgnd(CDC* pDC); и определен в классе CWnd. Наш класс COpenGL среди своих многочисленных предков имеет класс CComControl, который происходит от класса CWindowlmpl, а тот, в свою очередь, является потомком класса cwindow. Последний выполняет в ATL ту же роль, что и класс cwnd в MFC, но не несет с собой бремени наследования от CObject. Это в основном и ускоряет функционирование ATL-приложений.
Теперь введите в класс обработчик сообщения WM_CREATE и заполните его кодами, которые готовят окно и устанавливают некоторые параметры OpenGL:
LRESULT COpenGL::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/,'LPARAM /*lParam*/, BOOL& bHandled)
//======= Описатель формата окна OpenGL
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, // Глубина Z-буфера
0, // Глубина буфера Stencil
0, // Глубина буфера Auxiliary
0, // Теперь игнорируется
0, // Количество плоскостей
0, // Теперь игнорируется
0, // Цвет прозрачной маски
0 // Теперь игнорируется
};
// Добываем дежурный контекст и просим выбрать ближайший
m_hdc = GetDCO ;
int iD = ChoosePixelFormat(m_hdc, &pfd) ;
if ( !ID )
{
ATLASSERT(FALSE);
return -1;
}
//====== Пытаемся установить этот формат
if ( ISetPixelFormat (m_hdc, iD, &pfd))
{
ATLASSERT(FALSE);
return -1;
}
//====== Пытаемся создать контекст передачи OpenGL
if ( !(m_hRC = wglCreateContext (m_hdc)))
{
ATLASSERT(FALSE);
return -1;
}
//====== Пытаемся выбрать его в качестве текущего
if ( !wglMakeCurrent (m_hdc, m_hRC))
{
ATLASSERT(FALSE);
return -1;
}
//====== Теперь можно посылать команды OpenGL
glEnable (GL_LIGHTING) ;
// Будет освещение
glEnable (GL_LIGHTO) ;
// Только 1 источник
glEnable (GL_DEPTH_TEST) ;
// Учитывать глубину (ось Z)
//====== Учитывать цвет материала поверхности
glEnable (GL_COLOR_MATERIAL) ;
//====== Устанавливаем цвет фона
SetBkColor () ;
bHandled = TRUE;
return 0;
}
Класс copenGL должен реагировать на сообщение WM_SIZE и корректировать видимый объем сцены. Мы будем использовать режим просмотра с учетом перспективы. Его определяет функция
gluPerspective. Введите в класс copenGL обработку WM_SIZE и вставьте в нее следующие
коды:
LRESULT COpenGL: :OnSize(UINT /*uMsg*/, WPARAM /*wParam*/,
LPARAM IParam, BOOL& bHandled)
{
// Распаковываем длинный параметр и узнаем размеры окна
UINT сх = LOWORD ( IParam) , су = HIWORD (IParam) ;
//====== Вычисляем максимальные диспропорции окна
double dAspect = cx<=cy ? double (су) /сх
: double (сх) /су;
//==== Задаем тип текущей матрицы (матрица проекции)
glMatrixMode (GL_PROJECTION) ;
//====== Приравниваем ее к единичной диагональной
glLoadldentity () ;
//== Параметры перспективы (45 градусов - угол обзора)
gluPerspective (45., dAspect, 1., 10000.);
glViewport (0, 0, сх, су); DrawScene {) ;
bHandled = TRUE;
return 0;
}
Функция glViewport, как вы помните, задает прямоугольник просмотра. При закрытии окна внедренного объекта необходимо освободить память, занимаемую контекстом передачи, и отказаться от услуг таймера, с помощью которого мы будем производить анимацию вращения изображения. Введите в класс обработчик сообщения WM_DESTROY и измените ее стартовый код, как показано ниже:
LRESULT COpenGL: :OnDestroy (UINT /*uMsg*/, WPARAM
/*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
KillTimer(l);
if (m_hRC)
{
wglDeleteContext(m_hRC); m_hRC = 0;
}
bHandled = TRUE;
return 0;
}
Инициализация переменных
В конструктор класса вставьте код установки начальных значений переменных, с помощью которых пользователь сможет управлять сценой Open GL:
COpenGL: : COpenGL()
{
//====== Контекст передачи пока отсутствует
m_hRC = 0;
//====== Начальный разворот изображения
m_AngleX = 35. f;
m_AngleY = 20. f;
//====== Угол зрения для матрицы проекции
m_AngleView = 45. f;
//====== Начальный цвет фона
m_clrFillColor = RGB (255,245,255);
//====== Начальный режим заполнения
//====== внутренних точек полигона
m_FillMode = GL_FILL;
//====== Подготовка графика по умолчанию
DefaultGraphic ();
//=== Начальное смещение относительно центра сцены
//=== Сдвиг назад на полуторный размер объекта
m_zTrans = -1.5f*m_fRangeX;
m_xTrans = m_yTrans = 0.f ;
// Начальные значения квантов смещения (для анимации)
m_dx = m_dy = 0.f;
//=== Мыть не захвачена
m_bCaptured = false;
//=== Правая кнопка не была нажата
m_bRightButton = false;
//=== Рисуем четырехугольниками m_bQuad = true;
//====== Начальный значения параметров освещения
m_LightParam[OJ = 50; // X position
m_LightParam[l] = 80; // Y position
m_LightParam[2] = 100; // Z position
m_LightParam[3] = 15; // Ambient light
m_LightPararn[4] = 70; // Diffuse light
m_LightParam[5] = 100; // Specular light
m_LightParam[6] = 100; // Ambient material
m_LightParam[7] = 100; // Diffuse material
m_LightParam[8] = 40; // Specular material
m_LightParam[9] = 70; // Shininess material
m_LightParam[10] = 0; // Emission material
}
Функция перерисовки
Перерисовка изображения OpenGL состоит в том, что обнуляется буфер цвета и буфер глубины — буфер третьей координаты. Затем в матрицу моделирования (GL_MODELVIEW), которая уже выбрана в качестве текущей, загружается единичная матрица (glLoadldentity). После этого происходит установка освещения, с тем чтобы на него не действовали преобразования сдвига и вращения. Лишь после этого матрица моделирования домножается на матрицу трансляции и матрицу вращений. Чтобы рассмотреть изображение, достаточно иметь возможность вращать его вокруг двух осей (X и Y). Поэтому мы домножаем матрицу моделирования на две матрицы вращений (glRotatef). Сначала вращаем вокруг оси X, затем вокруг оси Y:
HRESULT COpenGL: :OnDraw (ATL_DRAWINFO& di)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadldentity{);
//====== Установка параметров освещения
SetLight ();
//====== Формирование матрицы моделирования
glTranslatef(m_xTrans,m_yTrans,m_zTrans);
glRotatef (m_AngleX, l.0f, 0.0f, 0.0f );
glRotatef (m_AngleY, 0.0f, l.0f, 0.0f );
//====== Вызов рисующих команд из списка
glCallList(1);
//====== Переключение буферов
SwapBuffers(m_hdc);
return S_OK;
}