Модель программирования Component Object Model. Разработка COM-сервера, страница 31

}

Реакция на изменение экспонируемого свойства FillColor должна теперь переехать в CPP-файл. Вот ее тело.

void COpenGL::OnFillColorChanged()

{

if (m_clrFillColor & 0x80000000)

m_clrFillColor = GetSysColor (m_clrFillColor & 0x1f);

SetBkColor();

}

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

Вы помните, что изображение OpenGL может быть создано в окне, которое прошло специальную процедуру подготовки. Цель — создать и сделать активным контекст передачи OpenGL (HGRC). Вы также помните, что подготовку контекста надо рассматрвать как некий обязательный ритуал, в котором порядок действий определен. Повторим его:

¨  Установка стиля окна;

¨  Обработка сообщения WM_ERASEBACKGROUND и отказ от стирания фона;

¨  Установка pixel-формата;

¨  Создание контекста устройства (HDC) и контекста передачи (HGLRC);

¨  Специфическая обработка сообщения WM_SIZE;

¨  Обработка сообщения WM_PAINT;

¨  Освобождение контекстов при закрытии окна.

Введите коды в уже существующую заготовку функции OnCreate. Здесь производится основная часть действий для подготовки окна OpenGL:

PIXELFORMATDESCRIPTOR pfd = // Описатель формата

{

sizeof(PIXELFORMATDESCRIPTOR),// Размер структуры

1,                 // Номер версии

PFD_DRAW_TO_WINDOW | // Поддержка GDI

PFD_SUPPORT_OPENGL | // Поддержка OpenGL

PFD_DOUBLEBUFFER,    // Двойная буферизация

PFD_TYPE_RGBA,       // Формат RGBA, не палитра

24,                // Глубина цвета

0, 0, 0, 0, 0, 0,    // Биты Color отсутствуют

0,                 // Нет буфера прозрачности

0,                 // Бит сдвига

0,  0, 0, 0, 0,      // Нет буфера Accumulation

32,                // 32-битный Z-буфер

0,                 // Нет буфера Stencil

0,                 // Нет буфера Auxiliary

PFD_MAIN_PLANE,      // Основной слой рисования

0,                 // Зарезервировано

0, 0, 0            // Маски слоев отсутствуют

};

m_hdc = GetDC();  // Добываем дежурный контекст и просим выбрать ближайший формат

int iD = ChoosePixelFormat(m_hdc, &pfd);

if (!iD)

{

ATLTRACE("\nChoosePixelFormat error");

return -1;

}

if ( !SetPixelFormat (m_hdc, iD, &pfd) ) // Пытаемся установить этот формат

{

ATLTRACE("\nSetPixelFormat error");

return -1;

}

if ( !(m_hRC = wglCreateContext (m_hdc))) // Пытаемся создать контекст передачи OpenGL

{

ATLTRACE("\nwglCreateContext error");

return -1;

}

if ( !wglMakeCurrent (m_hdc, m_hRC)) // Пытаемся выбрать его в качестве текущего

{

ATLTRACE("\nwglMakeCurrent error");

return -1;

}

//===== Теперь можно посылать команды OpenGL

glEnable(GL_LIGHTING);    // Будет освещение

glEnable(GL_LIGHT0);      // Только 1 источник

glEnable(GL_DEPTH_TEST); // Учитывать глубину (ось Z)

glEnable(GL_COLOR_MATERIAL);// Учитывать цвет материала поверхности

SetBkColor();    // Устанавливаем цвет фона

DrawScene(); // Создаем изображение и запоминаем в списке

bHandled = TRUE;

return 0;

Реакция на WM_ERASEBKGND, как было отмечено, должна установить в TRUE выходной параметр bHandled, что трактуется системой как: <Сообщение обработано и может быть убрано из очереди>. Сделайте это. Реакция на WM_SIZE должна учитывать изменение размеров окна и корректировать прямоугольник просмотра и матрицу проецирования. Введите внутрь OnSize такой код:

UINT cx = LOWORD(lParam), cy = HIWORD(lParam);

glViewport(0, 0, cx, cy); // Установка прямоугольника просмотра

double dAspect = cx<=cy ? double(cy)/cx : double(cx)/cy; // Вычисление диспропорции окна

glMatrixMode (GL_PROJECTION);

glLoadIdentity();

gluPerspective (m_AngleView, dAspect, 0.1, 100.); // Режим перспективной проекции

bHandled = TRUE;

return 0;

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

KillTimer(1); // Останавливаем таймер анимации

wglMakeCurrent(0, 0); // Отсоединяем контекст от потока