ВВЕДЕНИЕ

Бурный рост спроса на программные продукты во всем мире, связанный, в первую очередь, с развитием и распространением Интернета и систем электронной торговли и бизнеса, а также с внедрением новых поколений вычислительной техники и передовых достижений компьютерной графики, приводит к росту спроса на программные продукты, которые с максимальной функциональностью использует средства компьютерной графики. Говоря о машинной графике, следует отметить, что в условиях рынка (как в Украине, так и в развитых странах) большое внимание уделяется научной визуализации данных в целях наглядного представления научных и коммерческих результатов. Например, эффективно иллюстрированного материала оказывается достаточно, чтобы наглядно представить экономическое и финансовое состояние объекта исследования.

Целью данного курсового проекта является изучение структуры параметризированных 3D объектов и реализовать их с помощью OpenGL. В настоящее время графическая система OpenGL поддерживается различными языками программирования, в данном программном продукте будет использована стандартная библиотека объектно-ориентированного языка C++.

В программе реализована параллельное аксонометрическое проецирование (изометрия), изометрическая проекция получается комбинацией поворотов, за которой следует параллельное проецирование. Для реализации сложного объекта — журнального столика, были использованы различные математические методы. Для проведения аффинных преобразований в пространстве над фигурами использовались матрицы размерностью 4*4. Для построение простых объектов (пирамиды, додекаэдр, октаэдр, икосаэдр) были применены методы: разбиения на треугольники, методы медиан и параллелей. Для того, чтобы закрасить фигуры методом Гуро, произвели связывание вершин с нормалями, которые получаются в результате усреднений нормалей многоугольников, пересекающихся в этой вершине. Алгоритм удаления скрытых граней, реализованный в данной курсовой работе называется алгоритмом Z-буфера или буфера глубины, где для каждого пикселя находится грань, ближайшая к нему вдоль направления проектирования.

Данная программа является реализацией основных операций, необходимых для работы с объемными изображениями. Всё это очень важно для познания методов представления 3D-графики и качественного и эффективного использования её в графическом и геометрическом моделировании в информационных системах.

ПОСТАНОВКА ЗАДАЧИ

Целью данного курсового проекта является изучение структуры параметризированных 3D объектов и реализовать их с помощью OpenGL. В настоящее время графическая система OpenGL поддерживается различными языками программирования, в данном программном продукте будет использована стандартная библиотека объектно-ориентированного языка C++. Интерактивная система трехмерного геометрического моделирования должна представлять объекты в параллельном и перспективном видах проецирования, позволять производить элементарные преобразования над объектами в сцене (повороты, перемещение, вращение) и движение по траектории, заданной набором точек.

Систему трехмерного графического моделирования должна обладать следующей функциональностью:

— реализация заданного множества параметризированных 3D объектов:

–​ призма;

–​ цилиндр;

–​ додекаэдр;

–​ икосаэдр;

–​ пирамида с пятиугольным основанием;

–​  усеченная пирамида с пятиугольным основанием.;

–​ октаэдр;

— реализация сложного объекта – журнальный столик (см. рис. А1);

-​ разработка структуры объектов;

-​ движения по заданной траектории заданного набора параметризированных 3D объектов;

-​ реализация типичных операций управления «камерой» при визуализации и элементов управления объектом;

-​ возможность редактирования и манипулирования объектами в графической БД;

-​ разработка системы помощи.

-​ вызов всех функций реализуется в главном меню и продублирован в виде кнопок;

— загрузка и сохранения всех параметров сцены в файл данных;

— корректный выход из программы (без зависаний приложения);

— реализация планировки сцены (визуализация координатных осей);

— реализация заданного расположения и направления камеры;

— выбор типа проецирования;

— изменение размеров сцены;

-​ реализация всех аффинных преобразований для объекта с возможностью редактирования параметров: перенос, масштабирование, вращение вокруг каждой из осей, сдвиг, отражение вокруг каждой из осей.

Данная программа является реализацией основных операций, необходимых для работы с объемными изображениями. Всё это очень важно для познания методов представления 3D-графики и качественного и эффективного использования её в графическом и геометрическом моделировании в информационных системах.

1 ОБЗОР И СРАВНИТЕЛЬНЫЙ АНАЛИЗ ГРАФИЧЕСКИХ БИБЛИОТЕК И ОБОСНОВАНИЯ ИСПОЛЬЗОВАНИЯ БИБЛИОТЕКИ OpenGL

1.1​ Обзор графических библиотек и обоснования использования библиотек OpenGl

На данный момент в Windows существуют два стандарта для работы с трехмерной графикой: OpenGl, являющийся стандартом де-факто для всех рабочих станций, и Direct3D-стандарт, предложенный Windows. Библиотека DirectX, появившаяся впоследствии, была призвана облегчить жизнь программистам, решившимся перейти на новую для них систему. Сочетая в себе максимально возможную скорость и минимальную аппаратную зависи​мость, эта библиотека стала необходимым инструментом в программировании игр. Стоит обратить внимание на одну особенность — везде, где есть соответст​вующая поддержка, компоненты DirectX используют аппаратное ускорение. И только если такая возможность отсутствует, применяется программная эмуля​ция, причем все эти действия скрыты от программиста. Direct3Dявляется средством отображения трехмерных сцен. Этот компонент представляет собой надстройку над DirectDraw и имеет несколько частей: Retained Mode и Immediate Mode, каждая из которых отличается уровнем аб​страгирования от базовых концепций трехмерной графики. В данном курсовом проекте использовалась библиотека OpenGl, так как она является более продуманной и удобной, нежели постоянно изменяющийсяDirect3D. OpenGL идеально подходит для программистов, которым необходимо создать небольшую трехмерную сцену и не задумываться о деталях реализации алгоритмов трехмерной графики.

1.1.1​ Библиотека OpenGl

Для реализации программных модулей была использована интегрированная среда разработки Visual C++ 6.0 корпорации Microsoft. Для реализации графических моделей выбор был остановлен на библиотеке OpenGl, потому что она имеет ряд следующих преимуществ.

OpenGL — Open Graphics Library, открытая графическая библиотека. Термин «открытый» — означает независимый от производителей. Имеется спецификация стандарт) на OpenGL, где все четко задокументировано и описано. Библиотеку OpenGL может производить кто-угодно. Главное, чтобы библиотека удовлетворяла спецификации OpenGL и ряду тестов. Как следствие, в библиотеке нет никаких темных мест, секретов, недокументированных возможностей и т.п. Эту библиотеку написали целый ряд программистов, главным автором является Brian Paul. Библиотека Mesa распространяется в исходных текстах на языке Си и собирается почти для любой операционной системы. Стандарт OpenGL развивается с 1992 года. Он разрабатывается фирмой Silicon Graphics. С тех пор библиотека завоевала огромную популярность и была интегрирована с множеством языков и систем разработки приложений. Основное предназначение OpenGL программирование трехмерной графики. Библиотека OpenGL представляет из себя интерфейс программирования трехмерной графики. Единицей информации является вершина, из них состоят более сложные объекты. Можно создавать вершины, указывать как их соединять (линиями или многоугольниками), устанавливать координаты и параметры камеры и ламп, а библиотека OpenGL берет на себя работу создания изображения на экране. OpenGL идеально подходит для программистов, которым необходимо создать небольшую трехмерную сцену и не задумываться о деталях реализации алгоритмов трехмерной графики. Используя OpenGL возможно создавать трехмерные поверхности, осветить источниками света, передвигать объекты сцены, лампы и камеры по заданным траекториям, сделав тем самым анимацию. OpenGL непосредственно не поддерживает работу с устройствами ввода, такими как мышь или клавиатура, т.к. эта библиотека является платформенно независимой.

1.1.2 Стандартная библиотека C++

В Visual C++ используется реализация стандартной библиотеки C++, основанная на стандарте для языка C++ и библиотеки, ратифицированной Американским национальным институтом стандартов (ANSI) и Организацией Международных Стандартов (ISO).

Начиная с его разработки доктором Бьярном Страуструпом в 80-х годах, язык C++ широко использовался профессиональными программистами для разработки больших, сложных приложений в области коммуникаций, финансов, бизнеса и машинного проектирования. Заключительная стандартизация библиотеки C++ теперь облегчает возможность изучать C++ и использовать его вопреки широкому разнообразию платформ.

Стандартизация улучшает мобильность и стабильность. Использование Стандартной Библиотеки C++ позволяет формировать надежные приложения быстрее и обслуживать их с меньшими затратами и усилиями.

1.2 Программирование в Visual C++

1.2.1 Интегрированная среда разработки (IDE)

После запуска Visual C++, мы немедленно попадаем в интегрированную среду разработки, также называемую (IDE). Эта среда обеспечивает все инструментальные средства, которые нужны для проектирования, разработки, тестирования, и отладки приложений.

Среда разработки Visual C++ включает:

-​ визуальный проектировщик ресурсов (visual resource designer);

-​ менеджер классов (Class Mahager);

-​ палитру компонентов (Component palette);

-​ организатор проекта (Project Manager);

-​ редактор исходного текста (source code editor);

-​ отладчик (debugger).

Вы можете свободно двигаться от визуального представления объекта (в проектировщике ресурсов), к менеджеру классов, чтобы редактировать начальное состояние объекта; к редактору исходного текста, чтобы редактировать логику выполнения. Изменение свойств, связанных с кодом, например имени обработчика события, в менеджере классов автоматически изменяет соответствующий исходный текст. Кроме того, изменения в исходном тексте, типа переименования обработчика события в объявлении класса, немедленно отражается в менеджере классов.

1.2.2 Проектирование приложений

Visual C++ включает все инструментальные средства, необходимые для начала разработки приложения:

-​ пустое окно, для проектирования пользовательского интерфейса вашего приложения;

-​ обширная библиотека классов с объектами многократного использования;

-​ менеджер классов для просмотра и изменения свойств классов;

-​ редактор кода, который обеспечивает прямой доступ к основному тексту программы;

-​ организатор проекта для управления файлами, которые составляют один или больше проектов;

-​ много других инструментальных средств типа редактора изображений на панели инструментов и редактора меню;

Можно использовать Visual C++ для проектирования 32-разрядного Windows-приложения любого вида – от утилиты общего назначения до сложных программ доступа к данным или распределенным приложениям. Инструментальные средства базы данных Visual C++ и компоненты данных позволяют разрабатывать программы и приложения типа клиент/сервер.

1.2.3 Библиотека классов MFC

Библиотека классов MFC (Microsoft Foundation Classes) основана на модели свойства/методы/события (PME). PME модель определяет компоненты данных (свойства), функции, работающие с данными (методы), и способы взаимодействия с пользователями класса (события). MFC – иерархия классов, написанных на C++ и связанных с интегрированной средой разработки Visual C++, которая позволяет довольно быстро разрабатывать приложения. С помощью палитры компонентов и менеджера классов можно добавлять компоненты в приложение и определять их свойства, иногда не вмешиваясь в код.

2 АНАЛИЗ СТРУКТУРЫ ПРОГРАММЫ И ГРАФИЧЕСКИХ ГЕОМЕТРИЧЕСКИХ МЕТОДОВ

2.1 Анализ структуры программы

2.1.1 Структура приложения

В данном программном продукте приложение реализовано на языке Visual C++ 6.0 и построено по принципам обычного приложения с однодокументным интерфейсом. Приложение построено на основе архитектуры документ-представление, в основе которой лежат три основных понятия – фрейм, документ, представление. Документ – данные, с которыми работает приложение. Представление – класс окна, отображающий данные документа и управляющий взаимодействием пользователя с ним. Фрейм координирует работу вышеперечисленных объектов и является главным окном.

Данный программный продукт построен по принципу интерактивной работы с пользователем — приложение предоставляет панель меню и отдельную кнопочную панель, которые, по соответствующим действиям пользователя, вызывают соответствующие обработчики, функции.

Данная структура программы имеет ряд преимуществ:

-​ архитектура документ-представление позволяет быстро и эффективно изменить и отобразить данные документа;

-​ блоки диалога позволяют постоянно отображать (и изменять) полную информацию об объектах документа;

-​  панели инструментов предоставляют удобный интерфейс для настройки приложения и объектов документа;

-​ сохранение и восстановление данных документа по методу сериализации позволяет быстро и эффективно (в без избыточном формате) связать данные документа с файлом.

Таким образом, на данный момент программа построена по одному из наиболее оптимальных способов, соединив в себе наиболее сильные методы, предоставляемые библиотекой MFC.

2.1.2 Структура графических объектов и камеры

Каждый графический объект и камера реализованы отдельными классами и содержат специфические для каждого из них свойства, методы и переменные:

-​ dcGObject, класс базового объекта, хранящего список вершин и граней объекта, описание свойств материала, указатель на карту текстуры;

-​ dcGScene, класс сцены, хранит список объектов сцены и предоставляет функции для работы со сценой;

-​ dcGFactory, класс «фабрики» объектов, содержит функции создания разнообразных объектов сцены;

-​ dcGCamera, класс камеры сцены, содержит описание параметров камеры;

-​ dcGLight, класс источника света, содержит параметры светового потока;

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

2.2 Системы координат

2.2.1 Декартовая система координат

Если через точку пространства проведены три попарно перпендикулярные прямые, на каждой из них выбрано направление и выбрана единица измерения отрезков, то это значит, что задана декартовая система координат в пространстве. Прямые с выбранными на них направлениями называются осями координат, а их общая точка – началом координат. Эта система устанавливает взаимооднозначное соответствие между точками пространства и упорядоченными тройками действительных чисел. Декартовая система координат показана на рисунке 2.1.

M(x,y,z)

Рисунок 2.1 – Декартовая система координат

Различают правостороннюю и левостороннюю системы координат. Правосторонняя системой координат OXYZ – это такая система, в которой вращение относительно оси z происходит от оси x к оси y (против часовой стрелки).

Левостороняя – это система координат, в которой вращение относительно оси z происходит от оси y к оси x (по часовой стрелке).

В данном курсовом проекте использовалась правосторонняя декартовая система координат.

2.2.2 Векторная система координат

Векторная система координат устанавливает взаимооднозначное соответствие между векторами пространства и упорядоченными тройками действительных чисел. Векторная система координат показана на рисунке 2.2.

Вектор AB c координатами (x,y,z).

Рисунок 2.2 – Векторная система координат

2.2.3. Аффинная система координат

Аффинная система координат устанавливает взаимооднозначное соответствие между точками, векторами пространства и упорядоченными тройками действительных чисел. Она объединяет в себе декартовую и однородную системы координат.

2.2.4 Однородные координаты точки

В общем случае любая точка (х1, х2, х3, …,хN) в n-мерном пространстве записывается как точка (wх1, wх2, wх3, …wхN, w) в (n+1)–мерном пространстве, где w – любое ненулевое вещественное число. Эта группа из n+1чисел определяет однородные координаты исходной точки в n-мерном пространстве. Однородные координаты возникли из-за необходимости обратного преобразования из n-мерного пространства в (n+1)-мерное пространство. Точка A(5,7,4) в трехмерном пространстве, например, может быть записана в однородных координатах как А’(15,21,12,3) или как A”(500, 700,400,100) и так далее.

Пусть M – произвольная точка пространства с координатами x, y, z, тогда однородными координатами называется любая четвёрка одновременно неравных нулю чисел x1, x2, x3, x4, связанных с заданными x, y, z следующими соотношениями:

 (2.1)

2.3 Аффинные преобразования

Аффинные преобразования – это комбинация линейных преобразований, при которых параллельные линии переходят в параллельные, скрещивающиеся в скрещивающиеся, отношение отрезко7в на параллельных прямых сохраняются.

Среди аффинных преобразований различают: перенос, масштабирование, поворот, сдвиг, отражение. При проведении расчетов полезным является использование однородных координат, так как в обычных координатах используются громоздкие вычисления (сложение, умножение координат), а в однородных координатах вычисления упрощаются (матрицы перемножаются). Но основной целью введения однородных координат является их несомненное удобство в применении к геометрическим преобразованиям. Для упрощения вычислений в задачах компьютерной графики формулы преобразований представляют в виде матриц.

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

P’=P*M (2.2)

Рассмотрим аффинные преобразования, которые используются в нашей системе (оси абсцисс Ox, ординат Oy и аппликат Oz показаны на рисунке 2.2).

Матрица вращения вокруг оси абсцисс на угол :

 (2.3)

Матрица вращения вокруг оси ординат на угол :

 (2.4)

Матрица вращения вокруг оси аппликат на угол :

 (2.5)

Вращение вокруг оси аппликат на угол показано на рисунке 2.3.

Рисунок 2.3 – Вращение вокруг оси аппликат

Матрица растяжения (сжатия):

, (2.6)

где

> 1 — коэффициент растяжения вдоль оси абсцисс;

> 1 — коэффициент растяжения вдоль оси ординат;

> 1 — коэффициент растяжения вдоль оси аппликат.

Если 0<<1, 0<<1, 0<<1, то , , — коэффициенты сжатия вдоль осей абсцисс, ординат, аппликат соответственно.

Матрица переноса (вектор переноса (,,))

 (2.7)

Перенос точки Р в точку Р’ показан на рисунке 2.4.

Рисунок 2.4 — Перенос

Матрица отражения относительно плоскости XОY:

 (2.8)

Отражение относительно плоскости XОY показано на рисунке 2.5.

Рисунок 2.5 – Отражение относительно плоскости

Матрица отражения относительно плоскости XОZ:

 (2.9)

Матрица отражения относительно плоскости YОZ:

 (2.10)

2.4 Проецирование: параллельное и центральное

Изображение объектов на картинной плоскости связано с ещё одной геометрической операцией – проецированием. В компьютерной графике используется несколько различных видов проецирования. На практике наиболее употребимые – параллельное и центральное.

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

Рисунок 2.6 – Проектирующие пучки

В данном курсовом проекте реализовано изометрическое центральное проецирование, которое задается при помощи камер.

