Program Listing for File meshLoader.cpp

↰ Return to documentation for file (PrismEngine/src/meshLoader.cpp)

#include <unordered_map>
#include <iostream>
#include <tiny_obj_loader.h>
#include "meshLoader.h"
#include "logger.h"
#include "pathes.h"
#include "tangentCalculator.h"

prism::PGC::MeshData prism::PGC::L2::MeshLoader::loadObj(assets::MeshPath assetSpec, std::vector<Vertex>& vertices, std::vector<uint32_t>& indices) {
    assetSpec.path = prism::basePath / prism::modelsDir / assetSpec.path;

    tinyobj::attrib_t attrib;
    std::vector<tinyobj::shape_t> shapes;
    std::vector<tinyobj::material_t> materials;
    std::string warn, err;

    const std::string pathStr = assetSpec.path.generic_string();
    const std::string baseDir = assetSpec.path.parent_path().string();

    bool ok = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, pathStr.c_str(), baseDir.c_str(), true);
    if (!ok) logger::error(err.empty() ? "Failed to parse OBJ" : err);
    if (!warn.empty()) logger::warning("[OBJ] Warning: " + warn);

    prism::PGC::MeshData meshData;
    meshData.assetSpec = assetSpec;

    meshData.indexCount = meshData.vertexCount = 0;
    meshData.indexOffset = indices.size();
    meshData.vertexOffset = vertices.size();

    glm::mat4 transformMat = calculateMatrix(assetSpec.transform);
    glm::mat3 normalMat = glm::mat3(glm::transpose(glm::inverse(transformMat)));

    std::unordered_map<Vertex, uint32_t, VertexHasher> uniqueVertices;

    for (const auto& shape : shapes) {
        if (shape.name != assetSpec.linkName && assetSpec.linkName != "[all]") continue;

        for (const auto& index : shape.mesh.indices) {
            Vertex vertex{};

            vertex.pos = {
                attrib.vertices[3 * index.vertex_index + 0],
                attrib.vertices[3 * index.vertex_index + 1],
                attrib.vertices[3 * index.vertex_index + 2]
            };

            if (index.texcoord_index >= 0) {
                vertex.texCoord = {
                    attrib.texcoords[2 * index.texcoord_index + 0],
                    1.0f - attrib.texcoords[2 * index.texcoord_index + 1]
                };
            }
            else {
                vertex.texCoord = { 0.f, 0.f };
            }

            if (!attrib.colors.empty()) {
                vertex.color = { attrib.colors[3 * index.vertex_index + 0],
                                 attrib.colors[3 * index.vertex_index + 1],
                                 attrib.colors[3 * index.vertex_index + 2] };
            }
            else {
                vertex.color = { 1.f, 1.f, 1.f };
            }

            if (index.normal_index >= 0 && !attrib.normals.empty()) {
                vertex.normal = { attrib.normals[3 * index.normal_index + 0],
                                  attrib.normals[3 * index.normal_index + 1],
                                  attrib.normals[3 * index.normal_index + 2] };
            }
            else {
                vertex.normal = { 0.0f, 1.0f, 0.0f };
            }

            transformVertex(vertex, transformMat, normalMat);

            if (uniqueVertices.count(vertex) == 0) {
                uniqueVertices[vertex] = meshData.vertexCount;
                vertices.push_back(vertex);
                meshData.vertexCount++;
            }

            indices.push_back(uniqueVertices[vertex]);
            meshData.indexCount++;
        }
    }

    prism::PGC::L3::TangentCalculator::generateTangents(&vertices[meshData.vertexOffset], meshData.vertexCount, &indices[meshData.indexOffset], meshData.indexCount);

    return meshData;
}

