From 7115acab8748f1a6d8561593fe7d5e6cfc32cb76 Mon Sep 17 00:00:00 2001 From: bailwillharr Date: Tue, 12 Dec 2023 09:56:37 +0000 Subject: [PATCH] get gltf mesh loading half done --- CMakeLists.txt | 6 +- include/scene_manager.h | 2 +- src/imgui/imgui_impl_vulkan.h | 2 +- src/libs/mikktspace.c | 12 ++-- src/util/gltf_loader.cpp | 111 ++++++++++++++++++++++++++++++++-- test/CMakeLists.txt | 2 +- test/src/game.cpp | 2 +- 7 files changed, 120 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d0fe4eb..e2b83e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ option(ENGINE_BUILD_TEST "Compile the test program" ON) SET(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo") -project(engine LANGUAGES CXX +project(engine LANGUAGES CXX C VERSION "0.1.0" ) @@ -120,7 +120,7 @@ set_property(TARGET ${PROJECT_NAME} PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_EXTENSIONS OFF) -set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99) +set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11) set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD_REQUIRED ON) set_property(TARGET ${PROJECT_NAME} PROPERTY C_EXTENSIONS OFF) @@ -129,7 +129,7 @@ if (MSVC) target_compile_options(${PROJECT_NAME} PRIVATE /MP) target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS) else() - target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror -pedantic) + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -pedantic) endif() target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/include/scene_manager.h b/include/scene_manager.h index 4c484b2..2f7df02 100644 --- a/include/scene_manager.h +++ b/include/scene_manager.h @@ -36,7 +36,7 @@ class SceneManager { } ++index; } - if (index >= scenes_.size()) { + if (static_cast(index) >= scenes_.size()) { throw std::runtime_error("Failed to find active scene!"); } else { diff --git a/src/imgui/imgui_impl_vulkan.h b/src/imgui/imgui_impl_vulkan.h index cbf025b..e81ea48 100644 --- a/src/imgui/imgui_impl_vulkan.h +++ b/src/imgui/imgui_impl_vulkan.h @@ -40,7 +40,7 @@ #if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES) && !defined(VK_NO_PROTOTYPES) #define VK_NO_PROTOTYPES #endif -#include "volk/volk.h" +#include "volk.h" // Initialization data, for ImGui_ImplVulkan_Init() // [Please zero-clear before use!] diff --git a/src/libs/mikktspace.c b/src/libs/mikktspace.c index 0342ae0..5259a10 100644 --- a/src/libs/mikktspace.c +++ b/src/libs/mikktspace.c @@ -728,7 +728,8 @@ static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) { - int iNumUniqueVerts = 0, t=0, i=0; + // int iNumUniqueVerts = 0; + int t=0, i=0; for (t=0; t& arr) return mat; } -static void CreateNodes(engine::Scene& app_scene, const tg::Scene& gl_scene, const tg::Model& gl_model, engine::Entity parent_entity, - const tg::Node& node) +static void CreateNodes(engine::Scene& app_scene, const tg::Scene& gl_scene, const tg::Model& gl_model, engine::Entity parent_entity, const tg::Node& node) { static int node_uuid = 0; @@ -68,9 +67,111 @@ static void CreateNodes(engine::Scene& app_scene, const tg::Scene& gl_scene, con if (node.mesh >= 0) { const tg::Mesh& mesh = gl_model.meshes.at(node.mesh); - const tg::Primitive& prim = mesh.primitives.front(); - const tg::Accessor& indices_accessor = gl_model.accessors.at(prim.indices); - const tg::BufferView& indices_bufferview = gl_model.bufferViews.at(indices_accessor.bufferView); + const tg::Primitive& prim = mesh.primitives.front(); // required + if (prim.mode != TINYGLTF_MODE_TRIANGLES) throw std::runtime_error("glTF loader only supports triangles!"); + + const tg::Accessor& indices_accessor = gl_model.accessors.at(prim.indices); // not required. TODO: handle no indices + size_t indices_int_size = 0; + if (indices_accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) indices_int_size = 1; + if (indices_accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) indices_int_size = 2; + if (indices_accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) indices_int_size = 4; + if (indices_int_size == 0) throw std::runtime_error("GLTF parse error!"); + const tg::BufferView& indices_bufferview = gl_model.bufferViews.at(indices_accessor.bufferView); // required for TG + const size_t indices_byteoffset = indices_accessor.byteOffset + indices_bufferview.byteOffset; + const tg::Buffer& indices_buffer = gl_model.buffers.at(indices_bufferview.buffer); + if (indices_int_size != 4) throw std::runtime_error("TODO: handle and support this"); + const uint32_t* const indices_data = reinterpret_cast(indices_buffer.data.data() + indices_byteoffset); + // in future, let Mesh constructor use spans to avoid unneccesary copy here + const std::vector indices(indices_data, indices_data + indices_accessor.count); + + const tg::Accessor& pos_accessor = gl_model.accessors.at(prim.attributes.at("POSITION")); + if (pos_accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) throw std::runtime_error("Position att. must be float!"); + if (pos_accessor.type != 3) throw std::runtime_error("Position att. dim. must be 3!"); + const tg::BufferView& pos_bufferview = gl_model.bufferViews.at(pos_accessor.bufferView); + const size_t pos_byteoffset = pos_accessor.byteOffset + pos_bufferview.byteOffset; + const size_t pos_bytestride = pos_accessor.ByteStride(pos_bufferview); + const tg::Buffer& pos_buffer = gl_model.buffers.at(pos_bufferview.buffer); + + const tg::Accessor& norm_accessor = gl_model.accessors.at(prim.attributes.at("NORMAL")); + if (norm_accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) throw std::runtime_error("Normal att. must be float!"); + if (norm_accessor.type != 3) throw std::runtime_error("Normal att. dim. must be 3!"); + const tg::BufferView& norm_bufferview = gl_model.bufferViews.at(norm_accessor.bufferView); + const size_t norm_byteoffset = norm_accessor.byteOffset + norm_bufferview.byteOffset; + const size_t norm_bytestride = norm_accessor.ByteStride(norm_bufferview); + const tg::Buffer& norm_buffer = gl_model.buffers.at(norm_bufferview.buffer); + + const tg::Accessor& uv_accessor = gl_model.accessors.at(prim.attributes.at("TEXCOORD_0")); + if (uv_accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) throw std::runtime_error("UV att. must be float!"); + if (uv_accessor.type != 2) throw std::runtime_error("UV att. dim. must be 2!"); + const tg::BufferView& uv_bufferview = gl_model.bufferViews.at(uv_accessor.bufferView); + const size_t uv_byteoffset = uv_accessor.byteOffset + uv_bufferview.byteOffset; + const size_t uv_bytestride = uv_accessor.ByteStride(uv_bufferview); + const tg::Buffer& uv_buffer = gl_model.buffers.at(uv_bufferview.buffer); + + std::vector vertices(pos_accessor.count); + for (size_t i = 0; i < vertices.size(); ++i) { + vertices[i].pos = *reinterpret_cast(&pos_buffer.data[pos_byteoffset + pos_bytestride * i]); + vertices[i].norm = *reinterpret_cast(&norm_buffer.data[norm_byteoffset + norm_bytestride * i]); + vertices[i].uv = *reinterpret_cast(&uv_buffer.data[uv_byteoffset + uv_bytestride * i]); + } + + // create tangents + + struct MeshData { + engine::Vertex* vertices; + const uint32_t* indices; + size_t count; + }; + + MeshData meshData{}; + meshData.vertices = vertices.data(); + meshData.indices = indices.data(); + meshData.count = indices.size(); + + SMikkTSpaceInterface mts_interface{}; + mts_interface.m_getNumFaces = [](const SMikkTSpaceContext* pContext) -> int { return static_cast(pContext->m_pUserData)->count / 3; }; + mts_interface.m_getNumVerticesOfFace = [](const SMikkTSpaceContext*, const int) -> int { return 3; }; + mts_interface.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) -> void { + const MeshData* const meshData = static_cast(pContext->m_pUserData); + const glm::vec3 pos = meshData->vertices[meshData->indices[iFace * 3 + iVert]].pos; + fvPosOut[0] = pos.x; + fvPosOut[1] = pos.y; + fvPosOut[2] = pos.z; + }; + mts_interface.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert) -> void { + const MeshData* const meshData = static_cast(pContext->m_pUserData); + const glm::vec3 norm = meshData->vertices[meshData->indices[iFace * 3 + iVert]].norm; + fvNormOut[0] = norm.x; + fvNormOut[1] = norm.y; + fvNormOut[2] = norm.z; + }; + mts_interface.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert) -> void { + const MeshData* const meshData = static_cast(pContext->m_pUserData); + const glm::vec2 uv = meshData->vertices[meshData->indices[iFace * 3 + iVert]].uv; + fvTexcOut[0] = uv.x; + fvTexcOut[1] = uv.y; + }; + mts_interface.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, + const int iVert) -> void { + MeshData* const meshData = static_cast(pContext->m_pUserData); + glm::vec4& tangent = meshData->vertices[meshData->indices[iFace * 3 + iVert]].tangent; + tangent.x = fvTangent[0]; + tangent.y = fvTangent[1]; + tangent.z = fvTangent[2]; + tangent.w = fSign; + }; + SMikkTSpaceContext mts_context{}; + mts_context.m_pInterface = &mts_interface; + mts_context.m_pUserData = &meshData; + + bool tan_result = genTangSpaceDefault(&mts_context); + if (tan_result == false) throw std::runtime_error("Failed to generate tangents!"); + + auto mesh_comp = app_scene.AddComponent(entity); + mesh_comp->mesh = std::make_unique(app_scene.app()->renderer()->GetDevice(), vertices, indices); + mesh_comp->material = std::make_unique(app_scene.app()->renderer(), app_scene.app()->GetResource("builtin.fancy")); + mesh_comp->material->SetAlbedoTexture(app_scene.app()->GetResource("builtin.white")); + mesh_comp->material->SetNormalTexture(app_scene.app()->GetResource("builtin.normal")); } for (const int node : node.children) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b71d514..d1c919c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -36,7 +36,7 @@ if (MSVC) target_compile_options(${PROJECT_NAME} PRIVATE /MP) target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS) else() - target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror -pedantic) + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -pedantic) endif() target_include_directories(${PROJECT_NAME} PRIVATE src) diff --git a/test/src/game.cpp b/test/src/game.cpp index 797ebea..9ae88a5 100644 --- a/test/src/game.cpp +++ b/test/src/game.cpp @@ -74,7 +74,7 @@ void PlayGame(GameSettings settings) } { /* floor */ - engine::Entity floor = engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/terrain.dae"), true); + [[maybe_unused]] engine::Entity floor = engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/terrain.dae"), true); } #if 0