From c3d964fafd0776f7f11dedaf9c455633973a6c26 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Wed, 3 Jan 2024 02:21:16 +0300 Subject: [PATCH] Support loading GLB assets --- libs/gfx/include/psemek/gfx/gltf_parser.hpp | 3 ++ libs/gfx/source/gltf_parser.cpp | 55 ++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/libs/gfx/include/psemek/gfx/gltf_parser.hpp b/libs/gfx/include/psemek/gfx/gltf_parser.hpp index b0980230..7c52cdbf 100644 --- a/libs/gfx/include/psemek/gfx/gltf_parser.hpp +++ b/libs/gfx/include/psemek/gfx/gltf_parser.hpp @@ -140,6 +140,8 @@ namespace psemek::gfx { std::size_t length; std::string uri; + + std::optional data; // for GLB buffer }; // KHR_lights_punctual @@ -184,6 +186,7 @@ namespace psemek::gfx }; gltf_asset parse_gltf(io::istream && stream); + gltf_asset parse_glb(io::istream && stream); std::size_t attribute_size(gltf_asset::accessor::type_t type); diff --git a/libs/gfx/source/gltf_parser.cpp b/libs/gfx/source/gltf_parser.cpp index e31491a0..d4083d55 100644 --- a/libs/gfx/source/gltf_parser.cpp +++ b/libs/gfx/source/gltf_parser.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -378,7 +379,9 @@ namespace psemek::gfx auto & target = result.buffers.emplace_back(); target.length = buffer["byteLength"].GetUint64(); - target.uri = buffer["uri"].GetString(); + + if (buffer.HasMember("uri")) + target.uri = buffer["uri"].GetString(); } if (document.HasMember("extensions")) for (auto const & extension : document["extensions"].GetObject()) @@ -451,6 +454,56 @@ namespace psemek::gfx return result; } + gltf_asset parse_glb(io::istream && stream) + { + std::uint32_t magic, version, length; + stream.read_all((char *)&magic, 4); + stream.read_all((char *)&version, 4); + stream.read_all((char *)&length, 4); + + if (magic != 0x46546c67u) + throw std::runtime_error("Error parsing GLB magic"); + + if (version != 2) + throw std::runtime_error("Unknown GLB file version"); + + length -= 12; + + gltf_asset result; + + while (length > 0) + { + std::uint32_t chunk_length, chunk_type; + stream.read_all((char *)&chunk_length, 4); + stream.read_all((char *)&chunk_type, 4); + + util::blob data(chunk_length); + stream.read_all(data.data(), chunk_length); + + length -= 8; + length -= chunk_length; + + if (chunk_type == 0x4e4f534au) + { + result = parse_gltf(io::memory_istream(data.begin(), data.end())); + } + else if (chunk_type == 0x004e4942u) + { + if (result.buffers.empty()) + throw std::runtime_error("Error parsing GLB: glTF chunk has no buffers"); + + if (!result.buffers[0].uri.empty()) + throw std::runtime_error("Error parsing GLB: first glTF buffer has URI"); + + result.buffers[0].data = std::move(data); + } + else + throw std::runtime_error("Error parsing GLB: unknown chunk type"); + } + + return result; + } + std::size_t attribute_size(gltf_asset::accessor::type_t type) { using type_t = gltf_asset::accessor::type_t;