/*
GameEngine and Editor
by John Ryland
Copyright (c) 2023
*/
////////////////////////////////////////////////////////////////////////////////////
// Model
#include "Model.h"
#include <unordered_map>
#include <stdexcept>
#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/hash.hpp>
//#define TINYOBJLOADER_IMPLEMENTATION
#include <tiny_obj_loader.h>
using Vec2 = Vulkan::Attribute<glm::vec2, VK_FORMAT_R32G32_SFLOAT>;
using Vec3 = Vulkan::Attribute<glm::vec3, VK_FORMAT_R32G32B32_SFLOAT>;
struct Vertex
{
Vec3 m_position;
Vec3 m_color;
Vec2 m_textureCoordinate;
template <typename V>
void Visit(V& visitor) const
{
visitor.Visit(m_position);
visitor.Visit(m_color);
visitor.Visit(m_textureCoordinate);
}
};
namespace Render {
struct Model::ModelData
{
std::vector<Vertex> vertices;
std::vector<uint32_t> indices;
};
Model::Model()
: m_model(new ModelData)
{
}
Model::~Model()
{
delete m_model;
}
std::vector<VkVertexInputBindingDescription> Model::GetVertexBindingDescriptions()
{
return Vulkan::GetBindings<Vertex>();
}
std::vector<VkVertexInputAttributeDescription> Model::GetVertexAttributeDescriptions()
{
return Vulkan::GetAttributes<Vertex>();
}
void Model::Load(const char* fileName)
{
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string warn, err;
std::unordered_map<Vertex, uint32_t, Vulkan::Hash<Vertex>, Vulkan::IsEqual<Vertex>> uniqueVertices {};
if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, fileName))
{
throw std::runtime_error(warn + err);
}
for (const auto& shape : shapes)
{
for (const auto& index : shape.mesh.indices)
{
Vertex vertex {};
vertex.m_position.value = { attrib.vertices[3 * index.vertex_index + 0],
attrib.vertices[3 * index.vertex_index + 1],
attrib.vertices[3 * index.vertex_index + 2] };
vertex.m_textureCoordinate.value = { attrib.texcoords[2 * index.texcoord_index + 0],
1.0f - attrib.texcoords[2 * index.texcoord_index + 1] };
vertex.m_color.value = { 1.0f, 1.0f, 1.0f };
if (uniqueVertices.count(vertex) == 0)
{
uniqueVertices[vertex] = static_cast<uint32_t>(m_model->vertices.size());
m_model->vertices.push_back(vertex);
}
m_model->indices.push_back(uniqueVertices[vertex]);
}
}
}
void Model::GetVertexData(const uint8_t* &data, uint64_t& size)
{
data = (const uint8_t*)m_model->vertices.data();
size = (uint64_t)(sizeof(Vertex) * m_model->vertices.size());
}
void Model::GetIndexData(const uint8_t* &data, uint64_t& size)
{
data = (const uint8_t*)m_model->indices.data();
size = (uint64_t)(sizeof(uint32_t) * m_model->indices.size());
}
uint32_t Model::GetIndexCount()
{
return (uint32_t)m_model->indices.size();
}
} // Render namespace