-#include "BlockModel.hpp"
#include "Model.hpp"
-#include "OutlineModel.hpp"
+#include "Instance.hpp"
+#include "Skeletons.hpp"
-#include <iostream>
+#include "Shape.hpp"
+#include "ShapeRegistry.hpp"
+#include "../app/TextureIndex.hpp"
+#include "../graphics/DirectionalLighting.hpp"
+#include "../graphics/EntityMesh.hpp"
+
+#include <glm/gtx/quaternion.hpp>
namespace blank {
-Model::Model() noexcept
-: va(0)
-, handle{}
-, count(0) {
- glGenVertexArrays(1, &va);
- glGenBuffers(ATTRIB_COUNT, handle);
+Model::Model()
+: parent(nullptr)
+, node_mesh(nullptr)
+, id(0)
+, bounds{{ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }}
+, position(0.0f)
+, orientation(1.0f, 0.0f, 0.0f, 0.0f)
+, parts() {
+
}
-Model::~Model() noexcept {
- glDeleteBuffers(ATTRIB_COUNT, handle);
- glDeleteVertexArrays(1, &va);
+
+Model &Model::AddPart() {
+ parts.emplace_back();
+ parts.back().parent = this;
+ return parts.back();
}
-Model::Model(Model &&other) noexcept
-: va(other.va)
-, count(other.count) {
- other.va = 0;
- for (int i = 0; i < ATTRIB_COUNT; ++i) {
- handle[i] = other.handle[i];
- other.handle[i] = 0;
- }
+
+glm::mat4 Model::LocalTransform() const noexcept {
+ glm::mat4 transform(toMat4(orientation));
+ transform[3].x = position.x;
+ transform[3].y = position.y;
+ transform[3].z = position.z;
+ return transform;
}
-Model &Model::operator =(Model &&other) noexcept {
- std::swap(va, other.va);
- for (int i = 0; i < ATTRIB_COUNT; ++i) {
- std::swap(handle[i], other.handle[i]);
+glm::mat4 Model::GlobalTransform() const noexcept {
+ if (HasParent()) {
+ return Parent().GlobalTransform() * LocalTransform();
+ } else {
+ return LocalTransform();
}
- count = other.count;
- return *this;
}
-void Model::Update(const Buffer &buf) noexcept {
- glBindVertexArray(va);
- glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_VERTEX]);
- glBufferData(GL_ARRAY_BUFFER, buf.vertices.size() * sizeof(glm::vec3), buf.vertices.data(), GL_STATIC_DRAW);
- glEnableVertexAttribArray(ATTRIB_VERTEX);
- glVertexAttribPointer(
- ATTRIB_VERTEX, // location (for shader)
- 3, // size
- GL_FLOAT, // type
- GL_FALSE, // normalized
- 0, // stride
- nullptr // offset
- );
-
-#ifndef NDEBUG
- if (buf.colors.size() < buf.vertices.size()) {
- std::cerr << "Model: not enough colors!" << std::endl;
- }
-#endif
- glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_COLOR]);
- glBufferData(GL_ARRAY_BUFFER, buf.colors.size() * sizeof(glm::vec3), buf.colors.data(), GL_STATIC_DRAW);
- glEnableVertexAttribArray(ATTRIB_COLOR);
- glVertexAttribPointer(
- ATTRIB_COLOR, // location (for shader)
- 3, // size
- GL_FLOAT, // type
- GL_FALSE, // normalized
- 0, // stride
- nullptr // offset
- );
-
-#ifndef NDEBUG
- if (buf.normals.size() < buf.vertices.size()) {
- std::cerr << "Model: not enough normals!" << std::endl;
+
+void Model::Instantiate(Instance &inst) const {
+ inst.part_model = this;
+ inst.position = position;
+ inst.orientation = orientation;
+ inst.parts.clear();
+ inst.parts.reserve(parts.size());
+ for (const Model &part : parts) {
+ part.Instantiate(inst.AddPart());
}
-#endif
- glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_NORMAL]);
- glBufferData(GL_ARRAY_BUFFER, buf.normals.size() * sizeof(glm::vec3), buf.normals.data(), GL_STATIC_DRAW);
- glEnableVertexAttribArray(ATTRIB_NORMAL);
- glVertexAttribPointer(
- ATTRIB_NORMAL, // location (for shader)
- 3, // size
- GL_FLOAT, // type
- GL_FALSE, // normalized
- 0, // stride
- nullptr // offset
- );
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle[ATTRIB_INDEX]);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, buf.indices.size() * sizeof(Index), buf.indices.data(), GL_STATIC_DRAW);
- count = buf.indices.size();
}
-void Model::Draw() const noexcept {
- glBindVertexArray(va);
- glDrawElements(
- GL_TRIANGLES, // how
- count, // count
- GL_UNSIGNED_INT, // type
- nullptr // offset
- );
+Instance::Instance()
+: part_model(nullptr)
+, parent(nullptr)
+, position(0.0f)
+, orientation(1.0f, 0.0f, 0.0f, 0.0f)
+, parts() {
+
}
-BlockModel::BlockModel() noexcept
-: va(0)
-, handle{}
-, count(0) {
- glGenVertexArrays(1, &va);
- glGenBuffers(ATTRIB_COUNT, handle);
+Instance &Instance::AddPart() {
+ parts.emplace_back();
+ parts.back().parent = this;
+ return parts.back();
}
-BlockModel::~BlockModel() noexcept {
- glDeleteBuffers(ATTRIB_COUNT, handle);
- glDeleteVertexArrays(1, &va);
-}
-BlockModel::BlockModel(BlockModel &&other) noexcept
-: va(other.va)
-, count(other.count) {
- other.va = 0;
- for (int i = 0; i < ATTRIB_COUNT; ++i) {
- handle[i] = other.handle[i];
- other.handle[i] = 0;
- }
+glm::mat4 Instance::LocalTransform() const noexcept {
+ glm::mat4 transform(toMat4(orientation));
+ transform[3].x = position.x;
+ transform[3].y = position.y;
+ transform[3].z = position.z;
+ return transform;
}
-BlockModel &BlockModel::operator =(BlockModel &&other) noexcept {
- std::swap(va, other.va);
- for (int i = 0; i < ATTRIB_COUNT; ++i) {
- std::swap(handle[i], other.handle[i]);
+glm::mat4 Instance::GlobalTransform() const noexcept {
+ if (HasParent()) {
+ return Parent().GlobalTransform() * LocalTransform();
+ } else {
+ return LocalTransform();
}
- count = other.count;
- return *this;
}
-void BlockModel::Update(const Buffer &buf) noexcept {
- glBindVertexArray(va);
- glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_VERTEX]);
- glBufferData(GL_ARRAY_BUFFER, buf.vertices.size() * sizeof(glm::vec3), buf.vertices.data(), GL_STATIC_DRAW);
- glEnableVertexAttribArray(ATTRIB_VERTEX);
- glVertexAttribPointer(
- ATTRIB_VERTEX, // location (for shader)
- 3, // size
- GL_FLOAT, // type
- GL_FALSE, // normalized
- 0, // stride
- nullptr // offset
- );
-
-#ifndef NDEBUG
- if (buf.colors.size() < buf.vertices.size()) {
- std::cerr << "BlockModel: not enough colors!" << std::endl;
+
+void Instance::Render(const glm::mat4 &M, DirectionalLighting &prog) const {
+ glm::mat4 transform(M * LocalTransform());
+ if (part_model->HasNodeMesh()) {
+ prog.SetM(transform);
+ part_model->NodeMesh().Draw();
}
-#endif
- glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_COLOR]);
- glBufferData(GL_ARRAY_BUFFER, buf.colors.size() * sizeof(glm::vec3), buf.colors.data(), GL_STATIC_DRAW);
- glEnableVertexAttribArray(ATTRIB_COLOR);
- glVertexAttribPointer(
- ATTRIB_COLOR, // location (for shader)
- 3, // size
- GL_FLOAT, // type
- GL_FALSE, // normalized
- 0, // stride
- nullptr // offset
- );
-
-#ifndef NDEBUG
- if (buf.lights.size() < buf.vertices.size()) {
- std::cerr << "BlockModel: not enough lights!" << std::endl;
+ for (const Instance &part : parts) {
+ part.Render(transform, prog);
}
-#endif
- glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_LIGHT]);
- glBufferData(GL_ARRAY_BUFFER, buf.lights.size() * sizeof(float), buf.lights.data(), GL_STATIC_DRAW);
- glEnableVertexAttribArray(ATTRIB_LIGHT);
- glVertexAttribPointer(
- ATTRIB_LIGHT, // location (for shader)
- 1, // size
- GL_FLOAT, // type
- GL_FALSE, // normalized
- 0, // stride
- nullptr // offset
- );
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle[ATTRIB_INDEX]);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, buf.indices.size() * sizeof(Index), buf.indices.data(), GL_STATIC_DRAW);
- count = buf.indices.size();
}
-void BlockModel::Draw() const noexcept {
- glBindVertexArray(va);
- glDrawElements(
- GL_TRIANGLES, // how
- count, // count
- GL_UNSIGNED_INT, // type
- nullptr // offset
- );
-}
-
-OutlineModel::OutlineModel() noexcept
-: vertices()
-, colors()
-, indices()
-, va(0)
-, handle{}
-, dirty(false) {
- glGenVertexArrays(1, &va);
- glGenBuffers(ATTRIB_COUNT, handle);
-}
+Skeletons::Skeletons()
+: skeletons()
+, meshes() {
-OutlineModel::~OutlineModel() noexcept {
- glDeleteBuffers(ATTRIB_COUNT, handle);
- glDeleteVertexArrays(1, &va);
}
+Skeletons::~Skeletons() {
-void OutlineModel::Clear() noexcept {
- vertices.clear();
- colors.clear();
- indices.clear();
- Invalidate();
}
-void OutlineModel::Reserve(int v, int i) {
- vertices.reserve(v);
- colors.reserve(v);
- indices.reserve(i);
+void Skeletons::LoadHeadless() {
+ skeletons.clear();
+ skeletons.reserve(4);
+ AABB bounds{{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }};
+ {
+ skeletons.emplace_back(new Model);
+ skeletons[0]->ID(1);
+ skeletons[0]->Bounds(bounds);
+ }
+ {
+ skeletons.emplace_back(new Model);
+ skeletons[1]->ID(2);
+ skeletons[1]->Bounds(bounds);
+ }
+ {
+ skeletons.emplace_back(new Model);
+ skeletons[2]->ID(3);
+ skeletons[2]->Bounds(bounds);
+ }
+ {
+ skeletons.emplace_back(new Model);
+ skeletons[3]->ID(4);
+ skeletons[3]->Bounds(bounds);
+ }
}
-
-void OutlineModel::Update() noexcept {
- glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_VERTEX]);
- glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);
- glEnableVertexAttribArray(ATTRIB_VERTEX);
- glVertexAttribPointer(
- ATTRIB_VERTEX, // location (for shader)
- 3, // size
- GL_FLOAT, // type
- GL_FALSE, // normalized
- 0, // stride
- nullptr // offset
- );
-
-#ifndef NDEBUG
- if (colors.size() < vertices.size()) {
- std::cerr << "OutlineModel: not enough colors!" << std::endl;
- colors.resize(vertices.size(), { 1, 0, 1 });
+void Skeletons::Load(const ShapeRegistry &shapes, TextureIndex &tex_index) {
+ LoadHeadless();
+ meshes.resize(4);
+ const Shape &shape = shapes.Get("player_head_block");
+ EntityMesh::Buffer buf;
+ std::vector<float> tex_map;
+ tex_map.push_back(tex_index.GetID("rock-1"));
+ tex_map.push_back(tex_index.GetID("rock-face"));
+ buf.Reserve(shape.VertexCount(), shape.IndexCount());
+ {
+ shape.Fill(buf, tex_map);
+ buf.hsl_mods.resize(shape.VertexCount(), { 0.0f, 1.0f, 1.0f });
+ buf.rgb_mods.resize(shape.VertexCount(), { 1.0f, 1.0f, 0.0f });
+ meshes[0].Update(buf);
+ skeletons[0]->SetNodeMesh(&meshes[0]);
+ }
+ {
+ buf.Clear();
+ shape.Fill(buf, tex_map);
+ buf.hsl_mods.resize(shape.VertexCount(), { 0.0f, 1.0f, 1.0f });
+ buf.rgb_mods.resize(shape.VertexCount(), { 0.0f, 1.0f, 1.0f });
+ meshes[1].Update(buf);
+ skeletons[1]->SetNodeMesh(&meshes[1]);
+ }
+ {
+ buf.Clear();
+ shape.Fill(buf, tex_map);
+ buf.hsl_mods.resize(shape.VertexCount(), { 0.0f, 1.0f, 1.0f });
+ buf.rgb_mods.resize(shape.VertexCount(), { 1.0f, 0.0f, 1.0f });
+ meshes[2].Update(buf);
+ skeletons[2]->SetNodeMesh(&meshes[2]);
+ }
+ {
+ buf.Clear();
+ shape.Fill(buf, tex_map);
+ buf.hsl_mods.resize(shape.VertexCount(), { 0.0f, 1.0f, 1.0f });
+ buf.rgb_mods.resize(shape.VertexCount(), { 1.0f, 0.25f, 0.5f });
+ meshes[3].Update(buf);
+ skeletons[3]->SetNodeMesh(&meshes[3]);
}
-#endif
- glBindBuffer(GL_ARRAY_BUFFER, handle[ATTRIB_COLOR]);
- glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), colors.data(), GL_STATIC_DRAW);
- glEnableVertexAttribArray(ATTRIB_COLOR);
- glVertexAttribPointer(
- ATTRIB_COLOR, // location (for shader)
- 3, // size
- GL_FLOAT, // type
- GL_FALSE, // normalized
- 0, // stride
- nullptr // offset
- );
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle[ATTRIB_INDEX]);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(Index), indices.data(), GL_STATIC_DRAW);
-
- dirty = false;
}
-
-void OutlineModel::Draw() noexcept {
- glBindVertexArray(va);
-
- if (dirty) {
- Update();
+Model *Skeletons::ByID(std::uint16_t id) noexcept {
+ if (id == 0 || id > skeletons.size()) {
+ return nullptr;
+ } else {
+ return skeletons[id - 1].get();
}
+}
- glEnable(GL_LINE_SMOOTH);
- glLineWidth(2.0f);
-
- glDrawElements(
- GL_LINES, // how
- indices.size(), // count
- GL_UNSIGNED_SHORT, // type
- nullptr // offset
- );
+const Model *Skeletons::ByID(std::uint16_t id) const noexcept {
+ if (id == 0 || id > skeletons.size()) {
+ return nullptr;
+ } else {
+ return skeletons[id - 1].get();
+ }
}
}