Изометрическая проекция получается комбинацией поворотов, за которой следует параллельное проецирование. При повороте на угол R относительно оси ординат, на угол Q вокруг оси абсцисс и последующего проектирования вдоль оси аппликат формируется матрица:

 (2.11)

Построение центральных проекций организуется следущим образом. Если центр проецирования лежит на оси аппликат в точке С(0,0,с) и плоскость проецирования совпадает с координатной плоскостью XY, то через произвольную точку пространства М(x,y,z) и точку C можно провести прямую и записать соответствующее параметрическое уравнение.

X’=xt, Y’=yt, Z’=c+(z-c)t

Найдя координаты точки пересечения построенной прямой с плоскостью XY. Из условия Z’=0 получается, что

, следовательно ,

В данной системе используется также ортографическое проецирование. При ортографической проекции картинная плоскость совпадает с одной из координатных плоскостей или параллельна ей. Матрица проецирования вдоль оси X на плоскость YZ имеет вид:

 (2.12)

При переходе к однородным координатам получается матрица следующего вида:

 (2.13)

Перспективная проекция получается путем перспективного преобразования и проецирования на некоторую двумерную плоскость наблюдения. Предположим, что центр проецирования лежит на оси Z в точке C(0,0,c) и плоскость проецирования совпадает с координатной плоскостью XY (рисунок 2.7), тогда соответствующая матрица будет иметь вид:

 (2.12)

Рисунок 2.7 – Перспективная проекция

2.5 Управление камерой

2.5.1. Мировая и локальная системы координат

Мировая система координат – общая система координат, заданная началом координат и тремя ортонормированными векторами.

Локальная система координат вводит свою точку отсчета и направление координатных осей. В мировой системе координат можно описать бесконечное множество локальных систем координат.

2.5.2 Камера сцены

Совокупность объектов мировой системы координат определяют сцену. К объектам сцены относятся как трехмерные объекты, так и камеры, задающие видовые операции. Камера управляет проецированием.

Каждая камера задается следующими параметрами:

— положение в мировой системе координат;
— направление камеры (точнее, точкой, в которую направлена эта камера);
— угол зрения камеры;
— угол поворота относительно главной оптической оси.

Камера показана на рисунке 2.8.

Главная оптическая ось направлена по нормали к экрану.

Каждая локальная система координат может быть представлена в мировой системе координат положением начала координат и направлением x, y (достаточно направление двух осей).

Рисунок 2.8 – Камера

2.5.3Типичные преобразования камер

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

Типичные операции управления камерой:

а) панорамирование – камера поворачивается влево-вправо. Матрица панорамирования совпадает с матрицей поворота вокруг оси OZ на некоторый угол ;

б) вертикальное панорамирование – поворот вверх-вниз. Матрица вертикального панорамирования совпадает с матрицей поворота вокруг оси OX на некоторый угол ;

в) зуммирование – изменение угла зрения или расстояния до центральной точки. При зуммировании камера остается на месте. Матрица зуммирования может быть получена путем умножения матриц двух последовательных преобразований: перспективного преобразования и проецирования на плоскость OXZ;

г) вращение камеры вокруг главной оптической оси. Матрица вращения вокруг главной оптической оси совпадает с матрицей поворота вокруг оси ординат OY’ локальной системы координат. Поворот аналогичен повороту вокруг оси ординат OZ (рисунок 2.3);

д) наезд и откат камеры – перемещение камеры вдоль главной оптической оси. В этом случае изменяется положение камеры в мировой системе координат;

е) перенос влево-вправо и вверх-вниз относительно главной оптической оси.

2.6 Алгоритм удаления невидимых граней и поверхностей

Алгоритм удаления скрытых граней, реализованный в данной курсовой работе называется алгоритмом Z-буфера или буфера глубины.

Метод z-буфера (буфера глубины) является одним из самых простых алгоритмов удаления невидимых граней и поверхностей является, где для каждого пиксела находится грань, ближайшая к нему вдоль направления проектирования.

Поставим в соответствие каждому пикселу (x,y) картинной плоскости кроме цвета c(x,y), хранящегося в видеопамяти, его расстояние до картинной плоскости вдоль направления проектирования z(x,y) (его глубину).

Массив глубин инициализируется +.

Для вывода на картинную плоскость произвольной грани она переводится в растровое представление на картинной плоскости и затем для каждого пиксела этой грани находится его глубина. В случае, если эта глубина меньше значения глубины, хранящегося в z-буфере, пиксел рисуется и его глубина заносится в z-буфер.

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

Грань рисуется последовательно строка за строкой; для нахождения значений используется линейная интерполяция.

Фактически метод z-буфера осуществляет поразрядную сортировку по x и y, а затем сортировку по z, требуя всего одного сравнения для каждого пиксела каждой грани.

Метод z-буфера работает исключительно в пространстве картинной плоскости и не требует никакой предварительной обработки данных. Порядок, в котором грани выводятся на экран, не играет никакой роли.

Средние временные затраты составляют O(n), где n-общее количество граней.

Одним из основных недостатков z-буфера (помимо большого объема требуемой под буфер памяти) является избыточность вычислений: осуществляется вывод всех граней вне зависимости от того видны они или нет. И если, например, данный пиксел накрывается десятью различными лицевыми гранями, то для каждого соответствующего пиксела каждой из этих десяти граней необходимо произвести расчет цвета. При использовании сложных моделей освещенности и текстур эти вычисления могут потребовать слишком больших временных затрат.

2.7 Методы постоянного закрашивания и Гуро

В большинстве случаев модели задаются набором плоских выпуклых граней. Поэтому при построении изображения естественно воспользоваться этой простотой модели. Существует три простейших метода рендеринга полигональных моделей, дающих приемлемые результаты, — метод плоского (постоянного) закрашивания, метод Гуро и метод Фонга.

Метод постоянного закрашивания самый простой из всех трех. Он заключается в том, что на грани берется произвольная точка и определяется ее освещенность, которая и принимается за освещенность всей грани.

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

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

Для того, чтобы закрасить фигуры методом Гуро, производится связывание вершин с нормалями, которые получаются в результате усреднений нормалей многоугольников, пересекающихся в этой вершине.

2.8 Полигональная и проволочная модели

Трехмерные объекты могут быть отображены в двух видах: в виде проволочной или полигональной модели.

Проволочная модель в пространстве представляет собой набор точек.

Полигональная модель в пространстве представляет собой сплошное непрозрачное тело.

Данный программный продукт реализован по принципу интерактивной работы с пользователем — приложение предоставляет 6 панелей кнопок и 1 панель меню, которые, по соответствующим действиям пользователя, вызывают соответствующие обработчики, функции.

3 СОЗДАНИЕ ГРАФИЧЕСКИХ И ГЕОМЕТРИЧЕСКИХ МОДЕЛЕЙ

3.1 Методы организации и обработки информации в графической БД

Объекты сцены задаются вершинами и гранями. В каждом объекте хранится информация о количестве его вершин, и граней. В данном курсовом проекте будет реализовано параметрическое задание геометрии объектов. Грани объектов задаются тремя точками. Геометрия объектов подвергается преобразованиям проецирования для отображения в окнах проекций.

3.2 Построение цилиндра

Цилиндрической поверхностью называется поверхность, образуемая движением прямой (АВ), сохраняющей одно и то же направление и пересекающую данную (MN). Линия MN называется направляющей; прямые линии, соответствующие различным положения прямой АВ, называются образующими цилиндрической поверхности. Тело, ограниченное цилиндрической поверхностью и двумя параллельными плоскостями, называется цилиндром (рис. 3.2). Радиусом(R) цилиндра называется радиус его основания. Высотой (h), называется расстояние между плоскостями его оснований. Параметром цилиндра также является количество точек разбиения окружности основания(n). N раз проводим поворот АВ поверхности на угол и находим координаты АВ1.

АВ =(R,0,0) (начальная точка нижнего основания) Pi=Pi-1Поворотz(α) AB1=(R,0,H) (начальная точка нижнего основания) Pi΄=Pi-1΄Поворотz(α)

=(2*)\N

Параметры построения:

R – радиус основания;

h – высота цилиндра;

n – количество аппроксимаций.

Алгоритм построения. Центр локальной системы координат связываем с геометрическим центром нижнего основания цилиндра. Цилиндр описывается при помощи радиальных сегментов.

Координаты вершин нижнего основания рассчитываются следующим образом:

; (3.1)

Координаты вершин верхнего основания рассчитываются следую-щим образом:

, (3.2)

Получившиеся точки соединяют прямой линией.

Цилиндр показан на рисунке 3.3.

Рисунок 3.2 – Цилиндр

3.3 Построение призмы

Призмой (рис. 3.3) называется многогранник, у которого две грани ABC и abc (основание призмы)- равные многоугольники с соответственно параллельными сторонами, а все остальные грани (AabB, BbcC и т.д.)- параллелограммы, плоскости которых параллельны одной прямой (Aa, Bb, Cc и т.д.). Параллелограммы Abba, BCcb и т.д называются боковыми гранями. Ребрами Aa, Bb и т.д. называются боковыми. Высотой призмы называется перпендикуляр H, опущенный из любой точки одного основания на плоскость другого.

Параметры построения призмы:

R – радиус основания;

h – высота призмы;

n – количество аппроксимаций;

угол наклона.

Алгоритм построения.

Призма описывается при помощи радиальных сегментов. Центр локальной системы координат связываем с геометрическим центром нижнего основания призмы. Координаты вершин нижнего основания рассчитываются следующим образом:

; (3.3)

Координаты вершин верхнего основания рассчитываются следующим образом:

, (3.4)

Координаты верхнего и нижнего основания соединяются между собой прямыми линиями.

Призма показана на рисунке 3.3.

Рисунок 3.3 — Призма

3.4 Построение пирамиды с пятиугольным основанием

Пирамидой (рис. 3.4) называется многогранник, у которого одна грань — основание пирамиды — многоугольник (ABCDE), а остальные -боковые грани — треугольники с общей вершиной S, называется вершиной пирамиды. Перпендикуляр SO, опущенный из вершины на основание, называется высотой пирамиды.

Центр локальной системы координат связываем с геометрическим центром пирамиды. Пирамида описывается при помощи радиальных сегментов.

Координаты вершин основания рассчитываются следующим образом:

; (3.5)

где R – радиус основания;

h – высота пирамиды;

n – количество аппроксимаций.

После построения основания, строим вершину , а затем соединяем вершины линиями.

Пирамида с пятиугольным основанием представлена на рисунке 3.4.

Рисунок 3.4 — Пирамида с пятиугольным основанием

3.5 Построение усеченной пирамиды с пятиугольным основанием

Если в пирамиде провести сечение abcde, параллельно основанию ABCDE, то тело ограниченное этим сечение, основанием и заключенной между ними боковой поверхности пирамиды, называется усеченной пирамидой (рис.3.5). Параллельные грани усеченной пирамиды (ABCDE и abcde) называются ее основаниями, расстояния между ними (ОО1)

Центр локальной системы координат связываем с геометрическим центром пирамиды. Пирамида описывается при помощи радиальных сегментов. Координаты вершин нижнего основания рассчитываются следующим образом:

; (3.6)

Координаты вершин верхнего основания рассчитываются следующим образом:

, (3.7)

Усеченная пирамида с пятиугольным основанием показана на рисунке 3.5.

Рисунок 3.5– Усеченная пирамида с пятиугольным основанием

3.6 Октаэдр

Центр локальной системы координат связываем с геометрическим центром октаэдра. Для построения октаэдра используется длина его радиуса R. Алгоритм построения геометрии октаэдра основан на том факте, что все его грани представляют собой правильные треугольники.

Количество вершин октаэдра равно 6.

Координаты вершин:

V1 (0;0;R);

V2 (R;0;0);

V3 (0;R;0);

V4 (-R;0;0);

V5 (0;-R;0);

V6 (0;0;-R).

Получившиеся вершины соединяем линиями.

Октаэдр показан на рисунке 3.6.

Рисунок 3.6 — Октаэдр

3.7 Икосаэдр

Центр локальной системы координат связываем с геометрическим центром икосаэдра. Параметры построения: длина стороны икосаэдра – R2. Алгоритм построения:

1) строим две окружности единичного радиуса, перпендикулярные оси z, на высоте 1/2, как показано на рисунке 3.7;

2) каждую окружность разбиваем на 5 равных сегментов, точки соединяем между собой;

3) вращаясь против часовой стрелки на угол = 2/5 выбираем точки икосаэдра

P0 (0; 0; 5/2); P0’(0; 0; — 5/2);

P1 (1/2; 0; -1/2); P1’ (-1/2; 0; -1/2);

Pi = Pi-1*Поворот(2/5); Pi’ = Pi-1’*Поворот(2/5);

Матрица поворота

4) соединяем вершины линиями.

6

7 5

8 4

9 3

1 10 2

Рисунок 3.7 – Рассечение цилиндра

3.8 Построение додекаэдра

Для построения додекаэдра (рис. 3.8) используется длина его ребра. Алгоритм построения геометрии додекаэдра основан на том факте, что все его грани представляют собой правильные пятиугольники. В каждой вершине сходится по три ребра.

Путем простейших аффинных преобразований добиваемся, чтобы объект находился в такой системе координат (локальной), как показано на рисунке 4.3.

Параметры построения: длина стороны додекаэдра – R2. Алгоритм построения:

1) строим две окружности единичного радиуса, перпендикулярные оси z, на высоте 1/2;

2) каждую окружность разбиваем на 5 равных сегментов, точки соединяем между собой;

3) вращаясь против часовой стрелки на угол = 2/5 выбираем точки икосаэдра

P0 (0; 0; 5/2); P0’(0; 0; — 5/2);

P1 (1/2; 0; -1/2); P1’ (-1/2; 0; -1/2);

Pi = Pi-1*Поворот(2/5); Pi’ = Pi-1’*Поворот(2/5);

Матрица поворота

4) находим центры тяжестей граней икосаэдра – они являются вершинами додекаэдра.

5) соединяем вершины линиями.

Количество вершин додекаэдра равно 20.

Рисунок 3.8 — Додекаэдр

4 МАТЕМАТИЧЕСКАЯ МОДЕЛЬ СЛОЖНОГО ОБЪЕКТА

Центр локальной системы координат связываем с геометрическим центром сложного объекта (журнального столика). Алгоритм построения журнального столика:

1.​ Построение журнального столика начинаем с построения ножек столика (3 призм) –noga1, noga2, noga3. Рассчитаем параметры 1-ой призмы noga1. Ее параметры (R, H, Angle,Seg), S, P.

Transformations

Translate(перенос) (-H*cos(Angle); y0; -H)

Rotated(поворот)(x0; y0;z0)

Scale(масштабирование)(S; S; S)

Noga2

Translate(перенос)(H*cos(Angle)*cos(60о);H*cos(Angle)*cos(30о);-H)

Rotated(поворот)(x0; y0;P)

Scale(масштабирование)(S; S; S)

Noga3

Translate(перенос)(H*cos(Angle)*cos(60о);-H*cos(Angle)*cos(30о);-H)

Rotated(поворот)(0; 0; P*2)

Scale(масштабирование)(S; S; S)

Построение ног(призм) показано на рисунке 4.1

Рисунок 4.1- Построение призм в журнальном столике

Получается, что три призмы имеют одно общее, верхнее, основание. Серединой этого основания будет точка (x0;y0;z0). В середине верхнего основания расположен икосаэдр с радиусом Rц.

2.​ Построение икосаэдра (ico)

Transformations

Translate(перенос)(x0;y0;z0)

Rotated(поворот)(x0;y0;z0)

Scale(масштабирование)(Rц; Rц; Rц)

Построение икосаэдра в журнальном столике показано на рисунке 4.2

Рисунок 4.2-Построение икосаэдра в журнальном столике

3.​ В качестве опоры столика использован цилиндр высотой Hц, радиусом Rц, сегментацией Seg (stoika).

Translate(перенос)(x0;y0;z0)

Rotated(поворот)(x0;y0;z0)

Scale(масштабирование)(S; S; S)

Построение цилиндра в журнальном столике показано на рисунке 4.3

Рисунок 4.3- Построение цилиндра в журнальном столике

4.​ Декоративный элемент опоры – октаэдр радиусом R=Rц, перемещенный по оси Oz(dec).

Translate(перенос)(x0;y0;Нц\2)

Rotated(поворот)(x0;y0;z0)

Scale(масштабирование)(S; S; S)

Построение октаэдра в журнальном столике показано на рисунке 4.4

Рисунок 4.4- Построение октаэдра в журнальном столике

5.​ Вверху опоры расположена усечённая пятиугольная пирамида высотой Hуп, нижним радиусом Rн=Rц, верхним радиусом Rв>Rц. Перемещение по оси Oz(tp).

Translate(перенос)(x0;y0;Нц-Нуп)

Rotated(поворот)(x0;y0;z0)

Scale(масштабирование)(S; S; S)

Построение усеченной пятиугольной пирамиды в журнальном столике показано на рисунке 4.5

Рисунок 4.5- Построение усеченной пятиугольной пирамиды

6. Поверхностью стола служит цилиндр высотой Нц2, радиусом Rц2, сегментация 17*Seg(stol).

Translate(перенос)(x0;y0;Нц)

Rotated(поворот)(x0;y0;z0)

Scale(масштабирование)(S; S; S)

Построение цилиндра в журнальном столике показано на рисунке 4.6

Рисунок 4.6- Построение цилиндра в журнальном столике

7.​ Декоративный элемент выполнен из пирамиды и додекаэдра.

Пятиугольная пирамида высотой Hп, радиусом Rп

Transformations

Translate(перенос)(-Rц2\2; Rц2\2;Нц+Нц2)

Rotated(поворот)(x0;y0;z0)

Scale(масштабирование)(S; S; S)

Построение додекаэдра в журнальном столике показано на рисунке 4.7

Рисунок 4.7- Построение додекаэдра в журнальном столике

8.​ Декоративный элемент выполнен из пятигранной пирамиды радиусом R

Transformations

Translate(перенос)(-Rц2\2; Rц2\2;Нп+Нц+Rц2)

Rotated(поворот)(x0;y0;z0)

