From 5163d01f46d5c7e082b84d3cd3d94bd007b89025 Mon Sep 17 00:00:00 2001
From: Sebastian Gaida <gaida@ca-digit.com>
Date: Fri, 16 Jul 2021 12:54:52 +0200
Subject: [PATCH] [#87] add meshlet header to scene module

---
 modules/scene/CMakeLists.txt                 |   2 +
 modules/scene/include/vkcv/scene/Meshlet.hpp | 161 +++++++++++++++++++
 2 files changed, 163 insertions(+)
 create mode 100644 modules/scene/include/vkcv/scene/Meshlet.hpp

diff --git a/modules/scene/CMakeLists.txt b/modules/scene/CMakeLists.txt
index 9aa76883..1898f883 100644
--- a/modules/scene/CMakeLists.txt
+++ b/modules/scene/CMakeLists.txt
@@ -21,6 +21,8 @@ set(vkcv_scene_sources
 		
 		${vkcv_scene_include}/vkcv/scene/Mesh.hpp
 		${vkcv_scene_source}/vkcv/scene/Mesh.cpp
+
+		${vkcv_scene_include}/vkcv/scene/Meshlet.hpp
 		
 		${vkcv_scene_include}/vkcv/scene/Node.hpp
 		${vkcv_scene_source}/vkcv/scene/Node.cpp
diff --git a/modules/scene/include/vkcv/scene/Meshlet.hpp b/modules/scene/include/vkcv/scene/Meshlet.hpp
new file mode 100644
index 00000000..654419cf
--- /dev/null
+++ b/modules/scene/include/vkcv/scene/Meshlet.hpp
@@ -0,0 +1,161 @@
+#pragma once
+
+#include <vector>
+#include <Map>
+#include <glm/glm.hpp>
+
+namespace vkcv::scene {
+
+    struct Vertex {
+        glm::vec3   position;
+        float       padding0;
+        glm::vec3   normal;
+        float       padding1;
+    };
+
+    struct Meshlet {
+        uint32_t vertexOffset;
+        uint32_t vertexCount;
+        uint32_t indexOffset;
+        uint32_t indexCount;
+    };
+
+    struct MeshShaderModelData {
+        std::vector<Vertex>     vertices;
+        std::vector<uint32_t>   localIndices;
+        std::vector<Meshlet>    meshlets;
+    };
+
+    std::vector<Vertex> convertToVertices(
+            const std::vector<uint8_t>&         vertexData,
+            const uint64_t                      vertexCount,
+            const vkcv::asset::VertexAttribute& positionAttribute,
+            const vkcv::asset::VertexAttribute& normalAttribute) {
+
+        assert(positionAttribute.type   == vkcv::asset::PrimitiveType::POSITION);
+        assert(normalAttribute.type     == vkcv::asset::PrimitiveType::NORMAL);
+
+        std::vector<Vertex> vertices;
+        vertices.reserve(vertexCount);
+
+        const size_t positionStepSize   = positionAttribute.stride == 0 ? sizeof(glm::vec3) : positionAttribute.stride;
+        const size_t normalStepSize     = normalAttribute.stride   == 0 ? sizeof(glm::vec3) : normalAttribute.stride;
+
+        for (int i = 0; i < vertexCount; i++) {
+            Vertex v;
+
+            const size_t positionOffset = positionAttribute.offset  + positionStepSize  * i;
+            const size_t normalOffset   = normalAttribute.offset    + normalStepSize    * i;
+
+            v.position  = *reinterpret_cast<const glm::vec3*>(&(vertexData[positionOffset]));
+            v.normal    = *reinterpret_cast<const glm::vec3*>(&(vertexData[normalOffset]));
+            vertices.push_back(v);
+        }
+        return vertices;
+    }
+
+    MeshShaderModelData createMeshShaderModelData(
+            const std::vector<Vertex>&      inVertices,
+            const std::vector<uint32_t>&    inIndices) {
+
+        MeshShaderModelData data;
+        size_t currentIndex = 0;
+
+        const size_t maxVerticesPerMeshlet = 64;
+        const size_t maxIndicesPerMeshlet  = 126 * 3;
+
+        bool indicesAreLeft = true;
+
+        while (indicesAreLeft) {
+            Meshlet meshlet;
+
+            meshlet.indexCount  = 0;
+            meshlet.vertexCount = 0;
+
+            meshlet.indexOffset  = data.localIndices.size();
+            meshlet.vertexOffset = data.vertices.size();
+
+            std::map<uint32_t, uint32_t> globalToLocalIndexMap;
+            std::vector<uint32_t> globalIndicesOrdered;
+
+            while (true) {
+
+                indicesAreLeft = currentIndex + 1 <= inIndices.size();
+                if (!indicesAreLeft) {
+                    break;
+                }
+
+                bool enoughSpaceForIndices = meshlet.indexCount + 3 < maxIndicesPerMeshlet;
+                if (!enoughSpaceForIndices) {
+                    break;
+                }
+
+                size_t vertexCountToAdd = 0;
+                for (int i = 0; i < 3; i++) {
+                    const uint32_t globalIndex = inIndices[currentIndex + i];
+                    const bool containsVertex  = globalToLocalIndexMap.find(globalIndex) != globalToLocalIndexMap.end();
+                    if (!containsVertex) {
+                        vertexCountToAdd++;
+                    }
+                }
+
+                bool enoughSpaceForVertices = meshlet.vertexCount + vertexCountToAdd < maxVerticesPerMeshlet;
+                if (!enoughSpaceForVertices) {
+                    break;
+                }
+
+                for (int i = 0; i < 3; i++) {
+                    const uint32_t globalIndex = inIndices[currentIndex + i];
+
+                    uint32_t localIndex;
+                    const bool indexAlreadyExists = globalToLocalIndexMap.find(globalIndex) != globalToLocalIndexMap.end();
+                    if (indexAlreadyExists) {
+                        localIndex = globalToLocalIndexMap[globalIndex];
+                    }
+                    else {
+                        localIndex = globalToLocalIndexMap.size();
+                        globalToLocalIndexMap[globalIndex] = localIndex;
+                        globalIndicesOrdered.push_back(globalIndex);
+                    }
+
+                    data.localIndices.push_back(localIndex);
+                }
+
+                meshlet.indexCount  += 3;
+                currentIndex        += 3;
+                meshlet.vertexCount += vertexCountToAdd;
+            }
+
+            for (const uint32_t globalIndex : globalIndicesOrdered) {
+                const Vertex v = inVertices[globalIndex];
+                data.vertices.push_back(v);
+            }
+
+            data.meshlets.push_back(meshlet);
+        }
+
+        return data;
+    }
+
+    std::vector<uint32_t> assetLoaderIndicesTo32BitIndices(const std::vector<uint8_t>& indexData, vkcv::asset::IndexType indexType) {
+        std::vector<uint32_t> indices;
+        if (indexType == vkcv::asset::IndexType::UINT16) {
+            for (int i = 0; i < indexData.size(); i += 2) {
+                const uint16_t index16Bit = *reinterpret_cast<const uint16_t*>(&(indexData[i]));
+                const uint32_t index32Bit = static_cast<uint32_t>(index16Bit);
+                indices.push_back(index32Bit);
+            }
+        }
+        else if (indexType == vkcv::asset::IndexType::UINT32) {
+            for (int i = 0; i < indexData.size(); i += 4) {
+                const uint32_t index32Bit = *reinterpret_cast<const uint32_t*>(&(indexData[i]));
+                indices.push_back(index32Bit);
+            }
+        }
+        else {
+            vkcv_log(vkcv::LogLevel::ERROR, "Unsupported index type");
+        }
+        return indices;
+    }
+
+}
\ No newline at end of file
-- 
GitLab