04/src/Model.cpp

354 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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), texCoords_vbo(VERTEX)
{
}
// Конструктор копирования
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), texCoords_vbo(copy.texCoords_vbo),
texture_diffuse(copy.texture_diffuse)
{
}
// Оператор присваивания
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;
texCoords_vbo = other.texCoords_vbo;
texture_diffuse = other.texture_diffuse;
return *this;
}
Model::~Model()
{
}
// Вызов отрисовки
void Model::render(const GLuint &model_uniform)
{
// Загрузим матрицу трансформации
glUniformMatrix4fv(model_uniform, 1, GL_FALSE, &getTransformMatrix()[0][0]);
// Подключаем текстуры
texture_diffuse.use();
// Подключаем 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 texCoords_attrib_config()
{
// Определим спецификацию атрибута
glVertexAttribPointer( 1 // индекс атрибута, должен совпадать с Layout шейдера
, 2 // количество компонент одного элемента
, GL_FLOAT // тип
, GL_FALSE // необходимость нормировать значения
, 0 // шаг
, (void *)0 // отступ с начала массива
);
// Включаем необходимый атрибут у выбранного VAO
glEnableVertexAttribArray(1);
}
// Загрузка текстурных координат в буфер
void Model::load_texCoords(glm::vec2* texCoords, GLuint count)
{
// Подключаем VAO
vao.use();
texCoords_vbo.use();
// Загрузка вершин в память буфера
texCoords_vbo.load(texCoords, sizeof(glm::vec2)*count);
texCoords_attrib_config();
}
// Ограничение диапазона из буфера индексов
void Model::set_index_range(size_t first_byteOffset, size_t count)
{
first_index_byteOffset = first_byteOffset;
indices_count = count;
}
// Привязка текстуры к модели
void Model::set_texture(Texture& texture)
{
GLuint type = texture.getType();
switch(type)
{
case TEX_DIFFUSE:
texture_diffuse = texture;
break;
};
}