Вы заметили, что до сих пор обходились без
каких-либо ресурсов. Мы не учитываем
традиционный диалог About, планку меню главного
окна, панель инструментов, две таблицы (строк и
ускорителей) и два значка, которые
присутствовали в каркасе приложения изначально.
Дальнейшее развитие потребует ввести новые
ресурсы. Главным из них будет диалог, который мы
запустим в немодальном режиме и который позволит
подробно исследовать влияние параметров
освещения на качество изображения. Начинать, как
обычно, следует с команд меню. Скорректируйте
меню главного окна так, чтобы в нем появились
новые команды:
-
Edit > Properties (ID_EDIT_PROPERTIES);
-
Edit > Background (ID_EDIT_BACKGROUND);
-
View > Fill (ID_VIEW_FILL);
-
View > Quad (ID_VIEW_QUAD).
Одновременно удалите не используемые нами
команды:
File > New, File > Open, File > Save, File >
Save as, File > Recent File, Edit > Undo, Edit >
Cut, Edit > Copy
и
Edit > Paste.
Примечание
Вы, конечно, знаете, что идентификаторы команд
можно не задавать. Они генерируются
автоматически при перемещении фокуса от вновь
созданной команды к любой другой.
После этого в классе cocview создайте
обработчики всех новых команд с именами по
умолчанию (их предлагает Studio.Net). При
создании реакций на эти команды меню (COGView >
Properties > Events) предварительно раскройте
все необходимые элементы в дереве Properties
t Commands. Одновременно с функциями
обработки типа COMMAND создайте (для всех
команд, кроме Edit > Background) функции
обновления пользовательского интерфейса, то есть
функции обработки типа UPDATE_ COMMANDJJI. Они,
как вы помните, следят за состоянием команд меню
и соответствующих им кнопок панели управления,
обновляя интерфейс пользователя. Команды
становятся доступными или, наоборот, в
зависимости признака, управляемого програмистом.
В обработчике OnEditBackground мы вызовем
стандартный диалог по выбору цвета, сразу открыв
обе его страницы (см. флаг CC_FULLOPEN). С
помощью этого диалога пользователь сможет
изменить цвет фона:
void
COGView::OnEditBackground(void)
{
//====== Создаем объект диалогового класса
CColorDialog dig(m_BkClr);
//====== Устанавливаем бит стиля
dig.m_cc.Flags |=
CC_FULLOPEN;
//====== Запускаем диалог и выбираем результат
if
(cilg.DoModal ()==IDOK)
{
m_BkClr =
dig.m_cc.rgbResuit;
//======
Изменяем цвет фона
SetBkColor();
Invalidate(FALSE);
}
}
Проверьте результат, запустив приложение и
вызвав диалог. При желании создайте глобальный
массив с 16 любимыми цветами и присвойте его
адрес переменной lpCustColors, которая входит в
состав полей структуры m_сс, являющейся членом
класса CColorDialog. В этом случае пользователь
сможет подобрать и запомнить некоторые цвета.
В обработчик OnViewQuad введите коды,
инвертирующие булевский признак m_bQuad, который
мы используем как флаг необходимости рисования
отдельными четырехугольниками (GL_QUADS), и
заново создают изображение. Если признак
инвертирован, то мы рисуем полосами (GL_QUAD_STRIP):
void
COGView::OnViewQuad(void)
{
// Инвертируем признак стиля задания
четырехугольников
m_bQuad = ! m_bQuad;
//====== Заново создаем изображение
DrawScene ();
Invalidate(FALSE); UpdateWindow();
}
В обработчик команды обновления интерфейса
введите коды, которые обеспечивают появление
маркера выбора рядом с командой меню (или
залипания кнопки панели управления):
void
COGView::OnUpdateViewQuad(CCmdUI* pCmdUI)
{
//====== Вставляем или убираем маркер (пометку)
pCmdUI->SetCheck(m_bQuad==true);
}
Проверьте результат и попробуйте объяснить
зубчатые края поверхности (рис. 46). Не знаю,
правильно ли я поступаю, когда по ходу изложения
вставляю задачи подобного рода. Но мной движет
желание немного приоткрыть дверь в кухню
разработчика и показать, что все не так уж
просто. Искать ошибки в алгоритме, особенно
чужом, является очень кропотливым занятием.
Однако совершенно необходимо приобрести этот
навык, так как без него невозможна работа в
команде, а также восприятие новых технологий,
раскрываемых в основном посредством анализа
содержательных (чужих) примеров (Samples). Чтобы
обнаружить ошибку подобного рода, надо тщательно
проанализировать код, в котором создается
изображение (ветвь GL_QUAD_STRIP), и понять, что
неправильно выбран индекс вершины. Замените
строку givertex3f (xn, yn, zn); HaglVertexSf (xi,
yi, zi); и вновь проверьте работу приложения.
Зубчатость края должна исчезнуть, но в
алгоритме, тем не менее, осталась еще небольшая,
слабо заметная неточность. Ее обнаружение и
исправление я оставляю вам, дорогой читатель.
Обработку следующей команды меню мы проведем в
том же стиле, за исключением того, что
переменная m_FillMode не является булевской,
хоть и принимает лишь два значения (GL_FILL и
GL_LINE). Из материала предыдущей главы помните,
возможен еще одни режим изображения полигонов —
GL_POINT. Логику его реализации при желании вы
введете самостоятельно, а сейчас введите коды
двух функции обработки команды меню:
void
COGView::OnViewFill(void)
{
//=== Переключаем режим заполнения
четырехугольника
m_FillMode =
m_FillMode==GL_FILL ?
GL_LINE : GL__FILL;
//====== Заново создаем изображение
DrawScene();
Invalidate(FALSE);
UpdateWindow() ;
}
void
COGView::OnUpdateViewFill(CCmdUI *pCmdUI)
{
//======
Вставляем или убираем маркер выбора
pCmdUI->SetCheck(m_FillMode==GL_FILL)
;
}
Запустите и проверьте работу команд меню.
Отметьте, что формула учета освещения работает и
в случае каркасного изображения примитивов (рис.
47).
Для обмена с диалогом по управлению освещением
нам понадобятся две вспомогательные функции
GetLightParams и SetLightParam. Назначение
первой из которых заполнить массив переменных,
отражающих текущее состояние параметров
освещения сцены OpenGL. Затем этот массив мы
передадим в метод диалогового класса для
синхронизации движков (sliders) управления.
Вторая функция позволяет изменить отдельный
параметр и привести его в соответствие с
положением движка. Так как мы насчитали 11
параметров, которыми хотим управлять, то
придется ввести в окно диалога 11 регуляторов,
которым соответствует массив m_LightPaxam из 11
элементов. Массив уже помещен в класс COGView,
нам осталось лишь задействовать его:
void
COGView: :GetLightParams (int *pPos)
{
//====== Проход по всем регулировкам
for
(int i=0; i<ll; i++)
//====== Заполняем
транспортный массив pPos
pPos[i] =
m_LightParam[i] ;
void
COGView: :SetLightParam (short Ip, int nPos)
{ //====== Синхронизируем параметр lp и
//======
устанавливаем его в положение nPos
m_LightParam[lp] =
nPos;
//=== Перерисовываем представление с учетом
изменений
Invalidate (FALSE)
;
} |