From 8f4d753be1ddfcaf113673e29323c8991d2eda39 Mon Sep 17 00:00:00 2001 From: sean Date: Thu, 25 Apr 2024 11:20:40 +0200 Subject: [PATCH] Change: Always load GLB buffers --- include/fastgltf/core.hpp | 16 ++++++++++-- src/fastgltf.cpp | 52 +++++++++++++++++---------------------- tests/glb_tests.cpp | 8 +++--- 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/include/fastgltf/core.hpp b/include/fastgltf/core.hpp index 49919af13..411dc8c54 100644 --- a/include/fastgltf/core.hpp +++ b/include/fastgltf/core.hpp @@ -245,7 +245,7 @@ namespace fastgltf { * a byte offset and length into the GLB file, which can be useful when using APIs like * DirectStorage or Metal IO. */ - LoadGLBBuffers = 1 << 3, + LoadGLBBuffers [[deprecated]] = 1 << 3, /** * Loads all external buffers into CPU memory. If disabled, fastgltf will only provide @@ -607,12 +607,23 @@ namespace fastgltf { */ class GltfDataGetter { public: + /** + * The read functions expect the implementation to store an offset from the start + * of the buffer/file to the current position. The parse process will always linearly + * access the memory, meaning it will go through the memory once from start to finish. + */ virtual void read(void* ptr, std::size_t count) = 0; + /** + * Reads a chunk of memory from the current offset, with some amount of padding. + * This padding is necessary for the simdjson parser, but can be initialized to anything. + * The memory pointed to by the span only needs to live until the next call to read(). + */ [[nodiscard]] virtual span read(std::size_t count, std::size_t padding) = 0; /** * Reset is used to put the offset index back to the start of the buffer/file. - * This is only used with determineGltfFileType, as it needs to peek into the beginning of the file. + * This is only necessary for functionality like determineGltfFileType. However, reset() + * will be called at the beginning of every parse process. */ virtual void reset() = 0; @@ -707,6 +718,7 @@ namespace fastgltf { MappedGltfFile(MappedGltfFile&& other) noexcept; MappedGltfFile& operator=(MappedGltfFile&& other) noexcept; + /** Memory maps a file. If this fails, you can check std::strerror for a more exact error. */ static Expected FromPath(const std::filesystem::path& path) noexcept { MappedGltfFile buffer(path); if (buffer.error != fastgltf::Error::None) { diff --git a/src/fastgltf.cpp b/src/fastgltf.cpp index 895c402f8..030211b16 100644 --- a/src/fastgltf.cpp +++ b/src/fastgltf.cpp @@ -3824,7 +3824,7 @@ fg::MappedGltfFile::MappedGltfFile(const fs::path& path) noexcept { } // Get the file size - struct stat statInfo; + struct stat statInfo {}; if (fstat(fd, &statInfo) != 0) { error = Error::InvalidPath; return; @@ -3840,7 +3840,6 @@ fg::MappedGltfFile::MappedGltfFile(const fs::path& path) noexcept { if (mappedFile != MAP_FAILED) { fileSize = static_cast(statInfo.st_size); } else { - std::perror("Mapping file"); error = Error::FileBufferAllocationFailed; } @@ -3849,7 +3848,7 @@ fg::MappedGltfFile::MappedGltfFile(const fs::path& path) noexcept { } fg::MappedGltfFile::MappedGltfFile(fastgltf::MappedGltfFile &&other) noexcept { - // Make sure that munmap is never called when other gets destructud. + // Make sure that munmap is never called when other gets destructed. mappedFile = std::exchange(other.mappedFile, MAP_FAILED); fileSize = other.fileSize; idx = other.idx; @@ -4043,11 +4042,12 @@ fg::Expected fg::Parser::loadGltfJson(GltfDataGetter& data, fs::path this->options = options; this->directory = std::move(directory); + data.reset(); auto jsonSpan = data.read(data.totalSize(), SIMDJSON_PADDING); - simdjson::padded_string_view view(reinterpret_cast(jsonSpan.data()), + padded_string_view view(reinterpret_cast(jsonSpan.data()), data.totalSize(), data.totalSize() + SIMDJSON_PADDING); - simdjson::dom::object root; + dom::object root; if (auto error = jsonParser->parse(view).get(root); error != SUCCESS) FASTGLTF_UNLIKELY { return Error::InvalidJson; } @@ -4066,6 +4066,8 @@ fg::Expected fg::Parser::loadGltfBinary(GltfDataGetter& data, fs::pat this->options = options; this->directory = std::move(directory); + data.reset(); + BinaryGltfHeader header = {}; data.read(&header, sizeof header); if (header.magic != binaryGltfHeaderMagic) { @@ -4108,34 +4110,26 @@ fg::Expected fg::Parser::loadGltfBinary(GltfDataGetter& data, fs::pat return Error::InvalidGLB; } + // TODO: Somehow allow skipping the binary part in the future? if (binaryChunk.chunkLength != 0) { - if (hasBit(options, Options::LoadGLBBuffers)) { - if (config.mapCallback != nullptr) { - auto info = config.mapCallback(binaryChunk.chunkLength, config.userPointer); - if (info.mappedMemory != nullptr) { - data.read(info.mappedMemory, binaryChunk.chunkLength); - if (config.unmapCallback != nullptr) { - config.unmapCallback(&info, config.userPointer); - } - glbBuffer = sources::CustomBuffer{info.customId, MimeType::None}; + if (config.mapCallback != nullptr) { + auto info = config.mapCallback(binaryChunk.chunkLength, config.userPointer); + if (info.mappedMemory != nullptr) { + data.read(info.mappedMemory, binaryChunk.chunkLength); + if (config.unmapCallback != nullptr) { + config.unmapCallback(&info, config.userPointer); } - } else { - StaticVector binaryData(binaryChunk.chunkLength); - data.read(binaryData.data(), binaryChunk.chunkLength); - - sources::Array vectorData = { - std::move(binaryData), - MimeType::GltfBuffer, - }; - glbBuffer = std::move(vectorData); + glbBuffer = sources::CustomBuffer{info.customId, MimeType::None}; } } else { - // TODO: What to do with this? - //const span glbBytes(reinterpret_cast(buffer->bufferPointer + offset), binaryChunk.chunkLength); - sources::ByteView glbByteView = {}; - //glbByteView.bytes = glbBytes; - glbByteView.mimeType = MimeType::GltfBuffer; - glbBuffer = glbByteView; + StaticVector binaryData(binaryChunk.chunkLength); + data.read(binaryData.data(), binaryChunk.chunkLength); + + sources::Array vectorData = { + std::move(binaryData), + MimeType::GltfBuffer, + }; + glbBuffer = std::move(vectorData); } } } diff --git a/tests/glb_tests.cpp b/tests/glb_tests.cpp index 69b186eb7..ced72e407 100644 --- a/tests/glb_tests.cpp +++ b/tests/glb_tests.cpp @@ -20,11 +20,9 @@ TEST_CASE("Load basic GLB file", "[gltf-loader]") { REQUIRE(asset->buffers.size() == 1); auto& buffer = asset->buffers.front(); - auto* bufferView = std::get_if(&buffer.data); - REQUIRE(bufferView != nullptr); - auto jsonSpan = fastgltf::span(jsonData.get()); - REQUIRE(bufferView->bytes.data() - jsonSpan.data() == 1016); - REQUIRE(jsonSpan.size() == 1664); + auto* array = std::get_if(&buffer.data); + REQUIRE(array != nullptr); + REQUIRE(array->bytes.size() == 1664 - 1016); } SECTION("Load basic Box.glb and load buffers") {