Копия проекта с 03
This commit is contained in:
119
src/Buffers.cpp
Normal file
119
src/Buffers.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "Buffers.h"
|
||||
|
||||
// Счетчики использований дескрипторов
|
||||
std::map<GLuint, GLuint> VAO::handler_count;
|
||||
std::map<GLuint, GLuint> BO::handler_count;
|
||||
|
||||
// Создает VAO и активирует его
|
||||
VAO::VAO()
|
||||
{
|
||||
glGenVertexArrays(1, &handler); // Генерация одного объекта массива вершин
|
||||
glBindVertexArray(handler); // Привязка для использования
|
||||
handler_count[handler] = 1; // Инициализация счетчика для дескриптора
|
||||
}
|
||||
|
||||
// Уничтожает VAO
|
||||
VAO::~VAO()
|
||||
{
|
||||
// Если дескриптор никем не используется - освободим его
|
||||
if (!--handler_count[handler])
|
||||
{
|
||||
glDeleteVertexArrays(1, &handler);
|
||||
handler_count.erase(handler); // Удаление из словаря
|
||||
}
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
VAO::VAO(const VAO & copy) : handler(copy.handler)
|
||||
{
|
||||
handler_count[handler]++;
|
||||
}
|
||||
|
||||
// Оператор присваивания
|
||||
VAO& VAO::operator=(const VAO & other)
|
||||
{
|
||||
// Если это разные дескрипторы
|
||||
if (handler != other.handler)
|
||||
{ // то следуюет удалить текущий перед заменой
|
||||
this->~VAO();
|
||||
handler = other.handler;
|
||||
handler_count[handler]++;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Активация VAO
|
||||
void VAO::use()
|
||||
{
|
||||
glBindVertexArray(handler); // Привязка VAO для использования
|
||||
}
|
||||
|
||||
// Деактивация активного VAO
|
||||
void VAO::disable()
|
||||
{
|
||||
glBindVertexArray(0); // Отключение VAO
|
||||
}
|
||||
|
||||
// Создает пустой буфер заданного типа
|
||||
BO::BO(BUFFER_TYPE t) : type(t)
|
||||
{
|
||||
glGenBuffers(1, &handler); // Генерация одного объекта буфера
|
||||
handler_count[handler] = 1;
|
||||
use(); // Привязка буфера
|
||||
}
|
||||
|
||||
// Создает и загружает туда данные
|
||||
BO::BO(BUFFER_TYPE t, const void *data, int size) : BO(t)
|
||||
{
|
||||
load(data, size);
|
||||
}
|
||||
|
||||
// Уничтожает буфер
|
||||
BO::~BO()
|
||||
{
|
||||
if (handler) // Если буфер был создан
|
||||
{
|
||||
// Если дескриптор никем не используется - освободим его
|
||||
if (!--handler_count[handler])
|
||||
{
|
||||
glDeleteBuffers(1, &handler);
|
||||
handler_count.erase(handler); // Удаление из словаря
|
||||
}
|
||||
handler = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
BO::BO(const BO & copy) : handler(copy.handler), type(copy.type)
|
||||
{
|
||||
handler_count[handler]++;
|
||||
}
|
||||
|
||||
// Оператор присваивания
|
||||
BO& BO::operator=(const BO & other)
|
||||
{
|
||||
// Если это разные дескрипторы
|
||||
if (handler != other.handler)
|
||||
{ // то следуюет удалить текущий перед заменой
|
||||
this->~BO();
|
||||
handler = other.handler;
|
||||
handler_count[handler]++;
|
||||
}
|
||||
// Изменим тип
|
||||
type = other.type;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Загрузка вершин в буфер
|
||||
void BO::load(const void *data, int size, GLuint mode)
|
||||
{
|
||||
use(); // Привязка буфера
|
||||
glBufferData(type, size, data, mode);
|
||||
}
|
||||
|
||||
void BO::use()
|
||||
{
|
||||
glBindBuffer(type, handler); // Привязка элементного буфера
|
||||
}
|
||||
183
src/Camera.cpp
Normal file
183
src/Camera.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
#include "Camera.h"
|
||||
|
||||
// Указатель на текущую используемую камеру
|
||||
Camera* Camera::p_current = NULL;
|
||||
|
||||
// Защищенный (protected) конструктор камеры без перспективы
|
||||
Camera::Camera(const glm::vec3 &pos, const glm::vec3 &initialRotation) : Node(NULL) // Пусть по умолчанию камера не относится к сцене
|
||||
{
|
||||
sensitivity = CAMERA_DEFAULT_SENSIVITY;
|
||||
position = pos; // задаем позицию
|
||||
// Определяем начальный поворот
|
||||
glm::quat rotationAroundX = glm::angleAxis( glm::radians(initialRotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
glm::quat rotationAroundY = glm::angleAxis(-glm::radians(initialRotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
glm::quat rotationAroundZ = glm::angleAxis( glm::radians(initialRotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
rotation = rotationAroundX * rotationAroundY * rotationAroundZ;
|
||||
// Признак изменения
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Конструктор камеры с проекцией перспективы
|
||||
Camera::Camera(float aspect, const glm::vec3 &position, const glm::vec3 &initialRotation, float fovy)
|
||||
: Camera(position, initialRotation)
|
||||
{
|
||||
setPerspective(fovy, aspect);
|
||||
}
|
||||
|
||||
// Конструктор ортографической камеры
|
||||
Camera::Camera(float width, float height, const glm::vec3 &position, const glm::vec3 &initialRotation)
|
||||
: Camera(position, initialRotation)
|
||||
{
|
||||
setOrtho(width, height);
|
||||
}
|
||||
|
||||
// Конструктор копирования камеры
|
||||
Camera::Camera(const Camera& copy)
|
||||
: Node(copy), projection(copy.projection), requiredRecalcVP(copy.requiredRecalcVP), sensitivity(copy.sensitivity)
|
||||
{
|
||||
// Если у оригинала не было изменений - перепишем матрицу вида-проекции
|
||||
if (!requiredRecalcVP)
|
||||
vp = copy.vp;
|
||||
}
|
||||
|
||||
// Оператор присваивания
|
||||
Camera& Camera::operator=(const Camera& other)
|
||||
{
|
||||
Node::operator=(other); // Вызов родительского оператора= для переноса узла
|
||||
|
||||
projection = other.projection;
|
||||
requiredRecalcVP = other.requiredRecalcVP;
|
||||
sensitivity = other.sensitivity;
|
||||
|
||||
// Если у оригинала не было изменений - перепишем матрицу вида-проекции
|
||||
if (!requiredRecalcVP)
|
||||
vp = other.vp;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Деструктор
|
||||
Camera::~Camera()
|
||||
{
|
||||
if (p_current == this)
|
||||
p_current = NULL;
|
||||
}
|
||||
|
||||
// Возвращает ссылку на константную матрицу проекции
|
||||
const glm::mat4& Camera::getProjection()
|
||||
{
|
||||
return projection;
|
||||
}
|
||||
|
||||
// Возвращает ссылку на константную матрицу вида
|
||||
const glm::mat4& Camera::getView()
|
||||
{
|
||||
recalcMatrices();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
// Возвращает ссылку на константную матрицу вида
|
||||
const glm::mat4& Camera::getVP()
|
||||
{
|
||||
recalcMatrices();
|
||||
|
||||
return vp;
|
||||
}
|
||||
|
||||
// Устанавливает заданную матрицу перспективы
|
||||
void Camera::setPerspective(float fovy, float aspect)
|
||||
{
|
||||
projection = glm::perspective(glm::radians(fovy), aspect, CAMERA_NEAR, CAMERA_FAR);
|
||||
requiredRecalcVP = true;
|
||||
}
|
||||
|
||||
// Устанавливает заданную ортографическую матрицу
|
||||
void Camera::setOrtho(float width, float height)
|
||||
{
|
||||
const float aspect = width / height;
|
||||
projection = glm::ortho(-1.0f, 1.0f, -1.0f/aspect, 1.0f/aspect, CAMERA_NEAR, CAMERA_FAR);
|
||||
requiredRecalcVP = true;
|
||||
}
|
||||
|
||||
// Изменяет чувствительность мыши
|
||||
void Camera::setSensitivity(float sens)
|
||||
{
|
||||
sensitivity = sens;
|
||||
}
|
||||
|
||||
// Возвращает чувствительность мыши
|
||||
const float& Camera::getSensitivity() const
|
||||
{
|
||||
return sensitivity;
|
||||
}
|
||||
|
||||
// Метод пересчета матрицы вида и произведения Вида*Проекции по необходимости, должен сбрасывать флаг changed
|
||||
void Camera::recalcMatrices()
|
||||
{
|
||||
if (changed || parent_changed)
|
||||
{
|
||||
glm::vec3 _position = position;
|
||||
glm::quat _rotation = rotation;
|
||||
if (parent) // Если есть родитель
|
||||
{
|
||||
glm::mat4 normalized_transform = parent->getTransformMatrix();
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
glm::vec3 axis = glm::vec3(normalized_transform[i]);
|
||||
normalized_transform[i] = glm::vec4(glm::normalize(axis), normalized_transform[i].w);
|
||||
}
|
||||
glm::vec4 tmp = normalized_transform * glm::vec4(_position, 1.0f);
|
||||
tmp /= tmp.w;
|
||||
_position = glm::vec3(tmp);
|
||||
_rotation = glm::quat_cast(normalized_transform) * _rotation;
|
||||
}
|
||||
glm::mat4 rotationMatrix = glm::mat4_cast(glm::conjugate(_rotation));
|
||||
glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0f), -_position);
|
||||
view = rotationMatrix * translationMatrix;
|
||||
requiredRecalcVP = true;
|
||||
}
|
||||
|
||||
Node::recalcMatrices();
|
||||
|
||||
if (requiredRecalcVP)
|
||||
{
|
||||
vp = projection * view;
|
||||
requiredRecalcVP = false; // Изменения применены
|
||||
}
|
||||
}
|
||||
|
||||
// Поворачивает камеру на dx и dy пикселей с учетом чувствительности
|
||||
void Camera::rotate(const glm::vec2 &xyOffset)
|
||||
{
|
||||
// xyOffset - сдвиги координат мыши, xyOffset.x означает поворот вокруг оси Y, а xyOffset.y - поворот вокруг оси X
|
||||
|
||||
// Вращение вокруг оси Y
|
||||
glm::quat qY = glm::angleAxis(-xyOffset.x * sensitivity, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
|
||||
// Вращение вокруг оси X
|
||||
glm::quat qX = glm::angleAxis(xyOffset.y * sensitivity, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
|
||||
// Сначала применяем вращение вокруг Y, затем вокруг X
|
||||
rotation = qY * rotation * qX;
|
||||
|
||||
changed = true;
|
||||
invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
|
||||
}
|
||||
|
||||
// Использование этой камеры как текущей
|
||||
void Camera::use()
|
||||
{
|
||||
p_current = this;
|
||||
}
|
||||
|
||||
// Ссылка на текущую используемую камеру
|
||||
Camera& Camera::current()
|
||||
{
|
||||
static Camera default_cam(800.0f/600.0f);
|
||||
|
||||
if (!p_current)
|
||||
return default_cam;
|
||||
else
|
||||
return *p_current;
|
||||
}
|
||||
306
src/Model.cpp
Normal file
306
src/Model.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
#include "Model.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// Конструктор с заданным родителем (по умолчанию NULL)
|
||||
Node::Node(Node* parent_) : parent(parent_), result_transform(1), parent_changed(false),
|
||||
position(0), rotation(1.0f, 0.0f, 0.0f, 0.0f), scale(1), changed(false), transform(1)
|
||||
{
|
||||
if (parent)
|
||||
{
|
||||
// Запишем себя в потомки
|
||||
parent->children.push_back(this);
|
||||
parent_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
Node::Node(const Node& copy): position(copy.position), rotation(copy.rotation), scale(copy.scale),
|
||||
parent(copy.parent), changed(copy.changed), parent_changed(copy.parent_changed), transform(1), result_transform(1)
|
||||
{
|
||||
// Запишем себя в потомки
|
||||
if (parent)
|
||||
parent->children.push_back(this);
|
||||
// Если у оригинала не было изменений - перепишем матрицу трансформации
|
||||
if (!changed)
|
||||
transform = copy.transform;
|
||||
// Если у родителя не было изменений для оригинала - перепишем результирующую матрицу трансформации
|
||||
if (!parent_changed)
|
||||
result_transform = copy.result_transform;
|
||||
}
|
||||
|
||||
Node::~Node()
|
||||
{
|
||||
setParent(NULL); // Удаляем себя из потомков
|
||||
// Сообщаем потомкам об удалении родителя
|
||||
for (Node* child : children)
|
||||
child->setParent(NULL);
|
||||
}
|
||||
|
||||
// Возвращает необходимость пересчета матрицы трансформации
|
||||
bool Node::isChanged()
|
||||
{
|
||||
return changed;
|
||||
}
|
||||
|
||||
// Константный доступ к позиции
|
||||
const glm::vec3& Node::c_position() const
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
// Константный доступ к повороту
|
||||
const glm::quat& Node::c_rotation() const
|
||||
{
|
||||
return rotation;
|
||||
}
|
||||
|
||||
// Константный доступ к масштабированию
|
||||
const glm::vec3& Node::c_scale() const
|
||||
{
|
||||
return scale;
|
||||
}
|
||||
|
||||
// Неконстантная ссылка для изменений позиции
|
||||
glm::vec3& Node::e_position()
|
||||
{
|
||||
changed = true; // Флаг о изменении
|
||||
invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
|
||||
return position;
|
||||
}
|
||||
|
||||
// Неконстантная ссылка для изменений поворота
|
||||
glm::quat& Node::e_rotation()
|
||||
{
|
||||
changed = true; // Флаг о изменении
|
||||
invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
|
||||
return rotation;
|
||||
}
|
||||
|
||||
// Неконстантная ссылка для изменений масштабирования
|
||||
glm::vec3& Node::e_scale()
|
||||
{
|
||||
changed = true; // Флаг о изменении
|
||||
invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
|
||||
return scale;
|
||||
}
|
||||
|
||||
// Возвращает матрицу трансформации модели
|
||||
const glm::mat4& Node::getTransformMatrix()
|
||||
{
|
||||
// Если требуется - пересчитаем матрицу
|
||||
recalcMatrices();
|
||||
|
||||
return result_transform;
|
||||
}
|
||||
|
||||
// Пересчет матрицы трансформации модели, если это требуется
|
||||
void Node::recalcMatrices()
|
||||
{
|
||||
// Если было изменение по векторам позиции, поворота и масштабирования
|
||||
if (changed)
|
||||
{
|
||||
transform = glm::mat4(1.0f);
|
||||
// Перемещение модели
|
||||
transform = glm::translate(transform, position);
|
||||
// Поворот модели
|
||||
transform = transform * glm::mat4_cast(rotation);
|
||||
// Масштабирование
|
||||
transform = glm::scale(transform, scale);
|
||||
}
|
||||
|
||||
// Если собственная или родительская матрицы менялись - необходимо пересчитать итоговую
|
||||
if (changed || parent_changed)
|
||||
{
|
||||
if (parent) // Если есть родитель
|
||||
result_transform = parent->getTransformMatrix() * transform;
|
||||
else // Если нет родителя
|
||||
result_transform = transform;
|
||||
|
||||
parent_changed = changed = false; // Изменения применены
|
||||
}
|
||||
}
|
||||
|
||||
// Проход потомков в глубину с изменением флага parent_changed
|
||||
void Node::invalidateParent()
|
||||
{
|
||||
// Цикл по потомкам
|
||||
for (Node* child : children)
|
||||
{
|
||||
child->parent_changed = true; // Флаг
|
||||
child->invalidateParent(); // Рекурсивный вызов для потомков выбранного потомка
|
||||
}
|
||||
}
|
||||
|
||||
// Устанавливает родителя для узла
|
||||
void Node::setParent(Node * parent)
|
||||
{
|
||||
// Если замена происходит на другого родителя
|
||||
if (parent != this->parent)
|
||||
{
|
||||
Node* tmp = parent;
|
||||
// Проверка на зацикливание об самого себя
|
||||
while (tmp)
|
||||
{
|
||||
if (tmp == this)
|
||||
return; // Можно выдать exception
|
||||
tmp = tmp->parent;
|
||||
}
|
||||
// Если есть старый родитель - удалим себя из его потомков
|
||||
if (this->parent)
|
||||
{
|
||||
// Поиск в списке родительских потомков
|
||||
auto position = std::find(this->parent->children.begin(), this->parent->children.end(), this);
|
||||
// Если итератор указывает в конец - ничего не найдено
|
||||
if (position != this->parent->children.end())
|
||||
this->parent->children.erase(position); // Само удаление
|
||||
}
|
||||
|
||||
this->parent = parent; // Заменяем указатель на родителя
|
||||
// Если родитель не NULL - добавляем себя в детей
|
||||
if (parent)
|
||||
parent->children.push_back(this);
|
||||
// В любом случае необходимо пересчитать собственную итоговую матрицу
|
||||
parent_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Возвращает указатель на родителя
|
||||
Node* Node::getParent()
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
// Возвращает ссылку на вектор дочерних узлов
|
||||
const std::vector<Node*>& Node::getChildren() const
|
||||
{
|
||||
return children;
|
||||
}
|
||||
|
||||
// Оператор присваивания
|
||||
Node& Node::operator=(const Node& other)
|
||||
{
|
||||
position = other.position;
|
||||
rotation = other.rotation;
|
||||
scale = other.scale;
|
||||
changed = other.changed;
|
||||
|
||||
if (!changed)
|
||||
transform = other.transform;
|
||||
|
||||
setParent(other.parent);
|
||||
|
||||
// Если у other флаг parent_changed == false, то можно переписать матрицу результата с него
|
||||
if (!other.parent_changed)
|
||||
{
|
||||
result_transform = other.result_transform;
|
||||
parent_changed = false; // Сбрасываем флаг после смены родителя
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Конструктор по умолчанию
|
||||
Model::Model(Node *parent) : Node(parent), verteces_count(0), first_index_byteOffset(0), indices_count(0),
|
||||
vertex_vbo(VERTEX), index_vbo(ELEMENT)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
Model::Model(const Model& copy) : Node(copy),
|
||||
vao(copy.vao),
|
||||
verteces_count(copy.verteces_count), first_index_byteOffset(copy.first_index_byteOffset), indices_count(copy.indices_count),
|
||||
vertex_vbo(copy.vertex_vbo), index_vbo(copy.index_vbo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Оператор присваивания
|
||||
Model& Model::operator=(const Model& other)
|
||||
{
|
||||
Node::operator=(other); // Явный вызов родительского оператора копирования
|
||||
|
||||
vao = other.vao;
|
||||
verteces_count = other.verteces_count;
|
||||
first_index_byteOffset = other.first_index_byteOffset;
|
||||
indices_count = other.indices_count;
|
||||
|
||||
vertex_vbo = other.vertex_vbo;
|
||||
index_vbo = other.index_vbo;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Model::~Model()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Вызов отрисовки
|
||||
void Model::render(const GLuint &model_uniform)
|
||||
{
|
||||
// Загрузим матрицу трансформации
|
||||
glUniformMatrix4fv(model_uniform, 1, GL_FALSE, &getTransformMatrix()[0][0]);
|
||||
|
||||
// Подключаем VAO
|
||||
vao.use();
|
||||
// Если есть индексы - рисуем с их использованием
|
||||
if (indices_count)
|
||||
{
|
||||
index_vbo.use();
|
||||
glDrawElements(GL_TRIANGLES, indices_count, GL_UNSIGNED_INT, (void*)(first_index_byteOffset));
|
||||
}
|
||||
// Если есть вершины - рисуем на основании массива вершин
|
||||
else if (verteces_count)
|
||||
glDrawArrays(GL_TRIANGLES, 0, verteces_count);
|
||||
}
|
||||
|
||||
// Функция для конфигурации атрибута вершинного буфера
|
||||
void vertex_attrib_config()
|
||||
{
|
||||
// Определим спецификацию атрибута
|
||||
glVertexAttribPointer( 0 // индекс атрибута, должен совпадать с Layout шейдера
|
||||
, 3 // количество компонент одного элемента
|
||||
, GL_FLOAT // тип
|
||||
, GL_FALSE // необходимость нормировать значения
|
||||
, 0 // шаг
|
||||
, (void *)0 // отступ с начала массива
|
||||
);
|
||||
// Включаем необходимый атрибут у выбранного VAO
|
||||
glEnableVertexAttribArray(0);
|
||||
}
|
||||
|
||||
// Загрузка вершин в буфер
|
||||
void Model::load_verteces(glm::vec3* verteces, GLuint count)
|
||||
{
|
||||
// Подключаем VAO и вершинный буфер
|
||||
vao.use();
|
||||
vertex_vbo.use();
|
||||
|
||||
// Загрузка вершин в память буфера
|
||||
vertex_vbo.load(verteces, sizeof(glm::vec3)*count);
|
||||
vertex_attrib_config();
|
||||
// Запоминаем количество вершин для отрисовки
|
||||
verteces_count = count;
|
||||
}
|
||||
|
||||
// Загрузка индексов в буфер
|
||||
void Model::load_indices(GLuint* indices, GLuint count)
|
||||
{
|
||||
// Подключаем VAO и индексный буфер
|
||||
vao.use();
|
||||
index_vbo.use();
|
||||
|
||||
// Загрузка вершин в память буфера
|
||||
index_vbo.load(indices, sizeof(GLuint)*count);
|
||||
// Запоминаем количество вершин для отрисовки
|
||||
indices_count = count;
|
||||
}
|
||||
|
||||
// Ограничение диапазона из буфера индексов
|
||||
void Model::set_index_range(size_t first_byteOffset, size_t count)
|
||||
{
|
||||
first_index_byteOffset = first_byteOffset;
|
||||
indices_count = count;
|
||||
}
|
||||
89
src/Scene.cpp
Normal file
89
src/Scene.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "Scene.h"
|
||||
|
||||
// Конструктор пустой сцены
|
||||
Scene::Scene()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
Scene::Scene(const Scene ©): root(copy.root),
|
||||
nodes(copy.nodes), models(copy.models), cameras(copy.cameras)
|
||||
{
|
||||
rebuld_tree(copy);
|
||||
}
|
||||
|
||||
// Оператор присваивания
|
||||
Scene& Scene::operator=(const Scene& other)
|
||||
{
|
||||
root = other.root;
|
||||
nodes = other.nodes;
|
||||
models = other.models;
|
||||
cameras = other.cameras;
|
||||
|
||||
rebuld_tree(other);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Рендер сцены
|
||||
void Scene::render(const GLuint &model_uniform)
|
||||
{
|
||||
for (auto & model : models)
|
||||
model.render(model_uniform);
|
||||
}
|
||||
|
||||
// Перестройка узлов выбранного списка
|
||||
template <class T>
|
||||
void Scene::rebuild_Nodes_list(T& nodes, const Scene& from)
|
||||
{
|
||||
for (auto it = nodes.begin(); it != nodes.end(); it++)
|
||||
{
|
||||
// Берем родителя, который указывает на оригинальный объект
|
||||
Node* parent = it->getParent();
|
||||
|
||||
// Если родитель - оригинальный корневой узел, то меняем на собственный корневой узел
|
||||
if (parent == &from.root)
|
||||
{
|
||||
it->setParent(&root);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Если можно привести к модели, то ищем родителя среди моделей
|
||||
if (dynamic_cast<Model*>(parent))
|
||||
move_parent(*it, from.models, this->models);
|
||||
else
|
||||
// Иначе проверяем на принадлежность к камерам
|
||||
if (dynamic_cast<Camera*>(parent))
|
||||
move_parent(*it, from.cameras, this->cameras);
|
||||
// Иначе это пустой узел
|
||||
else
|
||||
move_parent(*it, from.nodes, this->nodes);
|
||||
|
||||
// Не нашли родителя - значит он не часть этой сцены
|
||||
// и изменений по нему не требуется
|
||||
}
|
||||
}
|
||||
|
||||
// Сдвигает родителя узла между двумя списками при условии его принадлежности к оригинальному
|
||||
template <class T>
|
||||
void Scene::move_parent(Node& for_node, const std::list<T>& from_nodes, std::list<T>& this_nodes)
|
||||
{
|
||||
// Возьмем адрес родителя
|
||||
Node* parent = for_node.getParent();
|
||||
// Цикл по элементам списков для перемещения родителя
|
||||
// Списки в процессе копирования идеинтичные, вторая проверка не требуется
|
||||
for (auto it_from = from_nodes.begin(), it_this = this_nodes.begin(); it_from != from_nodes.end(); ++it_from, ++it_this)
|
||||
// Если адрес объекта, на который указывает итератор, совпадает с родителем - меняем родителя по второму итератору (it_this)
|
||||
if (&(*it_from) == parent)
|
||||
for_node.setParent(&(*it_this));
|
||||
}
|
||||
|
||||
// Перестройка дерева после копирования или присваивания
|
||||
void Scene::rebuld_tree(const Scene& from)
|
||||
{
|
||||
// Восстановим родителей в пустых узлах для копии
|
||||
rebuild_Nodes_list(nodes, from);
|
||||
rebuild_Nodes_list(models, from);
|
||||
rebuild_Nodes_list(cameras, from);
|
||||
}
|
||||
234
src/main.cpp
Executable file
234
src/main.cpp
Executable file
@@ -0,0 +1,234 @@
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GLM/glm.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "Camera.h"
|
||||
#include "Model.h"
|
||||
|
||||
#define WINDOW_WIDTH 800
|
||||
#define WINDOW_HEIGHT 600
|
||||
#define WINDOW_CAPTION "OPENGL notes on rekovalev.site"
|
||||
|
||||
// Функция-callback для изменения размеров буфера кадра в случае изменения размеров поверхности окна
|
||||
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||||
{
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
// Функция чтения шейдера из файла
|
||||
std::string readFile(const char* filename)
|
||||
{
|
||||
std::string text;
|
||||
std::ifstream file(filename, std::ios::in); // Открываем файл на чтение
|
||||
// Если файл доступен и успешно открыт
|
||||
if (file.is_open())
|
||||
{
|
||||
std::stringstream sstr; // Буфер для чтения
|
||||
sstr << file.rdbuf(); // Считываем файл
|
||||
text = sstr.str(); // Преобразуем буфер к строке
|
||||
file.close(); // Закрываем файл
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
// Функция для загрузки шейдеров
|
||||
// Принимает два адреса вершинного и фрагментного шейдеров
|
||||
// Возвращает дескриптор шейдерной программы
|
||||
GLuint LoadShaders(const char *vertex_file, const char *fragment_file)
|
||||
{
|
||||
// Создание дескрипторов вершинного и фрагментного шейдеров
|
||||
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
|
||||
GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
// Переменные под результат компиляции
|
||||
GLint result = GL_FALSE;
|
||||
int infoLogLength;
|
||||
|
||||
// Считываем текст вершинного шейдера
|
||||
std::string code = readFile(vertex_file);
|
||||
const char* pointer = code.c_str(); // Преобразование к указателю на const char, так как функция принимает массив си-строк
|
||||
|
||||
// Компиляция кода вершинного шейдера
|
||||
glShaderSource(vertexShaderID, 1, &pointer, NULL);
|
||||
glCompileShader(vertexShaderID);
|
||||
|
||||
// Проверка результата компиляции
|
||||
glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &result);
|
||||
glGetShaderiv(vertexShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
|
||||
if (infoLogLength > 0)
|
||||
{
|
||||
char* errorMessage = new char[infoLogLength + 1];
|
||||
glGetShaderInfoLog(vertexShaderID, infoLogLength, NULL, errorMessage);
|
||||
std::cout << errorMessage;
|
||||
delete[] errorMessage;
|
||||
}
|
||||
|
||||
// Считываем текст вершинного шейдера
|
||||
code = readFile(fragment_file);
|
||||
pointer = code.c_str(); // Преобразование к указателю на const char, так как функция принимает массив си-строк
|
||||
|
||||
// Компиляция кода фрагментного шейдера
|
||||
glShaderSource(fragmentShaderID, 1, &pointer, NULL);
|
||||
glCompileShader(fragmentShaderID);
|
||||
|
||||
// Проверка результата компиляции
|
||||
glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &result);
|
||||
glGetShaderiv(fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
|
||||
if (infoLogLength > 0)
|
||||
{
|
||||
char* errorMessage = new char[infoLogLength + 1];
|
||||
glGetShaderInfoLog(fragmentShaderID, infoLogLength, NULL, errorMessage);
|
||||
std::cout << errorMessage;
|
||||
delete[] errorMessage;
|
||||
}
|
||||
|
||||
// Привязка скомпилированных шейдеров
|
||||
GLuint programID = glCreateProgram();
|
||||
glAttachShader(programID, vertexShaderID);
|
||||
glAttachShader(programID, fragmentShaderID);
|
||||
glLinkProgram(programID);
|
||||
|
||||
// Проверка программы
|
||||
glGetProgramiv(programID, GL_LINK_STATUS, &result);
|
||||
glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength);
|
||||
if (infoLogLength > 0)
|
||||
{
|
||||
char* errorMessage = new char[infoLogLength + 1];
|
||||
glGetProgramInfoLog(programID, infoLogLength, NULL, errorMessage);
|
||||
std::cout << errorMessage;
|
||||
delete[] errorMessage;
|
||||
}
|
||||
|
||||
// Освобождение дескрипторов шейдеров
|
||||
glDeleteShader(vertexShaderID);
|
||||
glDeleteShader(fragmentShaderID);
|
||||
|
||||
return programID;
|
||||
}
|
||||
|
||||
|
||||
bool firstMouse = true;
|
||||
float lastX, lastY;
|
||||
|
||||
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
|
||||
{
|
||||
if (firstMouse)
|
||||
{
|
||||
lastX = xpos;
|
||||
lastY = ypos;
|
||||
firstMouse = false;
|
||||
}
|
||||
|
||||
glm::vec2 offset(xpos - lastX, lastY - ypos);
|
||||
lastX = xpos;
|
||||
lastY = ypos;
|
||||
|
||||
Camera::current().rotate(offset);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
GLFWwindow* window; // Указатель на окно GLFW3
|
||||
|
||||
// Инициализация GLFW3
|
||||
if (!glfwInit())
|
||||
{
|
||||
std::cout << "GLFW init error\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Завершение работы с GLFW3 перед выходом
|
||||
atexit(glfwTerminate);
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // Мажорная версия спецификаций OpenGL
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); // Минорная версия спецификаций OpenGL
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Контекст OpenGL, который поддерживает только основные функции
|
||||
|
||||
// Создание окна GLFW3 с заданными шириной, высотой и заголовком окна
|
||||
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_CAPTION, NULL, NULL);
|
||||
if (!window)
|
||||
{
|
||||
std::cout << "GLFW create window error\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Установка основного контекста окна
|
||||
glfwMakeContextCurrent(window);
|
||||
// Установка callback-функции для изменения размеров окна и буфера кадра
|
||||
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
||||
|
||||
glfwSwapInterval(1); // Вертикальная синхронизация
|
||||
|
||||
// Установка callback-функции для мыши и камеры
|
||||
glfwSetCursorPosCallback(window, mouse_callback);
|
||||
|
||||
// Загрузка функций OpenGL с помощью GLAD
|
||||
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
|
||||
{
|
||||
std::cout << "GLAD load GL error\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Компиляция шейдеров
|
||||
GLuint shaderProgram = LoadShaders("shaders/shader.vert", "shaders/shader.frag");
|
||||
// Активация шейдера
|
||||
glUseProgram(shaderProgram);
|
||||
|
||||
// Вершины прямоугольника
|
||||
glm::vec3 verticies[] = { {-0.5f, -0.5f, 0.0f}
|
||||
, { 0.5f, -0.5f, 0.0f}
|
||||
, { 0.5f, 0.5f, 0.0f}
|
||||
, {-0.5f, 0.5f, 0.0f}
|
||||
};
|
||||
// Модель прямоугольника
|
||||
Model rectangle;
|
||||
|
||||
// Загрузка вершин модели
|
||||
rectangle.load_verteces(verticies, sizeof(verticies)/sizeof(glm::vec3));
|
||||
|
||||
// индексы вершин
|
||||
GLuint indices[] = {0, 1, 2, 2, 3, 0};
|
||||
|
||||
// Загрузка индексов модели
|
||||
rectangle.load_indices(indices, sizeof(indices));
|
||||
|
||||
rectangle.e_position().z = 2;
|
||||
rectangle.e_rotation() = {0.733f, 0.462f, 0.191f, 0.462f};
|
||||
|
||||
// Установка цвета очистки буфера цвета
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
// Расположение Uniform-переменной
|
||||
GLuint vp_uniform = glGetUniformLocation(shaderProgram, "vp");
|
||||
GLuint model_uniform = glGetUniformLocation(shaderProgram, "model");
|
||||
|
||||
// Пока не произойдет событие запроса закрытия окна
|
||||
while(!glfwWindowShouldClose(window))
|
||||
{
|
||||
// Загрузим матрицу проекции*вида
|
||||
glUniformMatrix4fv(vp_uniform, 1, GL_FALSE, &Camera::current().getVP()[0][0]);
|
||||
|
||||
// Очистка буфера цвета
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Тут производится рендер
|
||||
rectangle.render(model_uniform);
|
||||
|
||||
// Представление содержимого буфера цепочки показа на окно
|
||||
glfwSwapBuffers(window);
|
||||
// Обработка системных событий
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
// Удаление шейдерной программы
|
||||
glDeleteProgram(shaderProgram);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user