prism::PGC::MeshData prism::PGC::L2::MeshLoader::loadCube(assets::MeshCube assetSpec, std::vector<Vertex>& vertices, std::vector<uint32_t>& indices)
{
    constexpr std::array<Vertex, 24> cubeVertices = {
        Vertex{{-0.5f, -0.5f,  0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}, { 0.0f,  0.0f,  1.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{ 0.5f, -0.5f,  0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}, { 0.0f,  0.0f,  1.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{ 0.5f,  0.5f,  0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}, { 0.0f,  0.0f,  1.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{-0.5f,  0.5f,  0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}, { 0.0f,  0.0f,  1.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},

        Vertex{{ 0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}, { 0.0f,  0.0f, -1.0f}, {-1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{-0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}, { 0.0f,  0.0f, -1.0f}, {-1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{-0.5f,  0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}, { 0.0f,  0.0f, -1.0f}, {-1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{ 0.5f,  0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}, { 0.0f,  0.0f, -1.0f}, {-1.0f,  0.0f,  0.0f, 1.0f}},

        Vertex{{ 0.5f, -0.5f,  0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}, { 1.0f,  0.0f,  0.0f}, { 0.0f,  0.0f, -1.0f, 1.0f}},
        Vertex{{ 0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}, { 1.0f,  0.0f,  0.0f}, { 0.0f,  0.0f, -1.0f, 1.0f}},
        Vertex{{ 0.5f,  0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}, { 1.0f,  0.0f,  0.0f}, { 0.0f,  0.0f, -1.0f, 1.0f}},
        Vertex{{ 0.5f,  0.5f,  0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}, { 1.0f,  0.0f,  0.0f}, { 0.0f,  0.0f, -1.0f, 1.0f}},

        Vertex{{-0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}, {-1.0f,  0.0f,  0.0f}, { 0.0f,  0.0f,  1.0f, 1.0f}},
        Vertex{{-0.5f, -0.5f,  0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}, {-1.0f,  0.0f,  0.0f}, { 0.0f,  0.0f,  1.0f, 1.0f}},
        Vertex{{-0.5f,  0.5f,  0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}, {-1.0f,  0.0f,  0.0f}, { 0.0f,  0.0f,  1.0f, 1.0f}},
        Vertex{{-0.5f,  0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}, {-1.0f,  0.0f,  0.0f}, { 0.0f,  0.0f,  1.0f, 1.0f}},

        Vertex{{-0.5f,  0.5f,  0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}, { 0.0f,  1.0f,  0.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{ 0.5f,  0.5f,  0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}, { 0.0f,  1.0f,  0.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{ 0.5f,  0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}, { 0.0f,  1.0f,  0.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{-0.5f,  0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}, { 0.0f,  1.0f,  0.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},

        Vertex{{-0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}, { 0.0f, -1.0f,  0.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{ 0.5f, -0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}, { 0.0f, -1.0f,  0.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{ 0.5f, -0.5f,  0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}, { 0.0f, -1.0f,  0.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{-0.5f, -0.5f,  0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}, { 0.0f, -1.0f,  0.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}}
    };

    constexpr std::array<uint32_t, 36> cubeIndices = {
        0, 1, 2,  2, 3, 0,
        4, 5, 6,  6, 7, 4,
        8, 9, 10, 10, 11, 8,
        12, 13, 14, 14, 15, 12,
        16, 17, 18, 18, 19, 16,
        20, 21, 22, 22, 23, 20
    };

    prism::PGC::MeshData meshData;
    meshData.assetSpec = assetSpec;
    meshData.vertexOffset = vertices.size();
    meshData.indexOffset = indices.size();
    meshData.vertexCount = cubeVertices.size();
    meshData.indexCount = cubeIndices.size();

    vertices.insert(vertices.end(), cubeVertices.begin(), cubeVertices.end());
    indices.insert(indices.end(), cubeIndices.begin(), cubeIndices.end());

    glm::mat4 transformMat = calculateMatrix(assetSpec.transform);
    glm::mat3 normalMat = glm::mat3(glm::transpose(glm::inverse(transformMat)));

    for (size_t i = meshData.vertexOffset; i < static_cast<unsigned long long>(meshData.vertexOffset) + meshData.vertexCount; i++) {
        transformVertex(vertices[i], transformMat, normalMat);
    }

    prism::PGC::L3::TangentCalculator::generateTangents(&vertices[meshData.vertexOffset], meshData.vertexCount, &indices[meshData.indexOffset], meshData.indexCount);
    return meshData;
}

prism::PGC::MeshData prism::PGC::L2::MeshLoader::loadPlane(assets::MeshPlane assetSpec, std::vector<Vertex>& vertices, std::vector<uint32_t>& indices) {
    constexpr std::array<Vertex, 4> planeVertices = {
        Vertex{{-0.5f,  0.0f,  0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 0.0f}, { 0.0f,  1.0f,  0.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{ 0.5f,  0.0f,  0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f}, { 0.0f,  1.0f,  0.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{ 0.5f,  0.0f, -0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}, { 0.0f,  1.0f,  0.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}},
        Vertex{{-0.5f,  0.0f, -0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}, { 0.0f,  1.0f,  0.0f}, { 1.0f,  0.0f,  0.0f, 1.0f}}
    };

    constexpr std::array<uint32_t, 6> planeIndices = {
        0, 1, 2,  2, 3, 0
    };

    prism::PGC::MeshData meshData;
    meshData.assetSpec = assetSpec;
    meshData.vertexOffset = vertices.size();
    meshData.indexOffset = indices.size();
    meshData.vertexCount = planeVertices.size();
    meshData.indexCount = planeIndices.size();

    vertices.insert(vertices.end(), planeVertices.begin(), planeVertices.end());
    indices.insert(indices.end(), planeIndices.begin(), planeIndices.end());

    glm::mat4 transformMat = calculateMatrix(assetSpec.transform);
    glm::mat3 normalMat = glm::mat3(glm::transpose(glm::inverse(transformMat)));

    for (size_t i = meshData.vertexOffset; i < static_cast<unsigned long long>(meshData.vertexOffset) + meshData.vertexCount; i++) {
        transformVertex(vertices[i], transformMat, normalMat);
    }

    prism::PGC::L3::TangentCalculator::generateTangents(&vertices[meshData.vertexOffset], meshData.vertexCount, &indices[meshData.indexOffset], meshData.indexCount);
    return meshData;
}

prism::PGC::MeshData prism::PGC::L2::MeshLoader::loadGrid(assets::MeshGrid assetSpec, std::vector<Vertex>& vertices, std::vector<uint32_t>& indices)
{
    prism::PGC::MeshData meshData;

    meshData.vertexCount = (assetSpec.subdivisionsX + 1) * (assetSpec.subdivisionsZ + 1);
    std::vector<Vertex> gridVertices;
    gridVertices.resize(meshData.vertexCount);
    for (size_t i = 0; i < meshData.vertexCount; i++)
    {
        size_t x = i % (assetSpec.subdivisionsX + 1);
        size_t z = i / (assetSpec.subdivisionsX + 1);

        float offsetX = (float)assetSpec.subdivisionsX / 2.0f;
        float offsetZ = (float)assetSpec.subdivisionsZ / 2.0f;

        gridVertices[i].pos.x = (float)x - offsetX;
        gridVertices[i].pos.y = 0;
        gridVertices[i].pos.z = (float)z - offsetZ;
        gridVertices[i].color = { 1.0f, 1.0f, 1.0f };
        gridVertices[i].texCoord.x = (float)x / assetSpec.repeatTextureX;
        gridVertices[i].texCoord.y = (float)z / assetSpec.repeatTextureZ;
        gridVertices[i].normal.x = 0.f;
        gridVertices[i].normal.y = 1.f;
        gridVertices[i].normal.z = 0.f;

    }

    meshData.indexCount = assetSpec.subdivisionsX * assetSpec.subdivisionsZ * 6;
    std::vector<uint32_t> gridIndices;
    gridIndices.resize(meshData.indexCount);

    size_t index_offset = 0;
    for (size_t z = 0; z < assetSpec.subdivisionsZ; z++)
    {
        for (size_t x = 0; x < assetSpec.subdivisionsX; x++)
        {
            uint32_t top_left = z * (assetSpec.subdivisionsX + 1) + x;
            uint32_t top_right = top_left + 1;
            uint32_t bottom_left = (z + 1) * (assetSpec.subdivisionsX + 1) + x;
            uint32_t bottom_right = bottom_left + 1;

            gridIndices[index_offset++] = top_left;
            gridIndices[index_offset++] = bottom_left;
            gridIndices[index_offset++] = top_right;

            gridIndices[index_offset++] = top_right;
            gridIndices[index_offset++] = bottom_left;
            gridIndices[index_offset++] = bottom_right;
        }
    }

    meshData.vertexOffset = vertices.size();
    meshData.indexOffset = indices.size();

    vertices.insert(vertices.end(), gridVertices.begin(), gridVertices.end());
    indices.insert(indices.end(), gridIndices.begin(), gridIndices.end());

    glm::mat4 transformMat = calculateMatrix(assetSpec.transform);
    glm::mat3 normalMat = glm::mat3(glm::transpose(glm::inverse(transformMat)));

    for (size_t i = meshData.vertexOffset; i < static_cast<unsigned long long>(meshData.vertexOffset) + meshData.vertexCount; i++) {
        transformVertex(vertices[i], transformMat, normalMat);
    }

    prism::PGC::L3::TangentCalculator::generateTangents(&vertices[meshData.vertexOffset], meshData.vertexCount, &indices[meshData.indexOffset], meshData.indexCount);
    return meshData;
}

prism::PGC::MeshData prism::PGC::L2::MeshLoader::loadIcoSphere(assets::MeshIcoSphere assetSpec, std::vector<Vertex>& vertices, std::vector<uint32_t>& indices)
{
    prism::PGC::MeshData meshData;
    meshData.assetSpec = assetSpec;

    meshData.vertexOffset = vertices.size();
    meshData.indexOffset = indices.size();

    const float t = (1.0f + std::sqrt(5.0f)) / 2.0f;

    std::vector<glm::vec3> icoPositions = {
        glm::normalize(glm::vec3(-1.0f,  t,  0.0f)),
        glm::normalize(glm::vec3(1.0f,  t,  0.0f)),
        glm::normalize(glm::vec3(-1.0f, -t,  0.0f)),
        glm::normalize(glm::vec3(1.0f, -t,  0.0f)),
        glm::normalize(glm::vec3(0.0f, -1.0f,  t)),
        glm::normalize(glm::vec3(0.0f,  1.0f,  t)),
        glm::normalize(glm::vec3(0.0f, -1.0f, -t)),
        glm::normalize(glm::vec3(0.0f,  1.0f, -t)),
        glm::normalize(glm::vec3(t,  0.0f, -1.0f)),
        glm::normalize(glm::vec3(t,  0.0f,  1.0f)),
        glm::normalize(glm::vec3(-t,  0.0f, -1.0f)),
        glm::normalize(glm::vec3(-t,  0.0f,  1.0f))
    };

    std::vector<std::array<uint32_t, 3>> triangles = {
        {0, 11, 5}, {0, 5, 1}, {0, 1, 7}, {0, 7, 10}, {0, 10, 11},
        {1, 5, 9}, {5, 11, 4}, {11, 10, 2}, {10, 7, 6}, {7, 1, 8},
        {3, 9, 4}, {3, 4, 2}, {3, 2, 6}, {3, 6, 8}, {3, 8, 9},
        {4, 9, 5}, {2, 4, 11}, {6, 2, 10}, {8, 6, 7}, {9, 8, 1}
    };

    std::map<uint64_t, uint32_t> middlePointCache;

    auto getMiddlePoint = [&](uint32_t p1, uint32_t p2) -> uint32_t
        {
            uint64_t key = (std::min(p1, p2) * 100000ULL) + std::max(p1, p2);
            auto it = middlePointCache.find(key);
            if (it != middlePointCache.end()) {
                return it->second;
            }

            glm::vec3 mid = glm::normalize((icoPositions[p1] + icoPositions[p2]) * 0.5f);
            uint32_t newIndex = static_cast<uint32_t>(icoPositions.size());
            icoPositions.push_back(mid);
            middlePointCache[key] = newIndex;
            return newIndex;
        };


    for (uint16_t level = 0; level < assetSpec.subdivisions; level++)
    {
        std::vector<std::array<uint32_t, 3>> newTriangles;
        newTriangles.reserve(triangles.size() * 4);

        for (const auto& tri : triangles)
        {
            uint32_t a = tri[0], b = tri[1], c = tri[2];
            uint32_t ab = getMiddlePoint(a, b);
            uint32_t bc = getMiddlePoint(b, c);
            uint32_t ca = getMiddlePoint(c, a);

            newTriangles.push_back({ a, ab, ca });
            newTriangles.push_back({ b, bc, ab });
            newTriangles.push_back({ c, ca, bc });
            newTriangles.push_back({ ab, bc, ca });
        }
        triangles = std::move(newTriangles);
    }

    meshData.vertexCount = static_cast<uint32_t>(icoPositions.size());
    vertices.reserve(vertices.size() + meshData.vertexCount);

    for (const auto& pos : icoPositions)
    {
        Vertex v{};
        v.pos = pos;
        v.normal = pos;

        float u = 0.5f + std::atan2(pos.z, pos.x) / (2.0f * glm::pi<float>());
        float vCoord = 0.5f - std::asin(pos.y) / glm::pi<float>();
        v.texCoord = { u, vCoord };

        v.color = { 1.0f, 1.0f, 1.0f };
        vertices.push_back(v);
    }

    meshData.indexCount = static_cast<uint32_t>(triangles.size() * 3);
    indices.reserve(indices.size() + meshData.indexCount);

    for (const auto& tri : triangles)
    {
        indices.push_back(meshData.vertexOffset + tri[0]);
        indices.push_back(meshData.vertexOffset + tri[1]);
        indices.push_back(meshData.vertexOffset + tri[2]);
    }

    glm::mat4 transformMat = calculateMatrix(assetSpec.transform);
    glm::mat3 normalMat = glm::mat3(glm::transpose(glm::inverse(transformMat)));

    for (size_t i = meshData.vertexOffset; i < meshData.vertexOffset + meshData.vertexCount; i++) transformVertex(vertices[i], transformMat, normalMat);


    prism::PGC::L3::TangentCalculator::generateTangents(&vertices[meshData.vertexOffset], meshData.vertexCount, &indices[meshData.indexOffset], meshData.indexCount);

    return meshData;
}

prism::PGC::MeshData prism::PGC::L2::MeshLoader::loadUvSphere(assets::MeshUvSphere assetSpec, std::vector<Vertex>& vertices, std::vector<uint32_t>& indices)
{
    prism::PGC::MeshData meshData;
    meshData.assetSpec = assetSpec;

    const uint32_t stacks = assetSpec.subdivisionsHoriz;
    const uint32_t slices = assetSpec.subdivisionsVert;

    meshData.vertexCount = (stacks + 1) * (slices + 1);
    meshData.indexCount = stacks * slices * 6;

    meshData.vertexOffset = vertices.size();
    meshData.indexOffset = indices.size();

    vertices.reserve(vertices.size() + meshData.vertexCount);
    indices.reserve(indices.size() + meshData.indexCount);

    const float pi = glm::pi<float>();
    const float twoPi = 2.0f * pi;

    for (uint32_t i = 0; i <= stacks; i++)
    {
        float phi = pi * static_cast<float>(i) / static_cast<float>(stacks);
        float sinPhi = std::sin(phi);
        float cosPhi = std::cos(phi);

        for (uint32_t j = 0; j <= slices; j++)
        {
            float theta = twoPi * static_cast<float>(j) / static_cast<float>(slices);
            float sinTheta = std::sin(theta);
            float cosTheta = std::cos(theta);

            Vertex v{};
            v.pos.x = sinPhi * cosTheta;
            v.pos.y = cosPhi;
            v.pos.z = sinPhi * sinTheta;

            v.normal = v.pos;

            v.texCoord.x = static_cast<float>(j) / static_cast<float>(slices);
            v.texCoord.y = static_cast<float>(i) / static_cast<float>(stacks);

            v.color = { 1.0f, 1.0f, 1.0f };

            vertices.push_back(v);
        }
    }


    for (uint32_t i = 0; i < stacks; i++)
    {
        for (uint32_t j = 0; j < slices; j++)
        {
            uint32_t first = meshData.vertexOffset + i * (slices + 1) + j;
            uint32_t second = first + slices + 1;

            if (i != 0)
            {
                indices.push_back(first);
                indices.push_back(first + 1);
                indices.push_back(second);
            }
            if (i != stacks - 1)
            {
                indices.push_back(first + 1);
                indices.push_back(second + 1);
                indices.push_back(second);
            }
        }
    }

    meshData.indexCount = static_cast<uint32_t>(indices.size() - meshData.indexOffset);

    glm::mat4 transformMat = calculateMatrix(assetSpec.transform);
    glm::mat3 normalMat = glm::mat3(glm::transpose(glm::inverse(transformMat)));

    for (size_t i = meshData.vertexOffset; i < meshData.vertexOffset + meshData.vertexCount; i++) transformVertex(vertices[i], transformMat, normalMat);


    prism::PGC::L3::TangentCalculator::generateTangents(&vertices[meshData.vertexOffset], meshData.vertexCount, &indices[meshData.indexOffset], meshData.indexCount);

    return meshData;
}

void prism::PGC::L2::MeshLoader::transformVertex(prism::PGC::Vertex& vertex, const glm::mat4& transformMat, const glm::mat3& normalMat)
{
    glm::vec4 posHomogeneous = transformMat * glm::vec4(vertex.pos, 1.0f);
    vertex.pos = glm::vec3(posHomogeneous) / posHomogeneous.w;
    vertex.normal = glm::normalize(normalMat * vertex.normal);
}

glm::mat4 prism::PGC::L2::MeshLoader::calculateMatrix(prism::PGC::MeshTransform transform)
{
    glm::mat4 transformMat = glm::mat4(1.0f);
    transformMat = glm::translate(transformMat, transform.position);
    transformMat = transformMat * glm::mat4_cast(transform.rotation);
    transformMat = glm::scale(transformMat, transform.scale);
    return transformMat;
}