Scale(масштабирование)(Sд; Sд; Sд)

Построение пятигранной пирамиды в журнальном столике показано на рисунке 4.8

Рисунок 4.8- Построение пятигранной пирамиды в журнальном столике

Построим матрицы преобразований для каждого простого объекта в журнальном столике.

Для призмы Noga1

 (4.1)

Для призмы Noga2

(4.2)

Для призмы Noga3

(4.3)

Построение матрицы для икосаэдра:

Построение матрицы для цилиндра, стойки журнального столика:

Построение декоративного элемента опоры – октаэдр, его матрица выглядит следующим образом:

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

Поверхностью стола служит цилиндр, его матрица:

Декоративный элемент выполнен из пирамиды

Декоративный элемент выполнен из додекаэдра

5 ОПИСАНИЕ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ

5.1 Описание основных структур данных и классов системы

5.1.1 Описание основных структур данных и классов объектов

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

Были использованы следующие векторы:

-​ Vertex – однородные координаты точки в пространстве;

-​ Face – грань, содержит три номера вершин.

Для отображения трехмерных объектов и сцен были реализованы следующие классы:

-​ dcGObject, класс базового объекта, хранящего список вершин и граней объекта, описание свойств материала;

-​ dcGScene, класс сцены, хранит список объектов сцены и предоставляет функции для работы со сценой;

-​ dcGFactory, класс «фабрики» объектов, содержит функции создания разнообразных объектов сцены;

-​ dcGCamera, класс камеры сцены, содержит описание параметров камеры;

-​ dcGLight, класс источника света, содержит параметры светового потока;

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

Схему взаимодействия классов графической библиотеки и внешних объектов можно изобразить следующим образом:

Рисунок 5.1 — Схема взаимодействия классов графического модуля

Программа при помощи командного языка оформляет обращение к сцене на создание или трансформацию объекта. Сцена рассматривает обращение и если это обращение о создании объекта, то создается пустой объект и отправляется запрос о создании уже определенного объекта в фабрику объектов (в качестве аргументов запрос содержит указатель на пустой объект и тип требуемого объекта). Если обращение содержит запрос о трансформации, то производится поиск требуемого объекта и его последующая трансформация.

Также обращение может содержать команды загрузки файла скрипта.

5.2 Описание классов

5.2.2 Описание класса базового объекта сцены

Все параметрические объекты системы представлены классами, которые наследуют свойства базового класса dcGObject :

class dcGObject

{

public:

dcGObject();

dcGObject(dcGObject& src);

virtual ~dcGObject();

CString m_sObjName;

BOOL IsVis;

// Геометрия

GLfloat *vertex;

GLint *faces;

GLubyte color[3];

GLubyte *mask;

int m_prop[3];

GLfloat px,py,pz;

GLfloat dx,dy,dz, rx,ry,rz, sx,sy,sz;

// Материал

GLubyte hasMaterial;

GLfloat ambient [4], diffuse [4], specular[4];

GLfloat shininess;

// методы

void Draw(UCHAR mode=0,LPVOID pScene=0);

void ResetProp(char bMatTrans = 1); // сброс свойств

void RemoveArrays(); // очистка содержимого массивов

void ComplexObj(); // создание составного объекта

void SaveArrays(const char *sFilename);

void operator=(dcGObject &src); // перегрузка присваивания

}

Таблица 5.1 – Атрибуты класса

Тип

Имя

Описание

Cstring

m_sObjName

Имя объекта

BOOL

IsVis

Свойство «видимый ли объект?»

GLfloat*

Vertex

массив координат вершин объекта

GLint*

Faces

массив граней объекта

GLubyte[3]

color

цвет объекта

GLubyte*

mask

маска видимости граней

int[3]

m_prop

число вершин, граней, размер маски

Glfloat

px,py,pz

координаты точки привязки

Glfloat

dx,dy,dz

параметры трансформации переноса

Glfloat

rx,ry,rz

параметры трансформации поворота

Glfloat

sx,sy,sz

параметры трансформации масштаба

GLfloat[4]

ambient

параметры света объекта (в тени)

GLfloat[4]

diffuse

параметры света рассеивания

GLfloat[4]

specular

параметры цвета отражения

Glfloat

shininess

коэффициент отражения

Glubyte

hasMaterial

свойство «материал применён»

dcGobject*

m_aObject

прикрепленные объекты

dcGObject(), dcGObject(dcGObject&) – конструктор по умолчанию и конструктор копирования.

~dcGObject() – деструктор объекта.

Draw(UCHAR mode,LPVOID pScene) – функция рисования объекта. Параметр mode задает способ отображения объекта в сцене: гранями, ребрами, вершинами. Параметр pScene является указателем на сцену, которая посылает запрос о отображении объекта.

ResetProp(), RemoveArrays() – функции сброса свойств и массивов объекта.

ComplexObject() – подготовка атрибутов для создания составного объекта.

SaveArrays(const char* filename) – отладочная функция сохранения текущих атрибутов объекта в файле.

Базовый объект сцены представлен поверхностью состоящей из треугольных граней (tri-mesh). Объект не хранит свой тип (куб, сфера и т.п.), т.е. работа со сценой не предполагает динамическое изменение структуры объекта, таких как, к примеру, изменение количества меридианов или параллелей как в случае со сферой. Сцена проектируется для отображения большей частью статических объектов: комнат, мебели и т.д.

При запуске функции рисования первым параметром является тип режима отображения объекта, а также, вместо указателя на контекст отображения — указатель на сцену, которая содержит этот контекст.

5.2.3 Описание класса параметрических объектов

class DCLIB2_API dcGFactory

{

public:

dcGFactory();

virtual ~dcGFactory();

// геометрия

void crPlane(dcGObject &obj,int dSeg); // плоскость

void crRegularPyramid(dcGObject &obj,float dR,float dH,int dSeg); // правильная пирамида

void crOctahedron(dcGObject &obj,float dR); // октаэдр

// цилиндер(разнорадиусный), правильное основание, наклонённый

void crRegularCylinder(dcGObject &obj,int dRbot,int dRtop,int dH,float fAngle,int dSeg);

void crIcosahedron(dcGObject &obj); // икосаэдр

void crDodecahedron(dcGObject &obj); // додекаэдр

// «helpers»

float Grad2Rad(float grad);

};

Таблица 5.2 – Функции класса параметрических объектов

Имя

Описание

crPlane

Создание плоскости

crRegularPyramid

Создание правильной пирамиды

crOctahedron

Создание октаэдра

crRegularCylinde

Создание цилиндра, призмы, усеченной пирамиды

crIcosahedron

Создание икосаэдра

crDodecahedron

Создание додекаэдра

Grad2Rad

перевод градусов в радианы

5.2.3.1 Функция создания правильной пирамиды

void dcGFactory::crRegularPyramid

Таблица 5.3 – Входные параметры

Тип

Имя

Описание

dcGObject

obj

указатель на создаваемый объект

float

dR

радиус пирамиды

float

dH

высота пирамиды

int

dSeg

сегментация пирамиды

5.2.3.2 Функция создания правильной пирамиды

void dcGFactory::crOctahedron

Таблица 5.4 – Входные параметры

Тип

Имя

Описание

dcGObject

obj

указатель на создаваемый объект

float

dR

радиус октаэдра

5.2.3.3 Функции для создания цилиндра, усеченной пирамиды, призма

void dcGFactory::crRegularCylinder- данная функция создает три объекта: цилиндр, усеченную пирамиду и призму.

Для того, чтобы построить цилиндр необходимо задать следующие входные параметры. Радиусы верхнего и нижнего основания равны.

Таблица 5.5 – Входные параметры

Тип

Имя

Описание

dcGObject

obj

указатель на создаваемый объект

int

dRbot

радиус верхнего основания цилиндра

int

dRtop

радиус нижнего основания цилиндра

int

dH

высота пирамиды

float

fAngle

угол наклона будет равен 90 градусов

int

dSeg

сегментация цилиндра

Для того, чтобы построить усеченную пирамиду необходимо задать следующие входные параметры.

Таблица 5.6 – Входные параметры

Тип

Имя

Описание

dcGObject

obj

указатель на создаваемый объект

int

dRbot

радиус верхнего основания усеченной пирамиды

int

dRtop

радиус нижнего основания усеченной пирамиды

int

dH

высота пирамиды

float

fAngle

угол наклона равен 90 градусов

int

dSeg

сегментация усеченной пирамиды

Для того чтобы построить призму необходимо задать следующие входные параметры. Радиусы верхнего и нижнего основания равны

Таблица 5.7 – Входные параметры

Тип

Имя

Описание

dcGObject

obj

указатель на создаваемый объект

int

dRbot

радиус верхнего основания призмы

int

dRtop

радиус нижнего основания призмы

int

dH

высота призмы

float

fAngle

угол наклона

int

dSeg

сегментация призмы

5.2.3.4 Функция создания икосаэдра

void dcGFactory::crIcosahedron

Таблица 5.8 – Входные параметры

Тип

Имя

Описание

dcGObject

obj

указатель на создаваемый объект

5.2.4 Описание класса сцены

Для хранения геометрии сцены был создан класс Scene, который содержит все вершины, ребра и грани сцены

class dcGScene

{

public:

dcGScene();

virtual ~dcGScene();

int m_ActiveCamera;

UCHAR m_ucELight; // вектор включенных светильников

CArray<dcGCamera,dcGCamera> m_aCameras; // камеры сцены

CArray<dcGObject,dcGObject> m_aObjs; // объекты сцены

CArray<_dcmsLight,_dcmsLight> m_aLight; // база светильников

void ParseScript(CString sScrFile); // выполнить скрипт

void ParseComm(const char* sScript); // выполнить команду

void EnableCamera(int dType=-1);

void EnableLight();

void DrawScene(int dType=0);

void DelObject(dcGObject* Leaf, CString sSearchObj);

protected:

int m_di, m_size;

CString m_sScript;

void CreateObj(int dType);

dcGObject* FindObject(dcGObject* Leaf, CString sSearchObj);

dcGCamera* FindCamera(CString sSearchObj);

_dcmsLight* FindLight(CString sSearchObj);

}

Таблица 5.9 – Атрибуты класса dcGScene

Тип

Имя

Описание

int

M_ActiveCamera

текущая активная камера

UCHAR

M_ucELight

вектор включенных светильников

dcGCamera*

M_aCameras

массив камер сцены

dcGObjects*

M_aObjs

массив объектов сцены

dcmsLight*

M_aLight

массив светильников

ParseScript(CString sSrcFile) – выполнить скрипт с именем sSrcFile.

ParseComm(const char* sScript) – выполнить команду.

EnableCamera(int dType) – включить камеру номер dType.

EnableLight() – включить освещение.

DrawScene(int mode) – отобразить сцену в режиме mode.

DelObject(dcGObject* Leaf, CString sSearchObj) – удалить объект.

CreateObject(int dType) – создать объект указанного типа.

FindObject-Camera-Light – найти указанный объект и вернуть на него указатель.

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

5.3 Описание класса контекста OpenGL

Для более удобной работы с контекстом вывода OpenGL был разработан и частично реализован класс COpenGL

class COpenGL

{

public:

COpenGL();

virtual ~COpenGL();

HGLRC m_hGLContext;

int m_GLPixelIndex;

BOOL StartGL(HDC hDC);

BOOL SetWindowPixelFormat(HDC hDC);

BOOL CreateViewGLContext(HDC hDC);

void InitViewport(int dStartX,int dStartY,int dDX,int dDY);

// перегрузка функции вида

void ViewMode(GLdouble angleY,GLdouble aspect,GLdouble znear,GLdouble zfar); // gluPerspective

void ViewMode(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top,

GLdouble znear,GLdouble zfar);// gluFrustum

///////////////////////

}

Таблица 5.9– Атрибуты класса

Тип

Имя

Описание

HGLRC

m_hGLContex

дескриптор контекста вывода OpenGL

int

m_GLPixelIndex

Индекс формата представления пикселов.

COpenGL() – конструктор класса.

~COpenGL() – деструктор класса, очищающий и уничтожающий контекст OpenGL.

StartGL(HDC hDC) – инициализация контекста OpenGL.

SetWIndowPixelFormat(HDC hDC) – установка формата представления пикселов.

CreateViewGLContex(HDC hDC) – создание контекста вывода OpenGL.

InitViewport(int dStartX,int dStartY,int DX,int DY) – инициализация порта вывода.

ViewMode(…) – установка матриц вида, настройка

5.4 Описание формата графической БД

5.4.1 Внутренний формат графической БД

Внутренним форматом графической БД является информация об объектах, параметры которых задаются и изменяются с клавиатуры.

Параметры объектов:

-​ для пирамиды задается радиус основания, высота, сегментация;

-​ для усеченной пирамиды задается радиус нижнего и верхнего основания, высота, сегментация;

-​ для конуса – радиус основания и высота, сегментация;

-​ для цилиндра – радиус и высота, сегментация;

-​ для октаэдра – радиус;

-​ для додекаэдра – радиус;

5.4.2 Внешний формат графической БД

Для сохранения иерархии объектов сцены во внешний файл и для загрузки сцены используется сериализация. Сериализация – это процесс сохранения текущего состояния объекта на каком-либо устройстве постоянного хранения (в файле или на диске) с возможностью последующего восстановления этого состояния.

6 ТЕСТОВЫЕ ПРИМЕРЫ

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

На данном рисунке отображен икосаэдр в 3Dmax

Приведем пример построения параметрических фигур в 3Dmax и в выполненной курсовой работе

Рисунок 6.1-Икосаэдр в 3Dmax

На данном рисунке отображен икосаэдр нарисованный в данном курсовом проекте.

Рисунок 6.2-Икосаэдр в выполненном курсовом проекте

На данном рисунке отображен цилиндр 3Dmax

Рисунок 6.3-Цилиндр в 3Dmax

На данном рисунке отображен цилиндр нарисованный в данном курсовом проекте.

Рисунок 6.4-Цилиндр в выполненном курсовом проекте

На данном рисунке отображена пирамида с пятиугольным основанием 3Dmax

Рисунок 6.5- пирамида с пятиугольным основанием в 3Dmax

На данном рисунке отображена пирамида с пятиугольным основанием нарисованный в данном курсовом проекте.

Рисунок 6.6- пирамида с пятиугольным основанием в выполненном курсовом проекте

На данном рисунке отображен октаэдр в 3Dmax

Рисунок 6.7- октаэдр в 3Dmax

На данном рисунке отображен октаэдр нарисованный в данном курсовом проекте.

Рисунок 6.8- октаэдр в выполненном курсовом проекте

На данном рисунке отображена призма 3Dmax

Рисунок 6.9- призма в 3Dmax

На данном рисунке отображепризма нарисованный в данном курсовом проекте.

Рисунок 6.10- призма в выполненном курсовом проекте

На данном рисунке отображена усеченная пирамида с пятиугольным основанием 3Dmax

6.11- пирамида с пятиугольным основанием в 3Dmax

На данном рисунке отображен пирамида с пятиугольным основанием нарисованный в данном курсовом проекте.

Рисунок 6.12- пирамида с пятиугольным основанием в выполненном курсовом проекте

ЗАКЛЮЧЕНИЕ

В данном проекте была реализована интерактивная система трехмерного графического моделирования на базе библиотеки OpenGL, позволяющая отображать, параметризировать и производить различные преобразования над 3D объектами. А также двигать их по заданной траектории, организована поддержка сложной иерархии объектов и сохранение сцены в файле.

Программа обеспечивает решение следующих задач: реализация заданного множества параметризированных 3D объектов (призмы, цилиндра, додекаэдра, икосаэдра, пирамида с пятиугольным основанием, усеченная пирамида с пятиугольным основанием, октаэдр, реализация сложного объекта – журнальный столик. Разработана структура объектов движения по заданной траектории заданного набора параметризированных 3D объектов. Реализованы типичные операции управления «камерой» при визуализации и элементов управления объектов, также возможность редактирования и манипулирования объектами в графической БД. Разработана система помощи. Вызов всех функций реализуется в главном меню и продублирован в виде кнопок. Выполняется загрузка и сохранения всех параметров сцены в файл данных. Реализован корректный выход из программы (без зависаний приложения) и планировка сцены (визуализация координатных осей). Реализовано заданное расположения и направления камеры, выбор типа проецирования, изменение размеров сцены. Реализованы все аффинные преобразования для объекта с возможностью редактирования параметров: перенос, масштабирование, вращение вокруг каждой из осей, сдвиг, отражение вокруг каждой из осей.

Таким образом, этот проект может быть использован в любом учебном заведении, программное обеспечение которого удовлетворяет требованиям, представленным в техническом задании.

В дальнейшем проект может быть улучшен и обновлен в соответствии с нововведенными требованиями.

ПЕРЕЧЕНЬ ССЫЛОК

1.​ Роджерс Д., Адамс Дж. Математические основы машинной графики. М.: Машиностроение, 1980 – 234с.

2.​ Роджерс , Дэвид Ф Алгоритмические основы машинной графики / Пер с англ. С.А.Вичеса М.: Мир, 1989 — 503с.

3.​ Шикин А.В. Боресков А.В. Компьютерная графика. Динамика, реалистические изображения. – М.: ДИАЛОГ-МИФИ, 1996. – 288с.

4.​ Аммерал Л. Принципы программирования в машинной графике. М.: «Сол Систем», 1992. – 224с.

5.​ Аммерал Л. Интерактивная трехмерная машинная графика. М.: «Сол Систем», 1992. – 317с.

6.​ Пол Айра Объектно-ориентированное программирование на С++. М.: Машиностроение, 1980.- 234с.

7.​ Курс лекций по предмету «Графическое и геометрическое моделирование».

8.​ Организация взаимодействия человека с техническими средствами АСУ. В 7 кн. Кн. 4. Отображение информации; Практ. пособие/В.М. Гасов, А.И. Коротаев, С.И. Сенькин; Под ред. В.Н. Четверикова. – М.: Высш. шк., 1990. – 111 с.: ил.

9.​ Динамика, реалистическое изображения, Препарта Ф., Шеймос М. Вычислительная геометрия: Введение.demo.design-3D programmig FAQ.-М.:Высш. шк., -1991

10.​ Инетернет страницы http://arcana.co.uk/products/magecian http://itsaft.miem.edu.ru/files/opengl2.exe

ПРИЛОЖЕНИЕ А

Техническое задание

А.1 Общие сведения

Полное наименование курсового проекта (КП) — «Разработка и реализация с помощью библиотеки OpenGL системы трехмерного графического моделирования. Журнальный столик».

КП проектируется студенткой 3-го курса Донецкого государственного института искусственного интеллекта (ДГИИИ), факультета СКИТ, группы ПО-20а Кочетковой Марией Геннадиевной.

Задание выдано кафедрой ПОИС.

Плановый срок начала работы по созданию подсистемы 28 февраля 2003 года, дата защиты – 5 июня 2003 года.

А.2 Назначение и цели создания проекта

КП предполагается использовать для наглядной демонстрации параметризированных 3D объектов.

Цель создания курсового проекта: изучить структуру построения параметризированных 3D объектов и реализовать их с помощью OpenGL.

А.3 Характеристика объекта автоматизации

А.3.2 Сведения об условиях эксплуатации КП

Данный программный продукт применим в учебных целях при изучении графического геометрического моделирования. Предназначен для студентов, слушающих курс лекций: «ГГМ»

А.4 Требования к проекту

Необходимо реализовать компьютерную систему трехмерного графического моделирования.

А.4.1 Требования к КП в целом

Программа должна обеспечивать решение таких задач:

— реализация заданного множества параметризированных 3D объектов:

–​ призма;

–​ цилиндр;

–​ додекаэдр;

–​ икосаэдр;

–​ пирамида с пятиугольным основанием;

–​  усеченная пирамида с пятиугольным основанием.;

–​ октаэдр;

— реализация сложного объекта – журнальный столик (см. рис. А1);

-​ разработка структуры объектов;

-​ движения по заданной траектории заданного набора параметризированных 3D объектов;

-​ реализация типичных операций управления «камерой» при визуализации и элементов управления объектом;

-​ возможность редактирования и манипулирования объектами в графической БД;

-​ разработка системы помощи.

-​ вызов всех функций реализуется в главном меню и продублирован в виде кнопок;

— загрузка и сохранения всех параметров сцены в файл данных;

— корректный выход из программы (без зависаний приложения);

— реализация планировки сцены (визуализация координатных осей);

— реализация заданного расположения и направления камеры;

— выбор типа проецирования;

— изменение размеров сцены;

— реализация всех аффинных преобразований для объекта с возможностью редактирования параметров: перенос, масштабирование, вращение вокруг каждой из осей, сдвиг, отражение вокруг каждой из осей.

А.4.2 Требования к видам обеспечения

А.4.2.1 Требования к программному обеспечению

К программному обеспечению (ПО) предъявляется следующее требование:

— операционная система – Microsoft Windows 95, 98, NT;

— стандартные библиотеки – Visual C++.

А.4.2.3 Требования к техническому обеспечению

-​ тип компьютера – INTEL 5x 86;

-​ объем памяти не менее RAM 64Мб;

-​ монитор типа SVGA, т.к. предполагается использование цветного графического интерфейса и высокого разрешения.

А.4.2.4 Требования к организационному обеспечению

Организационное обеспечение должно включать пояснительную записку со следующими приложениями:

-​ техническое задание;

— руководство пользователя;

-​ экранные формы;

-​ листинги основных блоков программы;

-​ пример файла графической БД, содержащего основные объекты системы.

А.4.2.5. Требования к математической модели

В данном КП производятся аффинные преобразования в пространстве, для этого используется матрица размерностью 4*4.

В КП простые объекты: октаэдр, додекаэдр, икосаэдр рисуется методом медианы и параллелей.

Закрашивание производится методом Гуро.

Закрашивание производится линиями, так как данный алгоритм получил широкое распространение в компьютерной графике.

А.5 Стадии и этапы разработки ПП

Стадии и этапы разработки ПП представлены в таблице А.5.1.

Таблица А.5.1- Стадии и этапы разработки ПП

Этапы работы

Срок

выполнения, недели

1.​ 

Постановка задания. Выбор темы курсового проекта.

1-2

2.​ 

Разработка технического задания

2-3

3.​ 

Анализ структуры программы и графических геометрических методов.

3-4

4.​ 

Создания графической и геометрической математической модели.

5-8

5.​ 

Разработка интерфейса и программирование.

9-10

6.​ 

Отладка программы

11-12

7.​ 

Написание программной документации и оформления пояснительной записки.

13-14

8.​ 

Защита КП.

15-16

Приложение Б

РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ

Б.1 Установка программы и комплект поставки ПО

Для установки программы необходимо распаковать ее из архива “3D-mash.sfx.exe”. Распакованная папка будет хранить следующие папки и файлы: scr_res (stolik.scr), папка, в которой хранятся текстовые файлы, в которых указывается координаты сцены и параметрических объектов, например, в файле stolik.scr, хранятся координаты сцены и фигур журнального столика. Главная библиотека dcOGL.dll, без которой программа не будет работать и она должна лежать в одной папке вместе с файлом 3D-mash.exe, содержит в себе такие классы dcGObject, класс базового объекта, хранящего список вершин и граней объекта, описание свойств материала, dcGScene, класс сцены, хранит список объектов сцены и предоставляет функции для работы со сценой, dcGFactory, класс «фабрики» объектов, содержит функции создания разнообразных объектов сцены,dcGCamera, класс камеры сцены, содержит описание параметров камеры,dcGLight, класс источника света, содержит параметры светового потока. Файл с названием temp_array_OnSave.tmp содержит в себе сохранненую информацию об объекте (координаты вершин, материал, цвет, геометрию сцены) в текстовом формате.

Далее необходимо запустить приложение «3D-mash.exe», после чего появляется главное окно приложения. Работа с ПП осуществляется при помощи мыши и клавиатуры. После запуска исполняемого файла, на экране появляется приложение и отдельная кнопочная панель, внешний вид которого представлен на рисунке В.1.

Б.2 Описание работы программы

После запуска программы 3D-mash.exe появится окно приложения и отдельная кнопочная панель. Окно приложений содержит следующее меню: меню «Файл», меню «Объект», меню «Вид», меню «Сдвиг\Отражение» и меню «Помощь». Кнопочная панель представляет собой кнопки дублирующие функции меню в главном приложении.

Меню «Файл» позволяет создать новую сцену, сохранить файл с определенными параметризованными объектами, загрузить сохраненный файл и выйти из программы. После окончания работы с геометрическими объектами сцену можно сохранить в файл. Так же, при желании работать с сохраненной сценой, можно загрузить этот файл.

Меню «Объект» предназначено для выбора и рисования параметрических объектов (призма, цилиндр, октаэдр, додекаэдр, икосаэдр, пирамида, усеченная пирамида). Также при помощи этого меню мы можем выбирать объект, задавать свойства и материалы выбранного объекта, удалять его. Для изменения параметров фигуры необходимо выбрать в этом меню «Свойства», после этого выплывет диалоговое окно для выбранного объекта поменять его параметры (радиус, высоту, количество аппроксимаций и т.д.). Если нужно поменять или выбрать материал объекту требуется выбрать в этом меню «Материалы», при появлении диалогового окна указать желаемый материал.

Меню «Вид» позволяет выбрать желаемый вид объекта: вид слева, сверху, спереди, в перспективе, а также развернуть объект во весь экран и выбирать свойство камеры и света. При выборе в этом меню «Свойства камеры» появляется диалоговое окно, в котором можно указывать параметры камеры (фокус, глаз, направления верха), а также можно изменить цвет фона, удалить или отобразить координатные оси и грани объекта. При выборе в меню «Свет» появляется окно, в котором можно включить и выключить источники света, указать их позицию, направление, угол под которым он будет падать на объект, цвет и интенсивность изменении света.

Меню «Сдвиг\Отражение» предназначено для реализации аффинных преобразований- сдвига и отражения вдоль любой оси.

О программе и ее использовании можно узнать больше, выбрав меню «Помощь».

Кнопочная панель, представленная на рисунке В2, содержит такие кнопки:

-​ L-загрузить сохраненныъй файл;

-​ N-создать новый файл;

-​ S-сохранить параметры сцены в файл;

-​ C-отчистить сцену;

-​ камера — при нажатии выплавает окно со свойствами камеры: основные коэффициент увеличение (разброс точек), смещение по оси Х, смещение по оси У, положение камер(окуляр,фокус, направления вектора верха), а также в окне можно изменить цвет фона цифрами от 0 до 255, удалить или отобразить координатные оси и грани объекта.

-​ свет — при нажатии появляется окно, в котором можно включить и выключить источники света, выбрать указать их позицию, направление, угол под которым он будет падать на объект, цвет можно указывать от 0 до 1, интенсивность изменении света изменяется от 0 до 128, чем больше экспоненета, тем ярче источник света.

-​ свойства — после этого выплывет диалоговое окно для выбранного объекта поменять его параметры: радиус, высоту, сегментация, угол наклона. Трансформации Т-это перенос, R- поворот, S- масштабирование. Можно менять прозрачность объекта прозрачность меняяется от 0 до 255, чем выше цифра, тем менее прозрачный объект. Меняется также цвет объекта от о до 255.

-​ пирамида- при нажатии появится окно, в котором нужно указать название пирамиды, высоту, радиус нижнего основания, сегментацию, точку привязки, цвет, при желании провести с объектом аффинные преобразования (перенос, поворот, масштаб), коээфициент прозрачности;

-​ усеченная пирамида- при нажатии появится окно, в котором нужно указать название усеченной пирамиды, высоту, радиус нижнего и верхнего основания, сегментацию, точку привязки, цвет, при желании провести с объектом аффинные преобразования (перенос, поворот, масштаб), коээфициент прозрачности;

-​ призма- при нажатии появится окно, в котором нужно указать название призмы, высоту, радиус нижнего основания, сегментацию, угол наклона точку привязки, цвет, при желании провести с объектом аффинные преобразования (перенос, поворот, масштаб), коээфициент прозрачности;

-​ цилиндр- при нажатии появится окно, в котором нужно указать название цилиндр, высоту, радиус нижнего основания, сегментацию, точку привязки, цвет, при желании провести с объектом аффинные преобразования (перенос, поворот, масштаб), коээфициент прозрачности.

-​ октаэдр- при нажатии появится окно, в котором нужно указать название октаэдра, радиус, точку привязки, цвет, при желании провести с объектом аффинные преобразования (перенос, поворот, масштаб), коээфициент прозрачности.

-​ додекаэдр- при нажатии появится окно, в котором нужно указать название додекаэдра, точку привязки, цвет, при желании провести с объектом аффинные преобразования (перенос, поворот, масштаб), коээфициент прозрачности.

-​ икосаэдр- при нажатии появится окно, в котором нужно указать название икосаэдра, точку привязки, цвет, при желании провести с объектом аффинные преобразования (перенос, поворот, масштаб), коээфициент прозрачности.

Приложение В

ЭКРАННЫЕ ФОРМЫ

Рисунок В.1- Главное окно приложения с меню и копками

Рисунок В2-окно параметров сцены

Рисунок В.3-Окно параметров камеры

Рисунок В.4-Окно ведения графической БД

Рисунок В.5-Изображение сложного объекта и окно его параметров

Рисунок В.6-Изображени объекта и окно его параметров(примитивы)

Рисунок В.7- Окно параметров источника света

Рисунок В.8-Окно параметров всех аффиных преобразований

Рисунок В.9-Изображение трех ортогональных проекций

Рисунок В.10-Изображение проекции с индивидуальными параметрами по варианту задания

Рисунок В.11-Окно загрузки и сохранение параметров сцены в файл

Рисунок В.12-Окно помощи по системе

ЛИСТИНГ ПРОГРАММЫ

Программирование камеры и света

// dcGScene.cpp: implementation of the dcGScene class.

//

#include «stdafx.h»

//#include «Ogl3.h»

#include «dcGScene.h»

#include «dcGAscImport.h»

#ifdef _DEBUG

#undef THIS_FILE

static char THIS_FILE[]=__FILE__;

#define new DEBUG_NEW

#endif

dcGScene::dcGScene()

{

m_ucELight = 0;

m_ActiveCamera = 0;

}

dcGScene::~dcGScene()

{

m_aObjs.RemoveAll();

}

void dcGScene::ParseScript(CString vstr)

{

if (vstr.Left(4).CompareNoCase(«Pak:»)!=0)

{

FILE *inFile;

char buf[512];

if (inFile = fopen(vstr,»rt»))

{

ZeroMemory(buf,512);

while(fgets(buf,512,inFile))

{

ParseComm(buf);

ZeroMemory(buf,512);

}

fclose(inFile);

}

}

}

void dcGScene::ParseComm(const char *sScript)

{

CString vstr;

m_sScript.Format(«%s»,sScript);

m_di = 0;

m_size = m_sScript.GetLength();

vstr = getWord();

////////////////////////////////////

// объекты

if (vstr.CompareNoCase(«#create»)==0)

{ CommCreate(); goto skip_level; }

if (vstr.CompareNoCase(«#transform»)==0)

{ CommTrans(); goto skip_level; }

if (vstr.CompareNoCase(«#material»)==0)

{ CommMaterial(); goto skip_level; }

if (vstr.CompareNoCase(«#loadtexture»)==0)

{ CommTexture(); goto skip_level;}

if (vstr.CompareNoCase(«#settexture«)==0)

{ CommSetTexture(); goto skip_level; }

if (vstr.CompareNoCase(«#offset»)==0)

{ CommOffset(); goto skip_level; }

if (vstr.CompareNoCase(«#enable»)==0)

{ CommEnable(); goto skip_level; }

if (vstr.CompareNoCase(«#setcolor»)==0)

{ CommSetColor(); goto skip_level; }

if (vstr.CompareNoCase(«#setpivot»)==0)

{ CommSetPivot(); goto skip_level; }

if (vstr.CompareNoCase(«#link»)==0)

{ CommLink(); goto skip_level; }

if (vstr.CompareNoCase(«#showobj»)==0)

{ CommShow(); goto skip_level; }

if (vstr.CompareNoCase(«#setshow»)==0)

{ CommSetShow(); goto skip_level; }

#ifdef DCGOBJ_FLIP_AND_SHIFT

if (vstr.CompareNoCase(«#ShiftFlip»)==0)

{ CommFlipShift(); goto skip_level; }

#endif

////////////////////////////////////

// камеры

if (vstr.CompareNoCase(«#camera»)==0)

{ CommCamera(); goto skip_level; }

if (vstr.CompareNoCase(«#setcamerapos»)==0)

{ CommCameraPos(); goto skip_level; }

if (vstr.CompareNoCase(«#cameraactive»)==0)

{ CommCameraActive(); goto skip_level; }

////////////////////////////////////

// светильики

if (vstr.CompareNoCase(«#light»)==0)

{ CommLight(); goto skip_level; }

if (vstr.CompareNoCase(«#lightpos»)==0)

{ CommLightPos(); goto skip_level; }

if (vstr.CompareNoCase(«#lightcolor«)==0)

{ CommLightCol(); goto skip_level; }

if (vstr.CompareNoCase(«#lightenable»)==0)

{ CommLightEnable(); goto skip_level; }

////////////////////////////////////

if (vstr.CompareNoCase(«#loadscript«)==0)

{ CommLoad(); goto skip_level; }

if (vstr.CompareNoCase(«#importasc»)==0)

{ CommImportAsc(); goto skip_level; }

if (vstr.CompareNoCase(«#removeall»)==0)

{ CommRemoveAll(); goto skip_level; }

if (vstr.CompareNoCase(«#removeobj»)==0)

{ CommRemoveObject(); goto skip_level; }

if (vstr.CompareNoCase(«#renameobj»)==0)

{ CommRenameObject(); goto skip_level; }

skip_level:

; // skipped

}

void dcGScene::CommCreate()

{

CString vstr;

vstr = getWord();

if (vstr.CompareNoCase(«plane»)==0)

{

CreateObj(1); // Plane Seg:1(default)

goto skip_level;

}

if (vstr.CompareNoCase(«box»)==0)

{

CreateObj(2); // Box Side:1 1 1(default)

goto skip_level;

}

if (vstr.CompareNoCase(«reg_pyramid«)==0)

{

CreateObj(3); // Regular Pyramid

goto skip_level;

}

if (vstr.CompareNoCase(«octahedron»)==0)

{

CreateObj(4); // Octahedron

goto skip_level;

}

if (vstr.CompareNoCase(«prism»)==0)

{

CreateObj(5); // prism

goto skip_level;

}

if (vstr.CompareNoCase(«cylinder»)==0)

{

CreateObj(6); // cylinder

goto skip_level;

}

if (vstr.CompareNoCase(«trunc_pyramid»)==0)

{

CreateObj(7); // trunc_pyramid

goto skip_level;

}

if (vstr.CompareNoCase(«icosahedron«)==0)

{

CreateObj(8); // icosahedron

goto skip_level;

}

if (vstr.CompareNoCase(«dodecahedron»)==0)

{

CreateObj(9); // dodecahedron

goto skip_level;

}

if (vstr.CompareNoCase(«hemisphere»)==0)

{

CreateObj(10); // hemisphere

goto skip_level;

}

skip_level:

; // skipped

}

void dcGScene::CommTrans()

{

CString vstr;

vstr = getText();

dcGObject *pObject;

pObject = FindObject(0,vstr);

// Scale

vstr = getWord();

if (vstr[0]!=’s’ && vstr[0]!=’S’) goto trans_label;

pObject->sx = (GLfloat)atof(vstr.Mid(6));

vstr = getWord(); pObject->sy = (GLfloat)atof(vstr);

vstr = getWord(); pObject->sz = (GLfloat)atof(vstr);

// Trans

if (m_di>=m_size) goto skip_label;

vstr = getWord();

trans_label:

if (vstr[0]!=’t’ && vstr[0]!=’T’) goto rotate_label;

pObject->dx = (GLfloat)atof(vstr.Mid(6));

vstr = getWord(); pObject->dy = (GLfloat)atof(vstr);

vstr = getWord(); pObject->dz = (GLfloat)atof(vstr);

// Rot’ate

if (m_di>=m_size) goto skip_label;

vstr = getWord();

rotate_label:

pObject->rx = (GLfloat)atof(vstr.Mid(4));

vstr = getWord(); pObject->ry = (GLfloat)atof(vstr);

vstr = getWord(); pObject->rz = (GLfloat)atof(vstr);

skip_label:

;

}

#ifdef DCGOBJ_FLIP_AND_SHIFT

void dcGScene::CommFlipShift()

{

CString vstr;

vstr = getText();

dcGObject *pObject;

pObject = FindObject(0,vstr);

// Shift

vstr = getWord();

if (vstr[0]!=’s’ && vstr[0]!=’S’) goto flip_label;

pObject->m_fShift[0] = (GLfloat)atof(vstr.Mid(6));

vstr = getWord(); pObject->m_fShift[1] = (GLfloat)atof(vstr);

vstr = getWord(); pObject->m_fShift[2] = (GLfloat)atof(vstr);

// Flip

if (m_di>=m_size) goto skip_label;

vstr = getWord();

flip_label:

pObject->m_bFlip[0] = (GLfloat)atof(vstr.Mid(5));

vstr = getWord(); pObject->m_bFlip[1] = (GLfloat)atof(vstr);

vstr = getWord(); pObject->m_bFlip[2] = (GLfloat)atof(vstr);

skip_label:

;

}

#endif

void dcGScene::CommOffset()

{

CString vstr;

vstr = getText();

dcGObject *pObject;

GLfloat vpar[3];

pObject = FindObject(0,vstr);

// Scale

vstr = getWord();

if (vstr[0]!=’s’ && vstr[0]!=’S’) goto trans_label;

vpar[0] = (GLfloat)atof(vstr.Mid(6));

vstr = getWord();vpar[1] = (GLfloat)atof(vstr);

vstr = getWord();vpar[2] = (GLfloat)atof(vstr);

ApplyChanges(pObject,’s’,vpar[0],vpar[1],vpar[2]);

// Trans

if (m_di>=m_size) goto skip_label;

vstr = getWord();

trans_label:

if (vstr[0]!=’t’ && vstr[0]!=’T’) goto rotate_label;

vpar[0] = (GLfloat)atof(vstr.Mid(6));

vstr = getWord();vpar[1] = (GLfloat)atof(vstr);

vstr = getWord();vpar[2] = (GLfloat)atof(vstr);

ApplyChanges(pObject,’t’,vpar[0],vpar[1],vpar[2]);

//pObject->dx += vpar[0];

//vstr = getWord(); pObject->dy += vpar[1];

//vstr = getWord(); pObject->dz += vpar[2];

// Rot’ate

if (m_di>=m_size) goto skip_label;

vstr = getWord();

rotate_label:

vpar[0] = (GLfloat)atof(vstr.Mid(4));

vstr = getWord();vpar[1] = (GLfloat)atof(vstr);

vstr = getWord();vpar[2] = (GLfloat)atof(vstr);

ApplyChanges(pObject,’r’,vpar[0],vpar[1],vpar[2]);

skip_label:

;

}

void dcGScene::CommMaterial()

{

CString vstr;

vstr = getText();

dcGObject *pObject;

pObject = FindObject(0,vstr);

// Ambient

if (m_di>=m_size) goto skip_label;

vstr = getWord();

if (vstr[0]!=’a’ && vstr[0]!=’A’) goto diffuse_label;

pObject->ambient[0] = (GLfloat)atof(vstr.Mid(8));

vstr = getWord(); pObject->ambient[1] = (GLfloat)atof(vstr);

vstr = getWord(); pObject->ambient[2] = (GLfloat)atof(vstr);

pObject->ambient[3] = 1.0f;

// Diffuse

if (m_di>=m_size) goto skip_label;

vstr = getWord();

diffuse_label:

if (vstr[0]!=’d’ && vstr[0]!=’D’) goto specular_label;

pObject->diffuse[0] = (GLfloat)atof(vstr.Mid(8));

vstr = getWord(); pObject->diffuse[1] = (GLfloat)atof(vstr);

vstr = getWord(); pObject->diffuse[2] = (GLfloat)atof(vstr);

pObject->diffuse[3] = 1.0f;

// Specular

if (m_di>=m_size) goto skip_label;

vstr = getWord();

specular_label:

if (vstr[1]!=’p’ && vstr[1]!=’P’) goto shininess_label;

pObject->specular[0] = (GLfloat)atof(vstr.Mid(9));

vstr = getWord(); pObject->specular[1] = (GLfloat)atof(vstr);

vstr = getWord(); pObject->specular[2] = (GLfloat)atof(vstr);

pObject->specular[3] = 1.0f;

// Shininess

if (m_di>=m_size) goto skip_label;

vstr = getWord();

shininess_label:

pObject->shininess = (GLfloat)atof(vstr.Mid(10));

skip_label:

;

}

void dcGScene::CommEnable()

{

CString vstr;

vstr = getText();

dcGObject *pObject;

pObject = FindObject(0,vstr);

// hasMaterial

vstr = getWord();

pObject->hasMaterial = atoi(vstr.Mid(12));

vstr = getWord();

pObject->hasTexture = atoi(vstr.Mid(11));

}

void dcGScene::CommShow()

{

CString vstr;

vstr = getText();

dcGObject *pObject;

pObject = FindObject(0,vstr);

// show:

vstr = getWord();

pObject->IsVis = atoi(vstr.Mid(5));

}

void dcGScene::CommSetShow()

{

CString vstr;

vstr = getText();

dcGObject *pObject;

pObject = FindObject(0,vstr);

// show:

vstr = getWord();

pObject->m_ucMode = atoi(vstr.Mid(5));

ApplyChanges(pObject,pObject->m_ucMode);

}

void dcGScene::CommSetPivot()

{

CString vstr;

int dOff = 0;

dcGObject *pObject;

vstr = getText();

pObject = FindObject(0,vstr);

vstr = getWord();

// Pivot Pos

if (m_di>=m_size) goto skip_label;

if (vstr[0]!=’p’ && vstr[0]!=’P’) goto skip_label;

pObject->px = (GLfloat)atof(vstr.Mid(4));

vstr = getWord();

pObject->py = (GLfloat)atof(vstr);

vstr = getWord();

pObject->pz = (GLfloat)atof(vstr);

skip_label:

;

}

void dcGScene::CommSetColor()

{

CString vstr;

int dOff = 0;

dcGObject *pObject;

vstr = getText();

pObject = FindObject(0,vstr);

vstr = getWord();

// Pivot Pos

if (m_di>=m_size) goto skip_label;

if (vstr[0]!=’c’ && vstr[0]!=’C’) goto skip_label;

pObject->color[0] = atoi(vstr.Mid(4));

vstr = getWord();

pObject->color[1] = atoi(vstr);

vstr = getWord();

pObject->color[2] = atoi(vstr);

vstr = getWord();

pObject->color[3] = atoi(vstr);

skip_label:

;

}

///////////////////////////////////////////////////////////////////

void dcGScene::CommCamera()

{

CString vstr;

int dLast;

dLast = m_aCameras.GetSize();

m_aCameras.SetSize(dLast+1);

vstr = getText();

m_aCameras[dLast].name = vstr;

vstr = getWord();

if (vstr.CompareNoCase(«Frustrum»)==0)

{

m_aCameras[dLast].numparams = 6;

m_aCameras[dLast].vidparams = new GLdouble[6];

vstr = getWord(); m_aCameras[dLast].vidparams[0] = atof(vstr.Mid(5)); // left:

vstr = getWord(); m_aCameras[dLast].vidparams[1] = atof(vstr.Mid(6)); // right:

vstr = getWord(); m_aCameras[dLast].vidparams[2] = atof(vstr.Mid(4)); // top:

vstr = getWord(); m_aCameras[dLast].vidparams[3] = atof(vstr.Mid(4)); // bot:

vstr = getWord(); m_aCameras[dLast].vidparams[4] = atof(vstr.Mid(6)); // znear:

vstr = getWord(); m_aCameras[dLast].vidparams[5] = atof(vstr.Mid(5)); // zfar:

}

if (vstr.CompareNoCase(«Perspective«)==0)

{ // Perspective

m_aCameras[dLast].numparams = 4;

m_aCameras[dLast].vidparams = new GLdouble[4];

vstr = getWord(); m_aCameras[dLast].vidparams[0] = atof(vstr.Mid(7)); // angleY:

vstr = getWord(); m_aCameras[dLast].vidparams[1] = atof(vstr.Mid(7)); // aspect:

vstr = getWord(); m_aCameras[dLast].vidparams[2] = atof(vstr.Mid(6)); // znear:

vstr = getWord(); m_aCameras[dLast].vidparams[3] = atof(vstr.Mid(5)); // zfar:

}

skip_level:

; // skipped

}

void dcGScene::CommCameraPos()

{

CString vstr;

int dOff = 0;

vstr = getText();

dcGCamera *pObject;

pObject = FindCamera(vstr);

vstr = getWord();

if (vstr.CompareNoCase(«offset»)==0)

{

dOff = 1;

vstr = getWord();

}

// Trans

if (m_di>=m_size) goto skip_label;

if (vstr[0]!=’t’ && vstr[0]!=’T’) goto rotate_label;

pObject->trans[0] = pObject->trans[0]*dOff + (GLfloat)atof(vstr.Mid(6));

vstr = getWord();

pObject->trans[1] = pObject->trans[1]*dOff + (GLfloat)atof(vstr);

vstr = getWord();

pObject->trans[2] = pObject->trans[2]*dOff + (GLfloat)atof(vstr);

// Rot’ate

if (m_di>=m_size) goto skip_label;

vstr = getWord();

rotate_label:

pObject->rot[0] = pObject->rot[0]*dOff + (GLfloat)atof(vstr.Mid(4));

vstr = getWord();

pObject->rot[1] = pObject->rot[1]*dOff + (GLfloat)atof(vstr);

vstr = getWord();

pObject->rot[2] = pObject->rot[2]*dOff + (GLfloat)atof(vstr);

skip_label:

;

}

void dcGScene::CommCameraActive()

{

CString vstr;

int vi, vs;

BOOL bFind=FALSE;

vstr = getText();

vs = m_aCameras.GetSize();

vi = 0;

while(vi<vs && !bFind)

if (m_aCameras[vi].name.CompareNoCase(vstr)==0) bFind = TRUE;

else vi++;

if (bFind)

m_ActiveCamera = vi;

else

m_ActiveCamera = 0;

}

void dcGScene::CommLight()

{

CString vstr;

int dLast;

vstr = getText();

_dcmsLight *pObject = 0;

pObject = FindLight(vstr);

if (pObject) return;

dLast = m_aLight.GetSize();

m_aLight.SetSize(dLast+1);

//vstr = getText();

m_aLight[dLast].name = vstr;

// Exp

vstr = getWord();

m_aLight[dLast].exponent = (GLfloat)atof(vstr.Mid(4));

// cutoff

vstr = getWord();

m_aLight[dLast].cutoff = (GLfloat)atof(vstr.Mid(7));

m_aLight[dLast].num = dLast;

skip_label:

;

}

void dcGScene::CommLightPos()

{

CString vstr;

int dOff = 0;

vstr = getText();

_dcmsLight *pObject;

pObject = FindLight(vstr);

vstr = getWord();

if (vstr.CompareNoCase(«offset»)==0)

{

dOff = 1;

vstr = getWord();

}

// Pos

if (m_di>=m_size) goto skip_label;

if (vstr[0]!=’p’ && vstr[0]!=’P’) goto dir_label;

pObject->pos[0] = pObject->pos[0]*dOff + (GLfloat)atof(vstr.Mid(4));

vstr = getWord();

pObject->pos[1] = pObject->pos[1]*dOff + (GLfloat)atof(vstr);

vstr = getWord();

pObject->pos[2] = pObject->pos[2]*dOff + (GLfloat)atof(vstr);

pObject->pos[3] = 1.0;

// Direction

if (m_di>=m_size) goto skip_label;

vstr = getWord();

dir_label:

pObject->dir[0] = pObject->dir[0]*dOff + (GLfloat)atof(vstr.Mid(4));

vstr = getWord();

pObject->dir[1] = pObject->dir[1]*dOff + (GLfloat)atof(vstr);

vstr = getWord();

pObject->dir[2] = pObject->dir[2]*dOff + (GLfloat)atof(vstr);

pObject->dir[3] = 1.0;

skip_label:

;

}

void dcGScene::CommLightCol()

{

CString vstr;

int dOff = 0;

vstr = getText();

_dcmsLight *pObject;

pObject = FindLight(vstr);

vstr = getWord();

// Diffuse

if (m_di>=m_size) goto skip_label;

if (vstr[0]!=’c’ && vstr[0]!=’C’) goto skip_label;

pObject->color[0] = (GLfloat)atof(vstr.Mid(7));// color:

vstr = getWord(); pObject->color[1] = (GLfloat)atof(vstr);

vstr = getWord(); pObject->color[2] = (GLfloat)atof(vstr);

pObject->color[3] = 1.0f;

skip_label:

;

}

void dcGScene::CommLightEnable()

{

CString vstr;

int dOff = 0;

vstr = getText();

_dcmsLight *pObject;

pObject = FindLight(vstr);

vstr = getWord();

// Vector

vstr = vstr.Mid(7);

m_ucELight = 0;

for(int vi=0;vi<8;vi++)

if (vstr[vi]==’1′) m_ucELight |= (1<<vi);

//vstr.Empty();

//vstr.Format(«%d»,m_ucELight);

//MessageBox(0,vstr,»dll»,MB_OK);

skip_label:

;

}

/////////////////////////////////////////////

// Иное

void dcGScene::CommLoad()

{

CString vstr;

// hasMaterial

vstr = getText();

ParseScript(vstr);

}

void dcGScene::CommSetTexture()

{

CString vstr;

int vi,vs;

char vf = 1;

vstr = getText();

dcGObject *pObject;

pObject = FindObject(0,vstr);

// Texture name

vstr = getWord();

if (vstr[0]!=’n’ && vstr[0]!=’N’) goto inv_label;

vstr = getText();

vs = m_aDibs.GetSize();

vi = 0;

while(vi<vs && vf)

{

if (vstr.CompareNoCase(m_aDibs[vi].name)==0) vf=0;

else vi++;

}

if (vf==0)

{

CSize cs;

pObject->dTexIndex = vi;

cs = m_aDibs[vi].cDib.GetDimensions();

pObject->dTexX = cs.cx;

pObject->dTexY = cs.cy;

}

if (m_di>=(m_size-1)) goto skip_label;

vstr = getWord();

inv_label:

if (vstr[0]!=’i’ && vstr[0]!=’I’) goto skip_label;

pObject->dTexInvMode = GL_MODULATE + atoi(vstr.Mid(8));

/*

// Rot’ate

if (m_di>=m_size) goto skip_label;

vstr = getWord();

rotate_label:

pObject->rx = (GLfloat)atof(vstr.Mid(4));

vstr = getWord(); pObject->ry = (GLfloat)atof(vstr);

vstr = getWord(); pObject->rz = (GLfloat)atof(vstr);

*/

skip_label:

;

}

void dcGScene::CommTexture()

{

CString vstr1,vstr2;

int dLast;

// Load

vstr1 = getText(); // path+filename

vstr2 = getText(); // texture name

LoadTexture(vstr1,vstr2);

}

void dcGScene::CommLink()

{

CString vstr;

CString tst;

int dLast;

dcGObject *pObject1;

dcGObject *pObject2;

BOOL has3=FALSE;

vstr = getText();

pObject1 = FindObject(0,vstr);

vstr = getText();

pObject2 = FindObject(0,vstr);

if (m_di>=(m_size-1)) goto skip_label;

vstr = getText();

has3 = TRUE;

skip_label:

dLast = pObject1->m_aObjects.GetSize();

if (/*dLast==0 ||*/ has3)

{

dcGObject tmpObj;

tmpObj = *pObject1;

pObject1->m_aObjects.SetSize(2);

pObject1->m_aObjects[0] = tmpObj;

pObject1->m_aObjects[1] = *pObject2;

pObject1->ComplexObj();

pObject1->m_sObjName = vstr;

pObject2->m_sObjName.Format(«%s_%d»,pObject1->m_sObjName,dLast);

tmpObj.RemoveArrays();

}

else

{

pObject1->m_aObjects.SetSize(dLast+1);

pObject1->m_aObjects[dLast] = *pObject2;

pObject2->m_sObjName.Format(«%s_%d»,pObject1->m_sObjName,dLast);

}

CString delstr = pObject2->m_sObjName;

DelObject(0,delstr);

}

void dcGScene::CommImportAsc()

{

CString vstr;

dcGAscImport cAsc;

vstr = getText();

cAsc.ImportASC(vstr,this);

}

void dcGScene::CommRemoveAll()

{

m_aDibs.RemoveAll();

m_aCameras.RemoveAll();

//m_aLight.RemoveAll();

m_aObjs.RemoveAll();

m_aObjs.FreeExtra();

//m_ActiveCamera = 0;

m_ucELight = 0;

}

void dcGScene::CommRemoveObject()

{

CString vstr;

vstr = getText();

DelObject(0,vstr);

}

void dcGScene::CommRenameObject()

{

CString vstr;

vstr = getText();

dcGObject *pObject;

pObject = FindObject(0,vstr);

vstr = getText();

pObject->m_sObjName.Empty();

pObject->m_sObjName = vstr;

}

///////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////

void dcGScene::CreateObj(int dType)

{

dcGFactory dcgFact;

int dPar[6];

float fPar[6];

int dLast;

CString vstr,tstr;

m_aObjs.SetSize(m_aObjs.GetSize()+1);

//m_aObjs.FreeExtra();

dLast = m_aObjs.GetSize()-1;

// Name

vstr = getText();

//m_aObjs[dLast].m_sObjName = new char[vstr.GetLength()+1];

//ZeroMemory(m_aObjs[dLast].m_sObjName,vstr.GetLength()+1);

m_aObjs[dLast].m_sObjName.Empty();

m_aObjs[dLast].m_sObjName = vstr;

m_aObjs[dLast].m_bType = dType;

// Geometry

switch(dType)

{

case 1: // create plane

vstr = getWord();

dPar[0] = atoi(vstr.Mid(4)); // отрезаем «Seg:»

dcgFact.crPlane(m_aObjs[dLast],dPar[0]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

case 2: // create Box

vstr = getWord();

dPar[0] = atoi(vstr.Mid(5)); // отрезаем «Side:»

vstr = getWord();dPar[1] = atoi(vstr);

vstr = getWord();dPar[2] = atoi(vstr);

dcgFact.crBox(m_aObjs[dLast],dPar[0],dPar[1],dPar[2]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

case 3: // create Regular Pyramid

vstr = getWord();

fPar[0] = atof(vstr.Mid(7)); // отрезаем «Radius:»

vstr = getWord();fPar[1] = atof(vstr.Mid(2)); // H:

vstr = getWord();dPar[0] = atoi(vstr.Mid(4)); // Seg:

dcgFact.crRegularPyramid(m_aObjs[dLast],fPar[0],fPar[1],dPar[0]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

case 4: // create Octahedron

vstr = getWord();

fPar[0] = atof(vstr.Mid(7)); // отрезаем «Radius:»

dcgFact.crOctahedron(m_aObjs[dLast],fPar[0]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

case 5: // create Prism

// worked

vstr = getWord();

dPar[0] = atoi(vstr.Mid(7)); // отрезаем «Radius:»

vstr = getWord();dPar[1] = atoi(vstr.Mid(2)); // H:

vstr = getWord();fPar[0] = atof(vstr.Mid(4)); // Ang:

m_aObjs[dLast].m_fFparam1 = atof(vstr.Mid(4));

vstr = getWord();dPar[2] = atoi(vstr.Mid(4)); // Seg:

dcgFact.crRegularCylinder(m_aObjs[dLast],dPar[0],dPar[0],dPar[1],fPar[0],dPar[2]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

case 6: // create Cylinder

vstr = getWord();

dPar[1] = atoi(vstr.Mid(7)); // отрезаем «Radius:»

vstr = getWord();dPar[2] = atoi(vstr.Mid(2)); // H:

vstr = getWord();dPar[0] = atoi(vstr.Mid(4)); // Seg:

dcgFact.crRegularCylinder(m_aObjs[dLast],dPar[1],dPar[1],dPar[2],90.0,dPar[0]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

case 7: // create Truncated Pyramid

vstr = getWord();

dPar[1] = atoi(vstr.Mid(7)); // отрезаем «Radius:»

vstr = getWord();dPar[2] = atoi(vstr.Mid(3)); // R2:

vstr = getWord();dPar[3] = atof(vstr.Mid(2)); // H:

vstr = getWord();dPar[0] = atoi(vstr.Mid(4)); // Seg:

dcgFact.crRegularCylinder(m_aObjs[dLast],dPar[1],dPar[2],dPar[3],90.0,dPar[0]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

case 8: // create Icosahedron

dcgFact.crIcosahedron(m_aObjs[dLast]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

case 9: // create Dodecahedron

dcgFact.crDodecahedron(m_aObjs[dLast]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

case 10: // create Hemishpere

vstr = getWord();

fPar[0] = atof(vstr.Mid(7)); // отрезаем «Radius:»

vstr = getWord();dPar[0] = atoi(vstr.Mid(4)); // Mer:

vstr = getWord();dPar[1] = atoi(vstr.Mid(4)); // Par:

dcgFact.crHemisphere(m_aObjs[dLast],fPar[0],dPar[0],dPar[1]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

}

// Color

vstr = getWord();

m_aObjs[dLast].color[0] = atoi(vstr.Mid(6));

vstr = getWord(); m_aObjs[dLast].color[1] = atoi(vstr);

vstr = getWord(); m_aObjs[dLast].color[2] = atoi(vstr);

vstr = getWord(); m_aObjs[dLast].color[3] = atoi(vstr);

// Pivot

vstr = getWord();

m_aObjs[dLast].px = (GLfloat)atof(vstr.Mid(6));

vstr = getWord(); m_aObjs[dLast].py = (GLfloat)atof(vstr);

vstr = getWord(); m_aObjs[dLast].pz = (GLfloat)atof(vstr);

// Texture Map

vstr = getWord();

vstr = getText();

if (vstr.CompareNoCase(«-none»)!=0)

{

if (vstr.CompareNoCase(«-default»)==0)

{

switch(dType)

{

case 1: // create plane TexMap

dcgFact.crPlaneTex(m_aObjs[dLast],dPar[0]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

case 2: // create box TexMap

dcgFact.crBoxTex(m_aObjs[dLast]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

case 7: // create Truncated Pyramid

dcgFact.crRegularCylinderTex(m_aObjs[dLast],dPar[1],dPar[2],dPar[3],90.0,dPar[0]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

case 10: // create Hemishpere

dcgFact.crHemisphereTex(m_aObjs[dLast],fPar[0],dPar[0],dPar[1]);

//m_aObjs[dLast].SaveArrays(«object.ar»);

break;

}

}

}

m_aObjs[dLast].hasMaterial = 0;

}

//////////////////////////////////////////////////////////////

// вывод сцены в контекст

void dcGScene::DrawScene(int dType)

{

int vs,vi;

vs = m_aObjs.GetSize();

if (vs==0) return;

for(vi=0;vi<vs;vi++)

{

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

m_aObjs[vi].Draw(dType,this);

}

}

void dcGScene::EnableCamera(int dType)

{

if (m_aCameras.GetSize()==0) return;

if (dType<0)

m_aCameras[m_ActiveCamera].Apply();

else

if (dType<m_aCameras.GetSize())

m_aCameras[dType].Apply();

}

void dcGScene::CameraLook(int dType)

{

if (dType<0)

m_aCameras[m_ActiveCamera].LookAt();

else

if (dType<m_aCameras.GetSize())

m_aCameras[dType].LookAt();

}

void dcGScene::EnableLight()

{

int vi,vs;

GLfloat amb[4] = {0.0,0.0,0.0,1.0};

GLfloat diff[4] = {1.0,1.0,1.0,1.0};

GLfloat spec[4] = {1.0,1.0,1.0,1.0};

vs = m_aLight.GetSize();

if (vs==0) return;

for(vi=0;vi<vs;vi++)

{

glLightfv(GL_LIGHT0+vi, GL_AMBIENT, amb);

glLightfv(GL_LIGHT0+vi, GL_DIFFUSE, m_aLight[vi].color);

glLightfv(GL_LIGHT0+vi, GL_SPECULAR, m_aLight[vi].color);

glLightfv(GL_LIGHT0+vi, GL_POSITION, m_aLight[vi].pos);

glLightfv(GL_LIGHT0+vi, GL_SPOT_DIRECTION, m_aLight[vi].dir);

//glLightf(GL_LIGHT0+vi, GL_SPOT_EXPONENT, m_aLight[vi].exponent);

glLighti(GL_LIGHT0+vi, GL_SPOT_EXPONENT, (GLint)(m_aLight[vi].exponent));

glLightf(GL_LIGHT0+vi, GL_SPOT_CUTOFF, m_aLight[vi].cutoff);

}

CString vstr;

CFile cf;

//cf.Open(«dll.dbg»,CFile::modeWrite|CFile::modeCreate);

for(vi=0;vi<vs;vi++)

{

vstr.Empty();

if( (m_ucELight&(1<<vi))==(1<<vi) )

glEnable(GL_LIGHT0+vi);

else

glDisable(GL_LIGHT0+vi);

char buf[64];

ZeroMemory(buf,64);

vstr.Format(» %d/%d(~%s~)»,vi,vs,m_aLight[vi].name);

strcpy(buf,vstr);

//cf.Write(&buf,strlen(buf));

ZeroMemory(buf,64);

vstr.Format(» %d:pos(%f;%f;%f)«,vi,m_aLight[vi].pos[0],m_aLight[vi].pos[1],m_aLight[vi].pos[2]);

strcpy(buf,vstr);

//cf.Write(&buf,strlen(buf));

ZeroMemory(buf,64);

vstr.Format(» %d:dir(%f;%f;%f)«,vi,m_aLight[vi].dir[0],m_aLight[vi].dir[1],m_aLight[vi].dir[2]);

strcpy(buf,vstr);

//cf.Write(&buf,strlen(buf));

ZeroMemory(buf,64);

vstr.Format(» %d:e_c(%f;%f)»,vi,m_aLight[vi].exponent,m_aLight[vi].cutoff);

strcpy(buf,vstr);

//cf.Write(&buf,strlen(buf));

//MessageBox(0,vstr,»dll»,MB_OK);

}

}

// найти объект по имени

dcGObject* dcGScene::FindObject(dcGObject* Leaf, CString sSearchObj)

{

int vf, vi, vs;

BOOL bFind = 0;

CString vstr;

vf = sSearchObj.Find(«>»);

if (vf!=-1)

{

vstr = sSearchObj.Left(vf);

if (Leaf==0)

vs = m_aObjs.GetSize();

else

vs = Leaf->m_aObjects.GetSize();

vi = 0;

while(vi<vs && bFind==0)

{

if (Leaf==0)

{

if (vstr.CompareNoCase(m_aObjs[vi].m_sObjName)==0)

bFind=1;

}

else

{

if (vstr.CompareNoCase(Leaf->m_aObjects[vi].m_sObjName)==0)

bFind=1;

}

if (bFind==0) vi++;

}

if (bFind==0) return 0;

else

{

if (Leaf==0)

return FindObject(&m_aObjs[vi],sSearchObj.Mid(vf+1));

else

return FindObject(&(Leaf->m_aObjects[vi]),sSearchObj.Mid(vf+1));

}

}

else

{

if (Leaf==0)

vs = m_aObjs.GetSize();

else

vs = Leaf->m_aObjects.GetSize();

vi = 0;

while(vi<vs && bFind==0)

{

if (Leaf==0)

{

if (sSearchObj.CompareNoCase(m_aObjs[vi].m_sObjName)==0)

bFind=1;

}

else

{

if (sSearchObj.CompareNoCase(Leaf->m_aObjects[vi].m_sObjName)==0)

bFind=1;

}

if (bFind==0) vi++;

}

if (bFind==0) return 0;

else

{

if (Leaf==0)

return &m_aObjs[vi];

else

return &(Leaf->m_aObjects[vi]);

}

}

}

// поиск камеры по имени

dcGCamera* dcGScene::FindCamera(CString sSearchObj)

{

int vi,vs;

BOOL bFind = FALSE;

vs = m_aCameras.GetSize();

vi = 0;

while(vi<vs && !bFind)

if (m_aCameras[vi].name.CompareNoCase(sSearchObj)==0) bFind = TRUE;

else vi++;

if (bFind)

return &m_aCameras[vi];

else return 0;

}

// поиск камеры по имени

_dcmsLight* dcGScene::FindLight(CString sSearchObj)

{

int vi,vs;

BOOL bFind = FALSE;

vs = m_aLight.GetSize();

vi = 0;

while(vi<vs && !bFind)

if (m_aLight[vi].name.CompareNoCase(sSearchObj)==0) bFind = TRUE;

else vi++;

if (bFind)

return &m_aLight[vi];

else return 0;

}

// удаление объекта

void dcGScene::DelObject(dcGObject* Leaf, CString sSearchObj)

{

int vf, vi, vs;

BOOL bFind = 0;

CString vstr;

//CString ttt;

//ttt.Format(«%s«,m_aObjs[vi].m_sObjName);

vf = sSearchObj.Find(«//»);

if (vf!=-1)

{

vstr = sSearchObj.Left(vf);

if (Leaf==0)

vs = m_aObjs.GetSize();

else

vs = Leaf->m_aObjects.GetSize();

vi = 0;

while(vi<vs && bFind==0)

{

if (Leaf==0)

{

if (sSearchObj.CompareNoCase(m_aObjs[vi].m_sObjName)==0)

bFind=1;

}

else

{

if (sSearchObj.CompareNoCase(Leaf->m_aObjects[vi].m_sObjName)==0)

bFind=1;

}

if (bFind==0) vi++;

}

if (bFind!=0)

{

if (Leaf==0)

DelObject(&m_aObjs[vi],vstr.Mid(vf+2));

else

DelObject(&(Leaf->m_aObjects[vi]),vstr.Mid(vf+2));

}

}

else

{

if (Leaf==0)

vs = m_aObjs.GetSize();

else

vs = Leaf->m_aObjects.GetSize();

vi = 0;

while(vi<vs && bFind==0)

{

if (Leaf==0)

{

if (sSearchObj.CompareNoCase(m_aObjs[vi].m_sObjName)==0)

bFind=1;

}

else

{

if (sSearchObj.CompareNoCase(Leaf->m_aObjects[vi].m_sObjName)==0)

bFind=1;

}

if (bFind==0) vi++;

}

if (bFind!=0)

{

if (Leaf==0)

{

m_aObjs[vi].RemoveArrays();

m_aObjs.RemoveAt(vi);

m_aObjs.FreeExtra();

//return &m_aObjs[vi];

}

else

{

Leaf->m_aObjects[vi].RemoveArrays();

Leaf->m_aObjects.RemoveAt(vi);

Leaf->m_aObjects.FreeExtra();

//return &(Leaf->m_aObjects[vi]);

}

}

}

}

// вернуть указатель на объект по индексу

dcGObject* dcGScene::GetObjByIndex(int dIndex)

{

if (dIndex>=0 && dIndex<m_aObjs.GetSize())

return &(m_aObjs[dIndex]);

}

void dcGScene::GetObjByIndex(int dIndex,dcGObject& pObj)

{

if (dIndex>=0 && dIndex<m_aObjs.GetSize())

pObj = m_aObjs[dIndex];

}

// применение изменений ко всей группе

void dcGScene::ApplyChanges(dcGObject *dst,char sType,GLfloat p1,GLfloat p2,GLfloat p3)

{

int vi,vs;

vs = dst->m_aObjects.GetSize();

switch(sType)

{

case ‘r’:

dst->rx +=p1;dst->ry +=p2;dst->rz +=p3;

if (dst->rx>360.0) dst->rx -= 360.0;

if (dst->ry>360.0) dst->ry -= 360.0;

if (dst->rz>360.0) dst->rz -= 360.0;

if (dst->rx<-360.0) dst->rx += 360.0;

if (dst->ry<-360.0) dst->ry += 360.0;

if (dst->rz<-360.0) dst->rz += 360.0;

break;

case ‘s’:

dst->sx +=p1;dst->sy +=p2;dst->sz +=p3;

break;

case ‘t’:

dst->dx +=p1;dst->dy +=p2;dst->dz +=p3;

break;

}

//for(vi=0;vi<vs;vi++)

// ApplyChanges(&dst->m_aObjects[vi],sType,p1,p2,p3);

}

void dcGScene::ApplyChanges(dcGObject *dst,UCHAR Mode)

{

int vi,vs;

vs = dst->m_aObjects.GetSize();

dst->m_ucMode = Mode;

for(vi=0;vi<vs;vi++)

ApplyChanges(&dst->m_aObjects[vi],Mode);

}

else

{

CFile inFile;

int dLast;

dLast = m_aDibs.GetSize();

m_aDibs.SetSize(dLast+1);

if (inFile.Open(vstr,CFile::modeRead))

{

if (!m_aDibs[dLast].cDib.Read(&inFile))

MessageBox(0,vstr,»Failed to read texture file»,0);

m_aDibs[dLast].name = sName;

m_aDibs[dLast].filename = vstr;

}

else

{

MessageBox(0,vstr,»Failed to find texture file»,0);

}

}

}

// взять слово из скрипта

CString dcGScene::getWord()

{

CString vres;

char vch;

vch = m_sScript[m_di];

while(m_di<m_size && (vch!=’ ‘ && vch!=0 && vch!=0x0d && vch!=0x0a))

{

vres += m_sScript[m_di];

m_di++;

if (m_di!=m_size) vch = m_sScript[m_di];

}

if (vch==13) {m_di++;m_di++;} // перевод каретки

if (m_di<m_size)

while(m_sScript[m_di]==’ ‘) m_di++; // скип пробелов

return vres;

}

// взять предложение из скрипта

CString dcGScene::getText()

{

CString vres;

char vch;

vch = m_sScript[m_di];

if (vch==’~’)

{

m_di++;

if (m_di!=m_size) vch = m_sScript[m_di];

while(m_di<m_size && (vch!=’~’ && vch!=0 /*vch!=0x0d && vch!=0x0a*/))

{

vres += m_sScript[m_di];

m_di++;

if (m_di!=m_size) vch = m_sScript[m_di];

}

}

m_di++;

//if (vch==13) {m_di++;m_di++;} // перевод каретки

if (m_di<m_size)

while(m_sScript[m_di]==’ ‘) m_di++; // скип пробелов

return vres;

}

Прогарммирование объектов

// dcGFactory.cpp: implementation of the dcGFactory class.

//

//////////////////////////////////////////////////////////////////////

#include «stdafx.h»

#include «dcGFactory.h»

#include «math.h»

#ifdef _DEBUG

#undef THIS_FILE

static char THIS_FILE[]=__FILE__;

#define new DEBUG_NEW

#endif

#define myPI 3.14159265358979

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

dcGFactory::dcGFactory()

{

}

dcGFactory::~dcGFactory()

{

}

float dcGFactory::Grad2Rad(float grad)

{

return (myPI*grad)/180.0;

}

void dcGFactory::crPlane(dcGObject &obj,int dSeg)

{

int vi,vj, i;

GLfloat x,y,dx,dy;

obj.m_prop[0] = (dSeg+1)*(dSeg+1);

obj.m_prop[1] = dSeg*dSeg*2;

obj.vertex = new GLfloat[obj.m_prop[0]*3];

obj.faces = new GLint[obj.m_prop[1]*3];

dx = dy = 1.0f / ((GLfloat)dSeg);

i = 0; y=0.0f;

for(vj=0;vj<=dSeg;vj++)

{

x = 0.0f;

for(vi=0;vi<=dSeg;vi++)

{

obj.vertex[i*3 ] = x;

obj.vertex[i*3+1] = y;

obj.vertex[i*3+2] = 0.0f;

x+=dx;

i++;

}

y+=dy;

}

i=0;

for(vj=0;vj<dSeg;vj++)

{

for (vi=0+vj*(dSeg+1);vi<(dSeg+vj*(dSeg+1));vi++)

{

obj.faces[i*3 ] = vi;

obj.faces[i*3+1] = vi+1;

obj.faces[i*3+2] = vi+dSeg+1;

//obj.faces[i*3 ] = vi;

//obj.faces[i*3+2] = vi+1;

//obj.faces[i*3+1] = vi+dSeg+1;

i++;

obj.faces[i*3 ] = vi+1;

obj.faces[i*3+1] = vi+dSeg+2;

obj.faces[i*3+2] = vi+dSeg+1;

//obj.faces[i*3 ] = vi+1;

//obj.faces[i*3+1] = vi+dSeg+2;

//obj.faces[i*3+2] = vi+dSeg+1;

i++;

}

}

//CString vstr;

//vstr.Format(«%d»,i);

//MessageBox(0,vstr,»info»,MB_OK);

}

void dcGFactory::crBox(dcGObject &obj,int dX,int dY,int dZ)

{

int i;

obj.m_prop[0] = 8;

obj.m_prop[1] = 12;

obj.vertex = new GLfloat[obj.m_prop[0]*3];

obj.faces = new GLint[obj.m_prop[1]*3];

for(i=0;i<2;i++)

{

obj.vertex[0 + 12*i] = 0 ;

obj.vertex[1 + 12*i] = 0 ;

obj.vertex[2 + 12*i] = dZ*i;

obj.vertex[3 + 12*i] = 0 ;

obj.vertex[4 + 12*i] = dY;

obj.vertex[5 + 12*i] = dZ*i;

obj.vertex[6 + 12*i] = dX;

obj.vertex[7 + 12*i] = dY;

obj.vertex[8 + 12*i] = dZ*i;

obj.vertex[9 + 12*i] = dX;

obj.vertex[10 + 12*i] = 0;

obj.vertex[11 + 12*i] = dZ*i;

}

i=0;

obj.faces[i]=0;obj.faces[i+1]=1;obj.faces[i+2]=2; i+=3; // bot

obj.faces[i]=0;obj.faces[i+1]=2;obj.faces[i+2]=3; i+=3;

obj.faces[i]=4;obj.faces[i+1]=6;obj.faces[i+2]=5; i+=3; // top

obj.faces[i]=4;obj.faces[i+1]=7;obj.faces[i+2]=6; i+=3;

obj.faces[i]=0;obj.faces[i+1]=5;obj.faces[i+2]=1; i+=3; // back

obj.faces[i]=0;obj.faces[i+1]=4;obj.faces[i+2]=5; i+=3;

obj.faces[i]=3;obj.faces[i+1]=2;obj.faces[i+2]=6; i+=3; // front

obj.faces[i]=3;obj.faces[i+1]=6;obj.faces[i+2]=7; i+=3;

obj.faces[i]=0;obj.faces[i+1]=7;obj.faces[i+2]=3; i+=3; // left

obj.faces[i]=0;obj.faces[i+1]=4;obj.faces[i+2]=7; i+=3;

obj.faces[i]=2;obj.faces[i+1]=1;obj.faces[i+2]=5; i+=3; // right

obj.faces[i]=2;obj.faces[i+1]=5;obj.faces[i+2]=6; i+=3;

}

void dcGFactory::crRegularPyramid(dcGObject &obj,float dR,float dH,int dSeg)

{

int i;

float vfAngleIter;

if (dSeg<3) dSeg = 3;

obj.m_prop[0] = dSeg+2;

obj.m_prop[1] = 2*dSeg;

obj.vertex = new GLfloat[obj.m_prop[0]*3];

obj.faces = new GLint[obj.m_prop[1]*3];

obj.vertex[0] = 0 ;obj.vertex[1] = 0 ;obj.vertex[2] = dH; // Apex

obj.vertex[(dSeg+1)*3]= 0;obj.vertex[(dSeg+1)*3+1]= 0; // \bottom

obj.vertex[(dSeg+1)*3+2]= 0; // /

vfAngleIter = Grad2Rad(360.0/((float)dSeg));

for(i=1;i<=dSeg;i++)

{

obj.vertex[i*3] = cos(vfAngleIter*(i-1))*dR;

obj.vertex[i*3+1] = sin(vfAngleIter*(i-1))*dR;

obj.vertex[i*3+2] = 0;

}

// side

for(i=0;i<dSeg-1;i++)

{

obj.faces[i*3 ] = 0; // apex

obj.faces[i*3+1] = i+1;

obj.faces[i*3+2] = i+2;

}

// conection side

obj.faces[i*3]=0;obj.faces[i*3+1]=i+1;obj.faces[i*3+2]=1; i++;

// bottom faces

for(;i<(2*dSeg)-1;i++)

{

obj.faces[i*3 ] = (dSeg+1); // apex

obj.faces[i*3+1] = i-dSeg+2;

obj.faces[i*3+2] = i-dSeg+1;

}

// conection side

obj.faces[i*3 ] = (dSeg+1);

obj.faces[i*3+1] = 1;

obj.faces[i*3+2] = dSeg;//i-dSeg+1;

}

void dcGFactory::crOctahedron(dcGObject &obj,float dR)

{

int i;

obj.m_prop[0] = 6;

obj.m_prop[1] = 8;

obj.vertex = new GLfloat[obj.m_prop[0]*3];

obj.faces = new GLint[obj.m_prop[1]*3];

i = 0;

obj.vertex[i] = 0 ;obj.vertex[i+1] = 0 ;obj.vertex[i+2] = dR; i+=3;

obj.vertex[i] = 0 ;obj.vertex[i+1] = dR ;obj.vertex[i+2] = 0 ; i+=3;

obj.vertex[i] = dR ;obj.vertex[i+1] = 0 ;obj.vertex[i+2] = 0 ; i+=3;

obj.vertex[i] = 0 ;obj.vertex[i+1] = -dR;obj.vertex[i+2] = 0 ; i+=3;

obj.vertex[i] = -dR;obj.vertex[i+1] = 0 ;obj.vertex[i+2] = 0 ; i+=3;

obj.vertex[i] = 0 ;obj.vertex[i+1] = 0 ;obj.vertex[i+2] = -dR;

i=0;

obj.faces[i]=0;obj.faces[i+1]=2;obj.faces[i+2]=1; i+=3;// top

obj.faces[i]=0;obj.faces[i+1]=3;obj.faces[i+2]=2; i+=3;

obj.faces[i]=0;obj.faces[i+1]=4;obj.faces[i+2]=3; i+=3;

obj.faces[i]=0;obj.faces[i+1]=1;obj.faces[i+2]=4; i+=3;

obj.faces[i]=5;obj.faces[i+1]=1;obj.faces[i+2]=2; i+=3;// bottom

obj.faces[i]=5;obj.faces[i+1]=4;obj.faces[i+2]=1; i+=3;

obj.faces[i]=5;obj.faces[i+1]=3;obj.faces[i+2]=4; i+=3;

obj.faces[i]=5;obj.faces[i+1]=2;obj.faces[i+2]=3; i+=3;

}

void dcGFactory::crRegularCylinder(dcGObject &obj,int dRbot,int dRtop,int dH,float fAngle,int dSeg)

//void dcGFactory::crRegularCylinder(dcGObject &obj,float dRbot,float dRtop,float dH,float fAngle,int dSeg)

{

int i,j;

float vfAngleIter, vfNaklonAngle;

float fCos_dH;

CString vstr;

//MessageBox(0,»dtrace. create prism geometry, step 0 — init»,»debug»,MB_OK);

if (dSeg<3) dSeg = 3;

obj.m_prop[0] = dSeg*2+2;

//obj.m_prop[1] = /*top+bottom*/ + /*side*/;

obj.m_prop[1] = dSeg*2 + dSeg*2;

obj.vertex = new GLfloat[obj.m_prop[0]*3];

obj.faces = new GLint[obj.m_prop[1]*3];

ZeroMemory(obj.vertex,sizeof(GLfloat)*obj.m_prop[0]*3);

vfAngleIter = Grad2Rad(360.0/((float)dSeg));

vfNaklonAngle = Grad2Rad(fAngle);

obj.vertex[0] = 0 ; obj.vertex[1] = 0; obj.vertex[2] = 0; // bottom

if ((float)fAngle==(float)90.0)

fCos_dH = 0.0;

else

fCos_dH = cos(vfNaklonAngle)*dH;

obj.vertex[(dSeg+1)*3] = fCos_dH;// \

obj.vertex[(dSeg+1)*3+1]= (GLfloat)0.0; // | Apex

obj.vertex[(dSeg+1)*3+2]= dH; // /

//vstr.Format(«fCos_dH = %f, (dSeg+1) = %d, obj.vY = %f»,fCos_dH,(dSeg+1),obj.vertex[(dSeg+1)*3+1]);

//MessageBox(0,vstr,»debug, RegularCylinder»,0);

// bottom vertexes

for(i=1;i<=dSeg;i++)

{

obj.vertex[i*3] = cos(vfAngleIter*(i-1))*dRbot;

obj.vertex[i*3+1] = sin(vfAngleIter*(i-1))*dRbot;

obj.vertex[i*3+2] = (GLfloat)0.0;

}

// top vertexes

// mr

i++;

//vstr.Format(«dtrace. create prism geometry,CURi = %d»,i);

//MessageBox(0,vstr,»debug»,MB_OK);

// —

j = 0;

for(;i<=2*dSeg+1;i++)

{

obj.vertex[i*3] = cos(vfAngleIter*j)*dRtop + fCos_dH;

obj.vertex[i*3+1] = sin(vfAngleIter*j)*dRtop;

obj.vertex[i*3+2] = dH;

j++;

}

//vstr.Format(«dtrace. create prism geometry,LASTi = %d, Vert= %d»,i,obj.m_prop[0]);

//MessageBox(0,vstr,»debug»,MB_OK);

//vstr.Format(«fCos_dH = %f, (dSeg+1) = %d, obj.vY = %f»,fCos_dH,(dSeg+1),obj.vertex[(dSeg+1)*3+1]);

//MessageBox(0,vstr,»debug, RegularCylinder»,0);

// Faces

// bottom side

j = 0;

for(i=1;i<dSeg;i++)

{

obj.faces[j ] = 0; // bottom

obj.faces[j+1] = i+1;

obj.faces[j+2] = i;

j+=3;

}

// conection side

obj.faces[j]=0;obj.faces[j+1]=1;obj.faces[j+2]=dSeg; j+=3;

// top side

for(i=1;i<dSeg;i++)

{

obj.faces[j] = dSeg+1; // top

obj.faces[j+1] = dSeg+i+1;

obj.faces[j+2] = dSeg+i+2;

j+=3;

}

// conection side

obj.faces[j]=dSeg+1;obj.faces[j+1]=2*dSeg+1;obj.faces[j+2]=dSeg+2; j+=3;

// sides

for(i=1;i<dSeg;i++)

{

obj.faces[j] = i;

obj.faces[j+1] = i+1;

obj.faces[j+2] = dSeg+i+1;

j+=3;

}

// conection side

obj.faces[j]=dSeg; obj.faces[j+1]=1;obj.faces[j+2]=2*dSeg+1; j+=3;

// second sides

for(i=1;i<dSeg;i++)

{

obj.faces[j] = dSeg+i+2;

obj.faces[j+1] = dSeg+i+1;

obj.faces[j+2] = i+1;

j+=3;

}

// conection side

obj.faces[j]=dSeg+2; obj.faces[j+1]=2*dSeg+1;obj.faces[j+2]=1; j+=3;

}

void dcGFactory::crIcosahedron(dcGObject &obj)

{

int i,j;

obj.m_prop[0] = 12;

obj.m_prop[1] = 20;

obj.vertex = new GLfloat[obj.m_prop[0]*3];

obj.faces = new GLint[obj.m_prop[1]*3];

//for(i=0;i<obj.m_prop[1]*3;i++) obj.faces[i]=0;

i = 0;

// top apex

obj.vertex[i] = 0 ;obj.vertex[i+1] = 0 ;obj.vertex[i+2] = (sqrt(5.0)*0.9)/2; i+=3;

// center

float vfGradus;

vfGradus = Grad2Rad(72.0);

for(j=0;j<5;j++)

{

obj.vertex[i] = cos(vfGradus*j)*0.9;

obj.vertex[i+1] = sin(vfGradus*j)*0.9;

obj.vertex[i+2] = 0.5*0.9 ;

i+=3;

}

for(j=0;j<5;j++)

{

obj.vertex[i] = cos(Grad2Rad(36)+vfGradus*j)*0.9;

obj.vertex[i+1] = sin(Grad2Rad(36)+vfGradus*j)*0.9;

obj.vertex[i+2] = -0.5*0.9 ;

i+=3;

}

// bottom apex

obj.vertex[i] = 0 ;obj.vertex[i+1] = 0 ;obj.vertex[i+2] = -(sqrt(5.0)*0.9)/2;

i=0;

// top

obj.faces[i]=0;obj.faces[i+1]=1;obj.faces[i+2]=2; i+=3;

obj.faces[i]=0;obj.faces[i+1]=2;obj.faces[i+2]=3; i+=3;

obj.faces[i]=0;obj.faces[i+1]=3;obj.faces[i+2]=4; i+=3;

obj.faces[i]=0;obj.faces[i+1]=4;obj.faces[i+2]=5; i+=3;

obj.faces[i]=0;obj.faces[i+1]=5;obj.faces[i+2]=1; i+=3;

// bottom

obj.faces[i]=11;obj.faces[i+1]=7;obj.faces[i+2]=6; i+=3;

obj.faces[i]=11;obj.faces[i+1]=8;obj.faces[i+2]=7; i+=3;

obj.faces[i]=11;obj.faces[i+1]=9;obj.faces[i+2]=8; i+=3;

obj.faces[i]=11;obj.faces[i+1]=10;obj.faces[i+2]=9; i+=3;

obj.faces[i]=11;obj.faces[i+1]=6;obj.faces[i+2]=10; i+=3;

// side

obj.faces[i]=1;obj.faces[i+1]=10;obj.faces[i+2]=6 ; i+=3;

obj.faces[i]=2;obj.faces[i+1]=6 ;obj.faces[i+2]=7 ; i+=3;

obj.faces[i]=3;obj.faces[i+1]=7 ;obj.faces[i+2]=8 ; i+=3;

obj.faces[i]=4;obj.faces[i+1]=8 ;obj.faces[i+2]=9 ; i+=3;

obj.faces[i]=5;obj.faces[i+1]=9 ;obj.faces[i+2]=10; i+=3;

//—

obj.faces[i]=6 ;obj.faces[i+1]=2;obj.faces[i+2]=1; i+=3;

obj.faces[i]=7 ;obj.faces[i+1]=3;obj.faces[i+2]=2; i+=3;

obj.faces[i]=8 ;obj.faces[i+1]=4;obj.faces[i+2]=3; i+=3;

obj.faces[i]=9 ;obj.faces[i+1]=5;obj.faces[i+2]=4; i+=3;

obj.faces[i]=10;obj.faces[i+1]=1;obj.faces[i+2]=5; i+=3;

}

obj.texvert[0 ] = 1.0;obj.texvert[1 ] = 1.0;

obj.texvert[2 ] = 1.0;obj.texvert[3 ] = 0.0;

obj.texvert[4 ] = 0.0;obj.texvert[5 ] = 0.0;

obj.texvert[6 ] = 0.0;obj.texvert[7 ] = 1.0;

obj.texvert[8 ] = 1.0;obj.texvert[9 ] = 1.0;

obj.texvert[10] = 1.0;obj.texvert[11] = 0.0;

obj.texvert[12] = 0.0;obj.texvert[13] = 0.0;

obj.texvert[14] = 0.0;obj.texvert[15] = 1.0;

obj.m_prop[2] = 1;

}

void dcGFactory::crRegularCylinderTex(dcGObject &obj,int dRbot,int dRtop,int dH,float fAngle,int dSeg)

{

int i,vi,vj;

float fTexXIter;

obj.texvert = new GLfloat[obj.m_prop[0]*2];

fTexXIter = 1.0/(float)dSeg;

obj.texvert[0] = 0.5;

obj.texvert[1] = 0.0; // bottom

obj.texvert[(dSeg+1)*2]= 0.5;

obj.texvert[(dSeg+1)*2+1]= 1.0;

i = 2;

for(vi=0;vi<dSeg;vi++)

{

obj.texvert[i ] = fTexXIter*vi;

obj.texvert[i+1] = 0.0; // bottom

i+=2;

}

i+=2;

for(vi=0;vi<dSeg;vi++)

{

obj.texvert[i ] = fTexXIter*vi;

obj.texvert[i+1] = 1.0; // top

i+=2;

}

obj.m_prop[2] = 1;

}

void dcGFactory::crHemisphereTex(dcGObject &obj,float fR,int dMer,int dPar)

{

int i,vi,vj;

float fTexXIter,fTexYIter;

obj.texvert = new GLfloat[obj.m_prop[0]*2];

fTexXIter = 1.0/(float)dMer;

fTexYIter = 1.0/(float)dPar;

obj.texvert[0 ] = 1.0;obj.texvert[1 ] = 0.5;

i = 2;

for(vi=0;vi<(dPar-1);vi++)

{

for(vj=0;vj<(dMer-1);vj++)

{

obj.texvert[i ] = 1.0-vi*fTexYIter;

obj.texvert[i+1] = vj*fTexXIter;

i+=2;

}

}

obj.m_prop[2] = 1;

}

Выполнение класса объекта

// dcGObject.cpp: implementation of the dcGObject class.

//

//////////////////////////////////////////////////////////////////////

#include «stdafx.h»

//#include «prb2.h»

#include «dcGObject.h»

#include «dcGScene.h»

#ifdef _DEBUG

#undef THIS_FILE

static char THIS_FILE[]=__FILE__;

#define new DEBUG_NEW

#endif

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

dcGObject::dcGObject()

{

vertex = 0;

faces = 0;

mask = 0;

texvert = 0;

// m_sObjName = 0;

hasTexture = 0;

dTexInvMode = GL_MODULATE;

m_prop[0] = m_prop[1] = m_prop[2] = 0;

#ifdef DCGOBJ_FLIP_AND_SHIFT

m_bFlip[0] = m_bFlip[1] = m_bFlip[2] = 0;

m_fShift[0] = m_fShift[1] = m_fShift[2] = 0;

#endif

IsVis = TRUE;

ResetProp(3);

}

dcGObject::dcGObject(dcGObject& src)

{

int vi, vs;

src.m_sObjName.Empty();

src.m_sObjName = m_sObjName;

src.m_ucMode = m_ucMode;

src.m_bType = m_bType;

src.m_fFparam1 = m_fFparam1;

src.RemoveArrays();

src.m_prop[0] = m_prop[0];src.m_prop[1] = m_prop[1];src.m_prop[2] = m_prop[2];

vs = m_prop[0]*3; src.vertex = new GLfloat[vs];

memcpy(src.vertex,vertex,vs*sizeof(GLfloat));

// for(vi=0;vi<vs;vi++) src.vertex[vi] = vertex[vi];

vs = m_prop[1]*3; src.faces = new GLint[vs];

memcpy(src.faces,faces,vs*sizeof(GLint));

// for(vi=0;vi<vs;vi++) src.faces[vi] = faces[vi];

//vs = sizeof(mask); src.mask = new GLubyte[vs];

//memcpy(src.mask,mask,vs);

//for(vi=0;vi<vs;vi++) src.mask[vi] = mask[vi];

src.color[0] = color[0];src.color[1] = color[1];src.color[2] = color[2];

src.color[3] = color[3];

src.dx = dx;src.dy = dy;src.dz = dz;

src.rx = rx;src.ry = ry;src.rz = rz;

src.sx = sx;src.sy = sy;src.sz = sz;

#ifdef DCGOBJ_FLIP_AND_SHIFT

memcpy(src.m_fShift,m_fShift,sizeof(GLfloat)*3);

memcpy(src.m_bFlip,m_bFlip,3);

#endif

src.hasMaterial = hasMaterial;

src.shininess = shininess;

for(vi=0;vi<4;vi++)

{

src.ambient [vi] = ambient [vi];

src.diffuse [vi] = diffuse [vi];

src.specular[vi] = specular[vi];

}

src.hasTexture = hasTexture;

src.dTexX = dTexX; src.dTexY = dTexY;

if (m_prop[2])

{

vs =m_prop[0]*2; src.texvert = new GLfloat[vs];

memcpy(src.texvert,texvert,vs*sizeof(GLfloat));

}

//for(vi=0;vi<vs;vi++) src.texvert[vi] = texvert[vi];

src.dTexIndex = dTexIndex;

src.dTexInvMode = dTexInvMode;

vs = m_aObjects.GetSize();

src.m_aObjects.SetSize(vs);

for(vi=0;vi<vs;vi++)

src.m_aObjects[vi] = m_aObjects[vi];

}

dcGObject::~dcGObject()

{

RemoveArrays();

}

/////////////////////////////////////////

// Implementation

/////////////////////////////////////////

void dcGObject::ComplexObj()

{

if (vertex) delete[] vertex;

if (faces) delete[] faces;

if (mask) delete[] mask;

if (texvert) delete[] texvert;

m_prop[0] = m_prop[1] = m_prop[2] = 0;

vertex = 0;

faces = 0;

mask = 0;

texvert = 0;

dx = dy = dz = 0.0;

rx = ry = rz = 0.0;

sx = sy = sz = 1.0;

hasMaterial = 0;

hasTexture = 0;

dTexInvMode = GL_MODULATE;

// if (m_sObjName) delete[] m_sObjName;

}

void dcGObject::RemoveArrays()

{

if (vertex) delete[] vertex;

if (faces) delete[] faces;

if (mask) delete[] mask;

if (texvert) delete[] texvert;

m_prop[0] = m_prop[1] = m_prop[2] = 0;

m_aObjects.RemoveAll();

vertex = 0;

faces = 0;

mask = 0;

texvert = 0;

dx = dy = dz = 0.0;

rx = ry = rz = 0.0;

sx = sy = sz = 1.0;

hasMaterial = 0;

hasTexture = 0;

dTexInvMode = GL_MODULATE;

m_ucMode = DCGOBJ_FACES;

// if (m_sObjName) delete[] m_sObjName;

}

void dcGObject::ResetProp(char bMatTrans)

{

if ((bMatTrans&0x01)==1)

{

px = py = pz = 0;

dx = dy = dz = 0;

rx = ry = rz = 0;

sx = sy = sz = 1.0f;

}

if ((bMatTrans&0x02)==2)

{

hasMaterial = FALSE;

shininess = 0;

for(int i=0;i<4;i++)

ambient[i] = diffuse[i] = specular[i] = 0;

}

}

void dcGObject::SetProp(int dVertex,int dFaces,int dTexVertex/* =0 */)

{

m_prop[0] = dVertex;

m_prop[1] = dFaces;

m_prop[2] = dTexVertex;

}

void dcGObject::Draw(UCHAR mode,LPVOID pScene)

{

int vs, vk;

glMatrixMode(GL_MODELVIEW);

if (mode<3) glLoadIdentity();

else mode -=3;

glTranslatef( px, py, pz); // begpivotPoint

//glTranslatef( dx, dy, dz);

glTranslatef( dx*((m_bFlip[0])?-1:1), dy*((m_bFlip[1])?-1:1), dz*((m_bFlip[2])?-1:1));

glRotatef( rx, 1.0f, 0.0f, 0.0f);

glRotatef( ry, 0.0f, 1.0f, 0.0f);

glRotatef( rz, 0.0f, 0.0f, 1.0f);

glTranslatef(-px,-py,-pz); // endpivotPoint

glScalef(sx,sy,sz);

#ifdef DCGOBJ_FLIP_AND_SHIFT

GLfloat vm[16];

ZeroMemory(vm,sizeof(GLfloat)*16);

vm[0] = (m_bFlip[0])?-1:1;

//vm[0] = 1;

vm[1] = m_fShift[1];

vm[2] = m_fShift[2];

vm[4] = m_fShift[0];

vm[5] = (m_bFlip[1])?-1:1;

//vm[5] = 1;

vm[6] = m_fShift[2];

vm[8] = m_fShift[0];

vm[9] = m_fShift[1];

vm[10] = (m_bFlip[2])?-1:1;

vm[15] = 1;

glMultMatrixf(vm);

#endif

vs = m_aObjects.GetSize();

for(vk=0;vk<vs;vk++)

{

glPushMatrix();

//m_aObjects[vk].SaveArrays(«temp.ar»);

m_aObjects[vk].Draw(mode+3,pScene);

glPopMatrix();

}

//SaveArrays(«object.ar»);

dcGScene* pScn1;

if (pScene!=0)

{

pScn1 = (dcGScene*) pScene;

}

// хёыш юс·хъЄ ёюёЄртэющ Єю фры№°х шфЄш эх шьххЄ ёьvёыр

if (vs!=0) goto stop_draw_obj;

// шэрўх — юс·хъЄ эх ёюёЄртэющ

if (hasMaterial==0)

{

glColor4ub(color[0],color[1],color[2],color[3]);

glEnable(GL_COLOR_MATERIAL);

}

else

{

glDisable(GL_COLOR_MATERIAL);

glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT ,ambient);

glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE ,diffuse);

glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,specular);

glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,shininess * 128.0);

}

if (!IsVis) goto EndVisible_label;

BYTE vbDrawMode;

switch(mode)

{

case 0:

vbDrawMode = m_ucMode&0x0f;

break;

case 1:

vbDrawMode = DCGOBJ_EDGES;

break;

}

switch(vbDrawMode)

{

case 0:

case DCGOBJ_FACES: // draw faces

{

int vi;

if (hasTexture==0 /*|| !(m_ucMode&DCGOBJ_TEXTURE)*/)

{

glDisable(GL_TEXTURE_2D);

for(vi=0;vi<m_prop[1];vi++)

{

glBegin(GL_TRIANGLES);

glVertex3f(vertex[faces[vi*3 ]*3],vertex[faces[vi*3 ]*3+1],vertex[faces[vi*3 ]*3+2]);

glVertex3f(vertex[faces[vi*3+1]*3],vertex[faces[vi*3+1]*3+1],vertex[faces[vi*3+1]*3+2]);

glVertex3f(vertex[faces[vi*3+2]*3],vertex[faces[vi*3+2]*3+1],vertex[faces[vi*3+2]*3+2]);

glEnd();

}

}

else

{

if (m_prop[2])

{

glEnable(GL_TEXTURE_2D);

glTexImage2D(GL_TEXTURE_2D,0,3,dTexX,dTexY,0,GL_RGB,

GL_UNSIGNED_BYTE,pScn1->m_aDibs[dTexIndex].cDib.m_lpImage);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, dTexInvMode);

for(vi=0;vi<m_prop[1];vi++)

{

glBegin(GL_TRIANGLES);

glTexCoord2d(texvert[faces[vi*3]*2],texvert[faces[vi*3]*2+1]);

glVertex3f(vertex[faces[vi*3 ]*3],vertex[faces[vi*3 ]*3+1],vertex[faces[vi*3 ]*3+2]);

glTexCoord2d(texvert[faces[vi*3+1]*2],texvert[faces[vi*3+1]*2+1]);

glVertex3f(vertex[faces[vi*3+1]*3],vertex[faces[vi*3+1]*3+1],vertex[faces[vi*3+1]*3+2]);

glTexCoord2d(texvert[faces[vi*3+2]*2],texvert[faces[vi*3+2]*2+1]);

glVertex3f(vertex[faces[vi*3+2]*3],vertex[faces[vi*3+2]*3+1],vertex[faces[vi*3+2]*3+2]);

glEnd();

}

}

}

}

break;

case DCGOBJ_EDGES:// draw edges

{

int vi;

for(vi=0;vi<m_prop[1];vi++)

{

glBegin(GL_LINE_LOOP);

glVertex3f(vertex[faces[vi*3 ]*3],vertex[faces[vi*3 ]*3+1],vertex[faces[vi*3 ]*3+2]);

glVertex3f(vertex[faces[vi*3+1]*3],vertex[faces[vi*3+1]*3+1],vertex[faces[vi*3+1]*3+2]);

glVertex3f(vertex[faces[vi*3+2]*3],vertex[faces[vi*3+2]*3+1],vertex[faces[vi*3+2]*3+2]);

glEnd();

}

}

break;

case DCGOBJ_VERTEX: // draw points

{

int vi;

for(vi=0;vi<m_prop[1];vi++)

{

glBegin(GL_POINTS);

glVertex3f(vertex[faces[vi*3 ]*3],vertex[faces[vi*3 ]*3+1],vertex[faces[vi*3 ]*3+2]);

glVertex3f(vertex[faces[vi*3+1]*3],vertex[faces[vi*3+1]*3+1],vertex[faces[vi*3+1]*3+2]);

glVertex3f(vertex[faces[vi*3+2]*3],vertex[faces[vi*3+2]*3+1],vertex[faces[vi*3+2]*3+2]);

glEnd();

}

}

break;

}

EndVisible_label:

if (hasMaterial==0) glDisable(GL_COLOR_MATERIAL);

else glEnable(GL_COLOR_MATERIAL);

stop_draw_obj:

;

}

void dcGObject::SaveArrays(const char *sFilename)

{

FILE *outf;

CString vstr;

char buf[512];

char odoa[2]={0x0d,0x0a};

int vi,vs;

outf = fopen(sFilename,«wb»);

if (!outf) goto error_label;

ZeroMemory(buf,512); strcpy(buf,m_sObjName);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

vstr.Format(«Prop.: vertex %d, faces %d, hasTexMap %d»,m_prop[0],m_prop[1],m_prop[2]);

ZeroMemory(buf,512); strcpy(buf,vstr);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

vstr.Format(«hasTexture %d, dTexIndex %d, Size %d x %d, InvMode %d»,hasTexture,dTexIndex,dTexX,dTexY,dTexInvMode);

ZeroMemory(buf,512); strcpy(buf,vstr);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

vstr.Format(«Mods.: Trans(%f; %f; %f) Rot(%f; %f; %f) Scale(%f; %f; %f)»,dx,dy,dz,rx,ry,rz,sx,sy,sz);

ZeroMemory(buf,512); strcpy(buf,vstr);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

vstr.Format(«Color R:%d G:%d B:%d A:%d»,color[0],color[1],color[2],color[3]);

ZeroMemory(buf,512); strcpy(buf,vstr);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

vstr.Format(«hasMaterial %d»,hasMaterial);

ZeroMemory(buf,512); strcpy(buf,vstr);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

vstr.Format(» Ambient R:%f G:%f B:%f»,ambient[0],ambient[1],ambient[2]);

ZeroMemory(buf,512); strcpy(buf,vstr);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

vstr.Format(» Diffuse R:%f G:%f B:%f»,diffuse[0],diffuse[1],diffuse[2]);

ZeroMemory(buf,512); strcpy(buf,vstr);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

vstr.Format(» Specular R:%f G:%f B:%f»,specular[0],specular[1],specular[2]);

ZeroMemory(buf,512); strcpy(buf,vstr);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

vstr.Format(» Shininess %f»,shininess);

ZeroMemory(buf,512); strcpy(buf,vstr);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

ZeroMemory(buf,512); strcpy(buf,»Vertex:»);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

vs = m_prop[0];

for(vi=0;vi<vs;vi++)

{

vstr.Format(«%f %f %f»,vertex[vi*3],vertex[vi*3+1],vertex[vi*3+2]);

ZeroMemory(buf,512); strcpy(buf,vstr);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

}

fwrite(&odoa,2,1,outf);

ZeroMemory(buf,512); strcpy(buf,»Faces:»);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

vs = m_prop[1];

for(vi=0;vi<vs;vi++)

{

vstr.Format(«%d %d %d»,faces[vi*3],faces[vi*3+1],faces[vi*3+2]);

ZeroMemory(buf,512); strcpy(buf,vstr);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

}

fwrite(&odoa,2,1,outf);

if (m_prop[2])

{

ZeroMemory(buf,512); strcpy(buf,»TextureMap:»);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

vs = m_prop[0];

for(vi=0;vi<vs;vi++)

{

vstr.Format(«%f %f»,texvert[vi*2],texvert[vi*2+1]);

ZeroMemory(buf,512); strcpy(buf,vstr);

fwrite(&buf,strlen(buf),1,outf);

fwrite(&odoa,2,1,outf);

}

}

fclose(outf);

error_label:

;

}

/////////////////////////////////////////////

/////////////////////////////////////////////

//

void dcGObject::operator =(dcGObject &src)

{

int vi, vs;

RemoveArrays();

//src.SaveArrays(«equal_op.ar»);

m_sObjName.Empty();

m_sObjName = src.m_sObjName;

m_ucMode = src.m_ucMode;

m_bType = src.m_bType;

m_fFparam1 = src.m_fFparam1;

m_prop[0] = src.m_prop[0];m_prop[1] = src.m_prop[1];m_prop[2] = src.m_prop[2];

vs = src.m_prop[0]*3; vertex = new GLfloat[vs];

/*CString vstr;

vstr.Format(«%d %d»,vs,src.m_prop[0]);

MessageBox(0,vstr,»sd»,MB_OK);*/

//for(int i=0;i<vs;i++)vertex[i] = src.vertex[i];

memcpy(vertex,src.vertex,vs*sizeof(GLfloat));

vs = src.m_prop[1]*3; faces = new GLint[vs];

//for(int j=0;j<vs;j++)faces[j] = src.faces[j];

memcpy(faces,src.faces,vs*sizeof(GLint));

//vs = sizeof(src.mask); mask = new GLubyte[vs];

//memcpy(mask,src.mask,vs);

//for(vi=0;vi<vs;vi++) src.mask[vi] = mask[vi];

color[0] = src.color[0];color[1] = src.color[1];color[2] = src.color[2];

color[3] = src.color[3];

dx = src.dx;dy = src.dy;dz = src.dz;

rx = src.rx;ry = src.ry;rz = src.rz;

sx = src.sx;sy = src.sy;sz = src.sz;

#ifdef DCGOBJ_FLIP_AND_SHIFT

memcpy(m_fShift,src.m_fShift,sizeof(GLfloat)*3);

memcpy(m_bFlip,src.m_bFlip,3);

#endif

hasMaterial = src.hasMaterial;

shininess = src.shininess;

for(vi=0;vi<4;vi++)

{

ambient [vi] = src.ambient [vi];

diffuse [vi] = src.diffuse [vi];

specular[vi] = src.specular[vi];

}

hasTexture = src.hasTexture;

dTexX = src.dTexX; dTexY = src.dTexY;

dTexIndex = src.dTexIndex;

dTexInvMode = src.dTexInvMode;

if (src.m_prop[2])

{

vs =src.m_prop[0]*2; texvert = new GLfloat[vs];

memcpy(texvert,src.texvert,vs*sizeof(GLfloat));

}

//for(int k=0;k<vs;k++)texvert[k] = src.texvert[k];

//SaveArrays(«equal_op1.ar»);

vs = src.m_aObjects.GetSize();

m_aObjects.SetSize(vs);

for(vi=0;vi<vs;vi++)

m_aObjects[vi] = src.m_aObjects[vi];

}