Учебник по Visual C++ .Net


Введение обработчиков сообщений


}

Отметьте, что прототип функции обработки отличается от того, который принят в MFC. Там он имеет вид af x_msg BOOL OnEraseBkgnd(CDC* pDC); и определен в классе CWnd. Наш класс COpenGL среди своих многочисленных предков имеет класс CComControl, который происходит от класса CWindowlmpl, а тот, в свою очередь, является потомком класса cwindow. Последний выполняет в ATL ту же роль, что и класс cwnd в MFC, но не несет с собой бремени наследования от CObject. Это в основном и ускоряет функционирование ATL-приложений.

В заготовке тела функций обработки все параметры закомментированы. Это сделано для того, чтобы упростить работу компилятору, так как далеко не все параметры задействованы постоянно. Если параметр необходимее его нужно сделать видимым для компилятора, убрав знаки комментария. Сделайте это для параметра bHandled.

Теперь введите в класс обработчик сообщения 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;

}

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