Support loading GLB assets

This commit is contained in:
Nikita Lisitsa 2024-01-03 02:21:16 +03:00
parent 00231ce3f6
commit c3d964fafd
2 changed files with 57 additions and 1 deletions

View file

@ -140,6 +140,8 @@ namespace psemek::gfx
{
std::size_t length;
std::string uri;
std::optional<util::blob> 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);

View file

@ -4,6 +4,7 @@
#include <psemek/geom/translation.hpp>
#include <psemek/util/to_string.hpp>
#include <psemek/util/exception.hpp>
#include <psemek/io/memory_stream.hpp>
#include <psemek/log/log.hpp>
#include <boost/preprocessor/stringize.hpp>
@ -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;