#include "Loader.h" #include #include #include #include "VulkanRenderer.h" namespace fastgltf { template<> struct ElementTraits : ElementTraitsBase { }; template<> struct ElementTraits : ElementTraitsBase { }; template<> struct ElementTraits : ElementTraitsBase { }; } #ifndef __cpp_lib_format_path # include # include # include # include template struct std::formatter : std::formatter, CharT> { template auto format(std::filesystem::path const &p, FormatContext &ctx) const { std::basic_string s; if constexpr (std::is_same_v) { s = p.generic_string(); } else if constexpr (std::is_same_v) { s = p.generic_wstring(); } # if defined(__cpp_lib_char8_t) else if constexpr (std::is_same_v) { s = p.generic_u8string(); } # endif else if constexpr (std::is_same_v) { s = p.generic_u16string(); } else if constexpr (std::is_same_v) { s = p.generic_u32string(); } return std::formatter, CharT>::format(s, ctx); } }; namespace Lunar { auto Mesh::load_gltf_meshes( VulkanRenderer &renderer, std::filesystem::path const path) -> std::optional>> { renderer.logger().debug("Loading GLTF from file: {}", path); auto data { fastgltf::GltfDataBuffer::FromPath(path) }; if (data.error() != fastgltf::Error::None) { renderer.logger().err("Failed to open glTF file: {} (error {})", path, fastgltf::to_underlying(data.error())); return {}; } constexpr auto gltfOptions { fastgltf::Options::LoadExternalBuffers }; fastgltf::Parser parser; auto load { parser.loadGltf(data.get(), path.parent_path(), gltfOptions) }; if (load.error() != fastgltf::Error::None) { renderer.logger().err( "Failed to load glTF: {}", fastgltf::to_underlying(load.error())); return {}; } fastgltf::Asset gltf { std::move(load.get()) }; std::vector> meshes; std::vector indices; std::vector vertices; for (auto &mesh : gltf.meshes) { Mesh new_mesh; new_mesh.name = mesh.name; indices.clear(); vertices.clear(); for (auto &&p : mesh.primitives) { Surface new_surface; new_surface.start_index = static_cast(indices.size()); new_surface.count = static_cast( gltf.accessors[p.indicesAccessor.value()].count); size_t initial_vertex { vertices.size() }; { // Indices auto &accessor = gltf.accessors[p.indicesAccessor.value()]; indices.reserve(indices.size() + accessor.count); fastgltf::iterateAccessor( gltf, accessor, [&](std::uint32_t idx) { indices.emplace_back(idx + initial_vertex); }); } { // Vertex positions auto &accessor = gltf.accessors[p.findAttribute("POSITION") ->accessorIndex]; for (auto pos : fastgltf::iterateAccessor(gltf, accessor)) { Vertex v { .position = pos, .u = 0, .normal = { 0, 0, 0 }, .v = 0, .color = { 1.0f, 1.0f, 1.0f, 1.0f }, }; vertices.emplace_back(v); } } if (auto attr = p.findAttribute("NORMAL")) { // Normals auto &accessor = gltf.accessors[attr->accessorIndex]; size_t local_index { 0 }; for (auto normal : fastgltf::iterateAccessor(gltf, accessor)) { vertices[initial_vertex + local_index].normal = normal; local_index++; } } if (auto attr = p.findAttribute("TEXCOORD_0")) { // UVs auto &accessor = gltf.accessors[attr->accessorIndex]; size_t local_index { 0 }; for (auto uv : fastgltf::iterateAccessor(gltf, accessor)) { uv.unpack(vertices[initial_vertex + local_index].u, vertices[initial_vertex + local_index].v); local_index++; } } if (auto attr = p.findAttribute("COLOR_0")) { // Colors auto &accessor = gltf.accessors[attr->accessorIndex]; size_t local_index { 0 }; switch (accessor.type) { case fastgltf::AccessorType::Vec3: { for (auto c3 : fastgltf::iterateAccessor( gltf, accessor)) { auto &dst = vertices[initial_vertex + local_index].color; dst = { c3.x(), c3.y(), c3.z(), 1.0f }; ++local_index; } break; } case fastgltf::AccessorType::Vec4: { for (auto c4 : fastgltf::iterateAccessor( gltf, accessor)) { vertices[initial_vertex + local_index].color = c4; ++local_index; } break; } default: renderer.logger().warn( "Unsupported COLOR_0 accessor type ({}) on mesh '{}'", static_cast(accessor.type), new_mesh.name); break; } } constexpr bool OVERRIDE_COLORS = false; if (OVERRIDE_COLORS) { for (auto &vtx : vertices) { vtx.color = smath::Vec4(vtx.normal, 1.f); } } new_mesh.surfaces.emplace_back(new_surface); } new_mesh.mesh_buffers = renderer.upload_mesh(indices, vertices); meshes.emplace_back(std::make_shared(std::move(new_mesh))); } return meshes; } #endif // __cpp_lib_format_path } // namespace Lunar