Files
QuaternionEngine/third_party/fastgltf/tests/accessor_tests.cpp

219 lines
9.4 KiB
C++

#include <catch2/catch_test_macros.hpp>
#include <glm/vec3.hpp>
#include <glm/gtc/epsilon.hpp>
#include <glm/ext/scalar_constants.hpp>
#include <fastgltf/parser.hpp>
#include <fastgltf/tools.hpp>
#include "gltf_path.hpp"
template<>
struct fastgltf::ElementTraits<glm::vec3> : fastgltf::ElementTraitsBase<glm::vec3, AccessorType::Vec3, float> {};
static const std::byte* getBufferData(const fastgltf::Buffer& buffer) {
const std::byte* result = nullptr;
std::visit(fastgltf::visitor {
[](auto&) {},
[&](const fastgltf::sources::Vector& vec) {
result = reinterpret_cast<const std::byte*>(vec.bytes.data());
},
[&](const fastgltf::sources::ByteView& bv) {
result = bv.bytes.data();
},
}, buffer.data);
return result;
}
TEST_CASE("Test data type conversion", "[gltf-tools]") {
// normalized int-to-float and normalized float-to-int
for (auto i = std::numeric_limits<std::int8_t>::min(); i < std::numeric_limits<std::int8_t>::max(); ++i) {
auto converted = fastgltf::internal::convertComponent<float>(i, true);
REQUIRE(glm::epsilonEqual<float>(converted, fastgltf::max<float>(i / 127.0f, -1), glm::epsilon<float>()));
REQUIRE(fastgltf::internal::convertComponent<std::int8_t>(converted, true) == std::round(converted * 127.0f));
}
for (auto i = std::numeric_limits<std::uint8_t>::min(); i < std::numeric_limits<std::uint8_t>::max(); ++i) {
auto converted = fastgltf::internal::convertComponent<float>(i, true);
REQUIRE(glm::epsilonEqual<float>(converted, i / 255.0f, glm::epsilon<float>()));
REQUIRE(fastgltf::internal::convertComponent<std::uint8_t>(converted, true) == std::round(converted * 255.0f));
}
for (auto i = std::numeric_limits<std::int16_t>::min(); i < std::numeric_limits<std::int16_t>::max(); ++i) {
auto converted = fastgltf::internal::convertComponent<float>(i, true);
REQUIRE(glm::epsilonEqual<float>(converted, fastgltf::max<float>(i / 32767.0f, -1), glm::epsilon<float>()));
REQUIRE(fastgltf::internal::convertComponent<std::int16_t>(converted, true) == std::round(converted * 32767.0f));
}
for (auto i = std::numeric_limits<std::uint16_t>::min(); i < std::numeric_limits<std::uint16_t>::max(); ++i) {
auto converted = fastgltf::internal::convertComponent<float>(i, true);
REQUIRE(glm::epsilonEqual<float>(converted, i / 65535.0f, glm::epsilon<float>()));
REQUIRE(fastgltf::internal::convertComponent<std::uint16_t>(converted, true) == std::round(converted * 65535.0f));
}
}
TEST_CASE("Test accessor", "[gltf-tools]") {
auto lightsLamp = sampleModels / "2.0" / "LightsPunctualLamp" / "glTF";
fastgltf::GltfDataBuffer jsonData;
REQUIRE(jsonData.loadFromFile(lightsLamp / "LightsPunctualLamp.gltf"));
fastgltf::Parser parser(fastgltf::Extensions::KHR_lights_punctual);
auto asset = parser.loadGLTF(&jsonData, lightsLamp, fastgltf::Options::LoadExternalBuffers,
fastgltf::Category::Buffers | fastgltf::Category::BufferViews | fastgltf::Category::Accessors);
REQUIRE(asset.error() == fastgltf::Error::None);
REQUIRE(asset->accessors.size() == 15);
auto& accessors = asset->accessors;
SECTION("getAccessorElement<std::uint16_t>") {
auto& firstAccessor = accessors[0];
REQUIRE(firstAccessor.type == fastgltf::AccessorType::Scalar);
REQUIRE(firstAccessor.componentType == fastgltf::ComponentType::UnsignedShort);
REQUIRE(firstAccessor.bufferViewIndex.has_value());
auto& view = asset->bufferViews[*firstAccessor.bufferViewIndex];
auto* bufferData = getBufferData(asset->buffers[view.bufferIndex]);
REQUIRE(bufferData != nullptr);
auto* checkData = reinterpret_cast<const std::uint16_t*>(bufferData + view.byteOffset
+ firstAccessor.byteOffset);
REQUIRE(*checkData == fastgltf::getAccessorElement<std::uint16_t>(asset.get(), firstAccessor, 0));
}
{
auto& secondAccessor = accessors[1];
REQUIRE(secondAccessor.type == fastgltf::AccessorType::Vec3);
REQUIRE(secondAccessor.componentType == fastgltf::ComponentType::Float);
REQUIRE(secondAccessor.bufferViewIndex.has_value());
auto& view = asset->bufferViews[*secondAccessor.bufferViewIndex];
auto* bufferData = getBufferData(asset->buffers[view.bufferIndex]);
REQUIRE(bufferData != nullptr);
auto* checkData = reinterpret_cast<const glm::vec3*>(bufferData + view.byteOffset
+ secondAccessor.byteOffset);
SECTION("getAccessorElement<glm::vec3>") {
REQUIRE(*checkData == fastgltf::getAccessorElement<glm::vec3>(asset.get(), secondAccessor, 0));
}
SECTION("iterateAccessor") {
auto dstCopy = std::make_unique<glm::vec3[]>(secondAccessor.count);
std::size_t i = 0;
fastgltf::iterateAccessor<glm::vec3>(asset.get(), secondAccessor, [&](auto&& v3) {
dstCopy[i++] = std::forward<glm::vec3>(v3);
});
REQUIRE(std::memcmp(dstCopy.get(), checkData, secondAccessor.count * sizeof(glm::vec3)) == 0);
}
SECTION("copyFromAccessor") {
auto dstCopy = std::make_unique<glm::vec3[]>(secondAccessor.count);
fastgltf::copyFromAccessor<glm::vec3>(asset.get(), secondAccessor, dstCopy.get());
REQUIRE(std::memcmp(dstCopy.get(), checkData, secondAccessor.count * sizeof(glm::vec3)) == 0);
}
SECTION("Iterator test") {
auto dstCopy = std::make_unique<glm::vec3[]>(secondAccessor.count);
auto accessor = fastgltf::iterateAccessor<glm::vec3>(asset.get(), secondAccessor);
for (auto it = accessor.begin(); it != accessor.end(); ++it) {
dstCopy[std::distance(accessor.begin(), it)] = *it;
}
REQUIRE(std::memcmp(dstCopy.get(), checkData, secondAccessor.count * sizeof(glm::vec3)) == 0);
}
}
}
TEST_CASE("Test sparse accessor", "[gltf-tools]") {
auto simpleSparseAccessor = sampleModels / "2.0" / "SimpleSparseAccessor" / "glTF";
auto jsonData = std::make_unique<fastgltf::GltfDataBuffer>();
REQUIRE(jsonData->loadFromFile(simpleSparseAccessor / "SimpleSparseAccessor.gltf"));
fastgltf::Parser parser;
auto asset = parser.loadGLTF(jsonData.get(), simpleSparseAccessor, fastgltf::Options::LoadExternalBuffers,
fastgltf::Category::Buffers | fastgltf::Category::BufferViews | fastgltf::Category::Accessors);
REQUIRE(asset.error() == fastgltf::Error::None);
REQUIRE(asset->accessors.size() == 2);
REQUIRE(!asset->accessors[0].sparse.has_value());
REQUIRE(asset->accessors[1].sparse.has_value());
auto& sparse = asset->accessors[1].sparse.value();
REQUIRE(sparse.count == 3);
REQUIRE(sparse.indicesBufferView == 2);
REQUIRE(sparse.indicesByteOffset == 0);
REQUIRE(sparse.valuesBufferView == 3);
REQUIRE(sparse.valuesByteOffset == 0);
REQUIRE(sparse.indexComponentType == fastgltf::ComponentType::UnsignedShort);
auto& secondAccessor = asset->accessors[1];
auto& viewIndices = asset->bufferViews[secondAccessor.sparse->indicesBufferView];
auto& viewValues = asset->bufferViews[secondAccessor.sparse->valuesBufferView];
auto& viewData = asset->bufferViews[*secondAccessor.bufferViewIndex];
auto* bufferData = getBufferData(asset->buffers[viewData.bufferIndex]) + viewData.byteOffset
+ secondAccessor.byteOffset;
auto dataStride = viewData.byteStride ? *viewData.byteStride
: fastgltf::getElementByteSize(secondAccessor.type, secondAccessor.componentType);
auto* dataIndices = reinterpret_cast<const std::uint16_t*>(getBufferData(asset->buffers[viewIndices.bufferIndex])
+ viewIndices.byteOffset + secondAccessor.sparse->indicesByteOffset);
auto* dataValues = reinterpret_cast<const glm::vec3*>(getBufferData(asset->buffers[viewValues.bufferIndex])
+ viewValues.byteOffset + secondAccessor.sparse->valuesByteOffset);
auto checkValues = std::make_unique<glm::vec3[]>(secondAccessor.count);
for (std::size_t i = 0, sparseIndex = 0; i < secondAccessor.count; ++i) {
if (sparseIndex < secondAccessor.sparse->count && dataIndices[sparseIndex] == i) {
checkValues[i] = dataValues[sparseIndex];
++sparseIndex;
} else {
checkValues[i] = *reinterpret_cast<const glm::vec3*>(bufferData + dataStride * i);
}
}
SECTION("getAccessorElement") {
for (std::size_t i = 0; i < secondAccessor.count; ++i) {
REQUIRE(checkValues[i] == fastgltf::getAccessorElement<glm::vec3>(asset.get(), secondAccessor, i));
}
}
SECTION("iterateAccessor") {
auto dstCopy = std::make_unique<glm::vec3[]>(secondAccessor.count);
std::size_t i = 0;
fastgltf::iterateAccessor<glm::vec3>(asset.get(), secondAccessor, [&](auto&& v3) {
dstCopy[i++] = std::forward<glm::vec3>(v3);
});
REQUIRE(std::memcmp(dstCopy.get(), checkValues.get(), secondAccessor.count * sizeof(glm::vec3)) == 0);
}
SECTION("iterateAccessor with idx") {
auto dstCopy = std::make_unique<glm::vec3[]>(secondAccessor.count);
fastgltf::iterateAccessorWithIndex<glm::vec3>(asset.get(), secondAccessor, [&](auto&& v3, std::size_t i) {
dstCopy[i] = std::forward<glm::vec3>(v3);
});
REQUIRE(std::memcmp(dstCopy.get(), checkValues.get(), secondAccessor.count * sizeof(glm::vec3)) == 0);
}
SECTION("copyFromAccessor") {
auto dstCopy = std::make_unique<glm::vec3[]>(secondAccessor.count);
fastgltf::copyFromAccessor<glm::vec3>(asset.get(), secondAccessor, dstCopy.get());
REQUIRE(std::memcmp(dstCopy.get(), checkValues.get(), secondAccessor.count * sizeof(glm::vec3)) == 0);
}
SECTION("Iterator test") {
auto dstCopy = std::make_unique<glm::vec3[]>(secondAccessor.count);
auto accessor = fastgltf::iterateAccessor<glm::vec3>(asset.get(), secondAccessor);
for (auto it = accessor.begin(); it != accessor.end(); ++it) {
dstCopy[std::distance(accessor.begin(), it)] = *it;
}
REQUIRE(std::memcmp(dstCopy.get(), checkValues.get(), secondAccessor.count * sizeof(glm::vec3)) == 0);
}
}