Установка освещения
Установка освещения
Параметры освещения будут изменяться с помощью регуляторов, которые мы разместим на новой странице блока Property Pages. Каждую новую страницу этого блока принято реализовывать в виде отдельного интерфейса, раскрываемого специальным объектом (ко-классом) ATL. Однако уже сейчас мы можем дать тело вспомогательной функции SetLight, которая устанавливает параметры освещения, подобно тому как это делалось в уроке, где говорили о графике в рамках MFC. Параметры освещения будут храниться в массиве m_LightParam, взаимо-действовующем с диалогом, размещенным на новой странице свойств:
void COGCOpenGLView::SetLight()
{
//====== Обе поверхности изображения участвуют
//====== при вычислении цвета пикселов при
//====== учете параметров освещения
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1) ;
//====== Позиция источника освещения
//====== зависит от размеров объекта
float fPosf] =
{
(m_LightParam[0]-50)*m_fRangeX/100,
(m_LightParam[l]-50)*m_fRangeY/100,
(m_LightParam[2]-50)*m_fRangeZ/100,
l.f
};
glLightfv(GL__LIGHTO, GL_POSITION, fPos);
//====== Интенсивность окружающего освещения
float f = m_LightParam[3]/100. f ;
float fAmbient[4] = { f, f, f, O.f };
glLightfv(GL_LIGHTO, GL_AMBIENT, fAmbient);
//====== Интенсивность рассеянного света
f = m_LightParam[4]/lOO.f ;
float fDiffuse[4] = { f, f, f, O.f } ;
glLightfv(GL_LIGHTO, GL_DIFFUSE, fDiffuse);
//====== Интенсивность отраженного света
f = m_LightParam[5]/l00.f;
float fSpecular[4] = { f, f, f, 0. f } ;
glLightfv(GL_LIGHTO, GL_SPECULAR, f Specular.) ;
//====== Отражающие свойства материала
//===== для разных компонентов света
f = m_LightParam[61/100.f;
float fAmbMat[4] = { f, f, f, O.f };
glMaterialfv(GL_FRONT_AND_BACK, GL__AMBIENT, fAmbMat);
f = m_LightParam[7]/l00.f;
float fDifMat[4] = {- f, f, f, l.f } ;
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fDifMat);
f = m_LightParam[8]/lOO.f;
float fSpecMat[4] = { f, f, f, 0.f };
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, fSpecMat);
//======= Блесткость материала
float fShine = 128 * m_LightParam[9]/100.f;
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, fShine);
//======= Излучение света материалом
f = m_LightParam[10]/lOO.f;
float fEmission[4] = { f, f, f, O.f };
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, fEmission);
}
Параметры освещения
Данные о том, как должна быть освещена сцена, мы будем получать из диалоговой вкладки свойств, которую создадим позже, но сейчас можем дать коды методов обмена данными, которые являются частью интерфейса lOpenGL:
STDMETHODIMP COpenGL::GetLightParams(int* pPos)
{
//======= Проход по всем регулировкам
for (int 1=0; i<ll; i++)
//======= Заполняем транспортный массив pPos
pPos[i] = m_LightParam[i];
return S_OK;
}
STDMETHODIMP COpenGL: : SetLightParam (short lp, int nPos)
//====== Синхронизируем параметр 1р и устанавливаем
//====== его в положение nPos
m_LightParam[lp] = nPos;
//==== Перерисовываем окно с учетом изменений
FireViewChange ();
return S_OK;
}
Метод CComControl: : FireViewChange уведомляет контейнер, что объект хочет перерисовать все свое окно. Если объект в данный момент неактивен, то уведомление с помощью указателя m_spAdviseSink поступает в клиентский сток (sink), который мы рассматривали при обзоре точек соединения.
В данный момент вы можете построить DLL и посмотреть, что получилось, запустив тестовый контейнер. Однако, как это часто бывает в жизни программиста, мы не увидим ничего, кроме пустой рамки объекта. В таком состоянии можно остаться надолго, если не хватает квалификации и опыта отладки СОМ DLL-серверов. Сразу не видны даже пути поиска причины отказа. Никаких грубых промахов вроде бы не совершали. Процесс создания окна внедренного объекта происходит где-то за кадром. Опытный читатель, возможно, давно заметил неточность, которая закралась на самой начальной стадии создания заготовки ATL Control, но если опыта или знаний недостаточно, то надо все начинать заново, или рассматривать работающие примеры и скрупулезно сравнивать код. Здесь я потратил пару мучительных дней, видимо, по своей глупости, но все-таки нашел причину отказа. Она, как это тоже часто бывает, оказалась очень простой и очевидной. Мы забыли установить один флажок при создании заготовки ко-класса, который устанавливает в TRUE переменную:
CComControl::m_bWindowOnly
Наш класс GOpenGL, конечно же, унаследовал эту переменную. Она указывает СОМ, что элемент ActiveX должен создавать окно, даже если контейнер поддерживает элементы, не создающие окон. Приведем оригинальный текст: «m_bWindowOnly — Flag indicating the control should be windowed, even if the container supports win-do wless controls». Для исправления ситуации достаточно вставить в конструктор класса COpenGL такую строку:
m_bWindowOnly = TRUE;
После этого вы должны увидеть окно нашего ActiveX элемента, а в нем поверхность, вид которой показан на Рисунок 9.1.
Реализация методов интерфейса
Методы, обозначенные в интерфейсе IOреnсb, будут вызываться из клиентского приложения либо через IDispatch, либо с помощью страницы свойств, которую мы вскоре создадим. В любом случае, эти методы должны либо получить параметр настройки изображения и перерисовать его с учетом настройки, либо вернуть текущее состояние запрашиваемого параметра настройки: