#ifndef glUnitH #define glUnitH #include #include #include #define _USE_MATH_DEFINES // разрешить константы, объявленные math.h, в частности значение M_PI #include // подключить к проекту lib-файлы (то же самое можно было сделать через свойства проекта) #pragma comment (lib, "opengl32.lib") #pragma comment (lib, "glu32.lib") // запретить некоторые раздрожающие предупреждения #pragma warning( disable: 4996 ) #pragma warning( disable: 4244 ) #pragma warning( disable: 4312 ) #pragma warning( disable: 4311 ) // 3D-вектор или 3D-точка typedef struct { float x,y,z; } VECTOR; // текстурная координата typedef struct { float u,v; } TEXCOORD; // цвет для 3D-графики typedef struct { float r,g,b,a; } COLOR3D; // Матрица пребразования 4x4. // Одна и та же память для хранения матрицы рассматривается либо как массив 4x4 (m[4][4]), // либо как 4 вектора rows.rowX, rows.rowY, rows.rowZ, rows.position // Пример работы с матрицей: // MATRIX A; // A.m[3][0] = 10.0f; A.m[3][1] = 20.0; // обращение как в матрице 4x4 ([строка][столбец]) // A.rows.position.x = 10.0; A.rows.position.y = 20.0; // обращение к той же памяти как к векторам typedef union { float m[4][4]; // как массив 4x4 // как 4 вектора struct { VECTOR rowX; float zero0; VECTOR rowY; float zero1; VECTOR rowZ; float zero2; VECTOR position; float one; } rows; } MATRIX; // предварительное объявление классов для последующей ссылки на эти классы class CTextureManager; class CMesh; class CObject3D; class CScene; // класс текстура class CTexture { public: CTextureManager *manager; // ссылка на менеджер текстур CTexture *next, *prev; // следующая и предыдущая текстура в списке GLuint handle; // дескриптор текстуры в памяти видеокарты char *name; // название текстуры (имя файла) CTexture(CTextureManager *texManager); // контструктор, texManager - менеджер текстур ~CTexture(); // декструктор void Bind(); // сделать текстуру текущей void SetName(const char *Name); // установить новое название текстуры bool Load(const char *fullFileName); // загрузить из указанного файла }; // класс менеджер текстур. Позволяет загружать текстуры без повторной загрузки одного и того же файла class CTextureManager { public: CTexture *textures; // указатель на текстуры char *path; // путь к папке, где лежат текстуры CTextureManager(); // конструктор ~CTextureManager(); // декстутор void Clear(); // удаляет все текстуры void SetPath(const char *Path); // установка папки, где лежат текстуры // получить указатель на текстуру с именем texName. Если такой текстуры нет, то загружает ее из файла. // возращает NULL, если файла текстуры в папке не существует или изображение из него не загружается CTexture *Get(const char *texName); }; // класс материал class CMaterial { public: COLOR3D ambientColor; // цвет в тени COLOR3D diffuseColor; // основной цвет COLOR3D specularColor; // цвет блика COLOR3D emmisionColor; // цвет самосвечения float glossiness; // параметр блеска bool twoSided; // материал двухсторонний CTexture *texture; // текстура (diffuseColor), если она есть у материала MATRIX matrix; // матрица преобразования текстуры CMaterial(); // конструктор void Bind(); // сделать материал текущим }; extern CMaterial defMaterial; // материал по умолчанию // класс Индекс-буфер class CIndexBuffer { public: CIndexBuffer *next; // следующий индекс-буфер текущего геометрического объекта (mesh) int count; // кол-во индексов int *indices; // указатель на массив индексов CMaterial *material; // указатель на материал, если есть GLuint handle; // дескриптор идекс-буфера, если он загружен в вилеркарту, или 0 CIndexBuffer(CMesh *mesh); // конструтор. mesh - геометрический объект, которому принадлежит. Вставляется в mesh автоматически ~CIndexBuffer(); // деструктор. Удаляет материал (но не текстуру). Не удаляет из mesh! void SetCount(int n); // устанавливает размер массива индексов, размещая память под него void UploadToGPU(); // загрузка данного индекс-буфера в память видеокарты с очисткой памяти на cpu void Render(CMesh *mesh); // рендер данного индекс-буфера. Вертекс-буфер должен быть уже установлен. }; // класс геометрический объект (mesh) class CMesh { public: CIndexBuffer *indexBuffers; // индекс-буферы, организованные в виде однонаправленной очереди int vCount; // количество вершин в вертекс-буфере VECTOR *vertices; // указатель на вертексы и на весь большой вертекс-буфер VECTOR *normals; // указатель на нормали (указатель на часть вертекст-буфера) TEXCOORD *texCoords; // указатель на текстурные координаты (указатель на часть вертекс-буфера) bool hasNormals, hasTexCoord; // если ли нормали и текстурные координаты COLOR3D wireColor; // цвет объекта (если нет материала) bool ccw; // порядок обхода вершин (по часовой или против часовой стрелки) GLuint handle; // дескриптор вертекс-буфера, если он загружен в видеокарту, или 0 CMesh(); // конструктор ~CMesh(); // декструктор. Удаляет данный класс и вложенные индекс-буферы // устанавливает количество вершин (n) в вертекс-буфере и размещает память под вертекс-буфер. // isNormals и isTexCoord соответственно если ли нормали и текстурные координаты. // Повторный вызов данной функции сохраняет старое содержимое буфера void SetVCount(int n, bool isNormals, bool isTexCoord); void UploadToGPU(); // загрузка на видеокарту вертекс-буфера и индекс-буферов данной mesh void Render(); // отрисовка данной mesh. Текущая матрица преобразования должна быть уже установлена }; // класс источник света class CLight { public: CObject3D *object; // указатель на объект, в который вложен данный источник света bool onOff; // включен (true) или выключен (false) COLOR3D color; // цвет float maxDistance; // максимальное расстояние, на которое светит свет, или -1, если светит до бесконечности float hotspot; // угол в радианах конуса горячего пятна света, или -1, если свет типа Omni float falloff; // угол в радианах конуса линейного спада до 0 конуса света CLight(CObject3D *obj); // конструктор. obj - объект в который вложен источник света // Рендер данного источника света. n - номер источника света OpenGL (от 0 до 7). // Матрица преобразования должна быть уже установлена void Render(int n); }; // класс камера class CCamera { public: CObject3D* object; // объект, в который вложена камера float fov; // угол обзора камеры по X // конструктор. obj - объект, в который вложена камера. Если у сцены нет активной камеры, то данная камера становится активной CCamera(CObject3D *obj); // декстуктор. Удаляет камеру со сцены, если данная камера является активной ~CCamera(); }; // класс 3D-объект. По сути система координат и носитель вложенных объектов (геометрии, источников света и камер). class CObject3D { public: // указатели на следующий, предыдущий, дочерний и родительские объекты иерархии (readonly) CObject3D *next,*prev,*child,*parent; char *name; // название объекта, данное в 3D Studio MAX // идентификатор объекта. Это не реальный указатель, а номер. // Удобно хранить и использовать в виде указателя на объект. CObject3D *id; MATRIX matrix; // локальная матрица преобразования (преобразование в родительский объект) MATRIX worldMatrix; // мировая матрица преобразования (преобразование в мировую систему координат) CMesh *mesh; // геометрический объект (mesh) или NULL CLight *light; // источник света или NULL CCamera *camera; // камера или NULL CObject3D(); // конструтор ~CObject3D(); // декструктор. Уничтожает данный объект и всю его иерархию void UploadToGPU(); // загрузка в память видеокарту данного объекта и всей его иерархии void SetName(const char *Name); // Установить название объекта // Устанить новый родительский объект, правильно вставляя его в иерархию объектов. // Объект сначала выходится из текущей иерархии вместе со своими дочерними объектами, а затем // вставляется в новую иерархию вместе с дочерними объектами. Если newParent=NULL то объект лишь // выводится из старой иерархии. Важно, что локальная матрица преобразования при этом не изменяется, // что приводит к скачку в мировой системе координат. Поэтому для иммитации захвата объекта и // присоединения его к другому родителю следует правильным образом изменить объекту локальную матрицу // преобразования, так, чтобы в попав в систему координат родителя объект сохранил те же координаты в // мировой системе координат. void SetParent(CObject3D *newParent); // Обновляет мировые матрицы преобразования worldMatrix текущего объекта и всей его дочерней иерархии. void UpdateTransform(); // Рекурсивно пробегает по дочерней иерархии данного объекта и рендерит источники света // Указатель n указывает на переменную, которая должна быть перед вызовом равна 0. void RenderLights(int *n); // Рекурсивно пробегает по дочерней иерархии и рендерит геометрические объекты void Render(); // находит объект по имени (Name) в дочерней иерархии данного объекта CObject3D *FindObject(const char *Name); // перемещает объекта на x, y, z вдоль осей текущего объекта void Translate(float x, float y, float z); // поворот объекта на (a) радиан вокруг оси X текущего объекта void RotateX(float a); // поворот объекта на (a) радиан вокруг оси Y текущего объекта void RotateY(float a); // поворот объекта на (a) радиан вокруг оси Z текущего объекта void RotateZ(float a); }; // Функция быстрого умножения матриц: // res = M1 x M2. Важно, чтобы последний столбей всех матрицы был (0,0,0,1) void MatrixMul(MATRIX &res, const MATRIX &M1, const MATRIX &M2); // Класс трехмерная сцена class CScene { public: HDC dc; // device context окна отображения трехмерной графики HGLRC rc; // render context трехмерной сцены int width, height; // длина и ширина поля для отображения графики COLOR3D backgroundColor; // цвет фона COLOR3D ambientLight; // рассеяный свет CObject3D *objects; // указатель на иерархию объектов CCamera *camera; // указатель на текущую камеру сцены CTextureManager textureManager; // менеджер текстур. CScene(); // конструктор ~CScene(); // декструктор. Закрывает 3D-графику и удаляет все текстуры и объекты сцены bool Init3D(HDC DC, int w, int h); // инициализирует 3D-графику. DC-device context устройства отображения, w,h - длина и ширина поля отображения void Resize(int w, int h); // изменяет размер области для отображения 3D-графики (w,h - длина и ширина). Применяется при изменении размеров окна void Close3D(); // закрывает 3D-графику (не трогая ни объекты ни текстуры) void ClearScene(); // очищает все объекты сцены и текстуры (подготовка к загрузке новой сцены) // загружает геометрию в память видеокарты (если это поддерживается видеокартой). Ускоряет последующую отрисовку сложной сцены void UploadToGPU(); void Clear(); // очистка текущего кадра цветом фона и очистка буфера глубины (Z-буфера) void Render(); // рендер кадра изображения void Swap(); // обмен видимой и активной страницы видеопамяти (см. технологию двойной буферизании) }; extern CScene *scene; // указатель на текущую сцену #endif