Skip to content

Commit

Permalink
Add: More DXMath element traits & transposed matrices
Browse files Browse the repository at this point in the history
When using the accessor tools for a DirectX::XMFLOAT4x4 it now transposes automatically, making the matrix behave as expected.
  • Loading branch information
spnda committed Aug 1, 2024
1 parent d4734a7 commit d433b90
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 15 deletions.
42 changes: 42 additions & 0 deletions include/fastgltf/dxmath_element_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

namespace fastgltf {

FASTGLTF_EXPORT template <typename ElementType, AccessorType EnumAccessorType, typename ComponentType = ElementType>
using TransposedElementTraits = ElementTraitsBase<ElementType, EnumAccessorType, ComponentType, true>;

template <>
struct ElementTraits<DirectX::XMFLOAT2> : ElementTraitsBase<DirectX::XMFLOAT2, AccessorType::Vec2, float> {};

Expand All @@ -17,4 +20,43 @@ struct ElementTraits<DirectX::XMFLOAT3> : ElementTraitsBase<DirectX::XMFLOAT3, A
template <>
struct ElementTraits<DirectX::XMFLOAT4> : ElementTraitsBase<DirectX::XMFLOAT4, AccessorType::Vec4, float> {};

template<>
struct ElementTraits<DirectX::XMBYTE2> : ElementTraitsBase<DirectX::XMBYTE2, AccessorType::Vec2, std::uint8_t> {};

template<>
struct ElementTraits<DirectX::XMBYTE4> : ElementTraitsBase<DirectX::XMBYTE4, AccessorType::Vec4, std::uint8_t> {};

template<>
struct ElementTraits<DirectX::XMBYTE2> : ElementTraitsBase<DirectX::XMBYTE2, AccessorType::Vec2, std::uint8_t> {};

template<>
struct ElementTraits<DirectX::XMBYTE4> : ElementTraitsBase<DirectX::XMBYTE4, AccessorType::Vec4, std::uint8_t> {};

template<>
struct ElementTraits<DirectX::XMSHORT2> : ElementTraitsBase<DirectX::XMSHORT2, AccessorType::Vec2, std::uint16_t> {};

template<>
struct ElementTraits<DirectX::XMSHORT4> : ElementTraitsBase<DirectX::XMSHORT4, AccessorType::Vec4, std::uint16_t> {};

template<>
struct ElementTraits<DirectX::XMUSHORT2> : ElementTraitsBase<DirectX::XMUSHORT2, AccessorType::Vec2, std::uint16_t> {};

template<>
struct ElementTraits<DirectX::XMUSHORT4> : ElementTraitsBase<DirectX::XMUSHORT4, AccessorType::Vec4, std::uint16_t> {};

template<>
struct ElementTraits<DirectX::XMUINT2> : ElementTraitsBase<DirectX::XMUINT2, AccessorType::Vec2, std::uint32_t> {};

template<>
struct ElementTraits<DirectX::XMUINT3> : ElementTraitsBase<DirectX::XMUINT3, AccessorType::Vec3, std::uint32_t> {};

template<>
struct ElementTraits<DirectX::XMUINT4> : ElementTraitsBase<DirectX::XMUINT4, AccessorType::Vec4, std::uint32_t> {};

template<>
struct ElementTraits<DirectX::XMFLOAT3x3> : TransposedElementTraits<DirectX::XMFLOAT3x3, AccessorType::Mat3, float> {};

template<>
struct ElementTraits<DirectX::XMFLOAT4X4> : TransposedElementTraits<DirectX::XMFLOAT4X4, AccessorType::Mat4, float> {};

} // namespace fastgltf
42 changes: 27 additions & 15 deletions include/fastgltf/tools.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,13 @@ struct ComponentTypeConverter<std::float64_t> {
};
#endif

FASTGLTF_EXPORT template <typename ElementType, AccessorType EnumAccessorType, typename ComponentType = ElementType>
FASTGLTF_EXPORT template <typename ElementType, AccessorType EnumAccessorType, typename ComponentType = ElementType, bool transpose = false>
struct ElementTraitsBase {
using element_type = ElementType;
using component_type = ComponentType;
static constexpr auto type = EnumAccessorType;
static constexpr auto enum_component_type = ComponentTypeConverter<ComponentType>::type;
static constexpr auto needs_transpose = transpose;
};

FASTGLTF_EXPORT template <typename>
Expand Down Expand Up @@ -305,25 +306,35 @@ constexpr DestType convertComponent(const std::byte* bytes, std::size_t index, A
return convertComponent<DestType>(deserializeComponent<SourceType>(bytes, index), normalized);
}

constexpr std::size_t getComponentIndex(std::size_t i, AccessorType type, bool transposed) {
if (transposed) {
auto n = getElementRowCount(type);
return (i % n) * n + (i / n);
}

return i;
}

template <typename DestType>
constexpr DestType getAccessorComponentAt(ComponentType componentType, AccessorType type, const std::byte* bytes, std::size_t componentIdx, bool normalized) {
constexpr DestType getAccessorComponentAt(ComponentType componentType, AccessorType type, const std::byte* bytes, std::size_t componentIdx, bool normalized = false, bool transposed = false) {
auto idx = getComponentIndex(componentIdx, type, transposed);
switch (componentType) {
case ComponentType::Byte:
return internal::convertComponent<DestType, std::int8_t>(bytes, componentIdx, type, normalized);
return internal::convertComponent<DestType, std::int8_t>(bytes, idx, type, normalized);
case ComponentType::UnsignedByte:
return internal::convertComponent<DestType, std::uint8_t>(bytes, componentIdx, type, normalized);
return internal::convertComponent<DestType, std::uint8_t>(bytes, idx, type, normalized);
case ComponentType::Short:
return internal::convertComponent<DestType, std::int16_t>(bytes, componentIdx, type, normalized);
return internal::convertComponent<DestType, std::int16_t>(bytes, idx, type, normalized);
case ComponentType::UnsignedShort:
return internal::convertComponent<DestType, std::uint16_t>(bytes, componentIdx, type, normalized);
return internal::convertComponent<DestType, std::uint16_t>(bytes, idx, type, normalized);
case ComponentType::Int:
return internal::convertComponent<DestType, std::int32_t>(bytes, componentIdx, type, normalized);
return internal::convertComponent<DestType, std::int32_t>(bytes, idx, type, normalized);
case ComponentType::UnsignedInt:
return internal::convertComponent<DestType, std::uint32_t>(bytes, componentIdx, type, normalized);
return internal::convertComponent<DestType, std::uint32_t>(bytes, idx, type, normalized);
case ComponentType::Float:
return internal::convertComponent<DestType, float>(bytes, componentIdx, type, normalized);
return internal::convertComponent<DestType, float>(bytes, idx, type, normalized);
case ComponentType::Double:
return internal::convertComponent<DestType, double>(bytes, componentIdx, type, normalized);
return internal::convertComponent<DestType, double>(bytes, idx, type, normalized);
case ComponentType::Invalid:
default:
return DestType {};
Expand All @@ -335,14 +346,15 @@ template <typename ElementType, typename SourceType, std::size_t... I>
requires Element<ElementType>
#endif
constexpr ElementType convertAccessorElement(const std::byte* bytes, bool normalized, std::index_sequence<I...>) {
using DestType = typename ElementTraits<ElementType>::component_type;
static_assert(std::is_arithmetic_v<DestType>, "Accessor traits must provide a valid component type");
using Traits = ElementTraits<ElementType>;
static_assert(std::is_arithmetic_v<typename Traits::component_type>, "Accessor traits must provide a valid component type");

constexpr auto accessorType = ElementTraits<ElementType>::type;
if constexpr (std::is_aggregate_v<ElementType>) {
return {convertComponent<DestType, SourceType>(bytes, I, accessorType, normalized)...};
return {convertComponent<typename Traits::component_type, SourceType>(
bytes, getComponentIndex(I, Traits::type, Traits::needs_transpose), Traits::type, normalized)...};
} else {
return ElementType(convertComponent<DestType, SourceType>(bytes, I, accessorType, normalized)...);
return ElementType(convertComponent<typename Traits::component_type, SourceType>(
bytes, getComponentIndex(I, Traits::type, Traits::needs_transpose), Traits::type, normalized)...);
}
}

Expand Down
19 changes: 19 additions & 0 deletions tests/accessor_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,25 @@ TEST_CASE("Test matrix data padding", "[gltf-tools]") {
}
}

TEST_CASE("Test matrix transpose", "[gltf-tools]") {
// First a case that doesn't require any padding
std::array<float, 4> mat2 {{
1, 2,
3, 4
}};
REQUIRE(fastgltf::getElementByteSize(fastgltf::AccessorType::Mat2, fastgltf::ComponentType::Float) == mat2.size() * sizeof(float));

static constexpr std::array<float, 4> transposed {{
1, 3, 2, 4
}};
for (std::size_t i = 0; i < 4; ++i) {
REQUIRE(float(i + 1) == fastgltf::internal::getAccessorComponentAt<float>(
fastgltf::ComponentType::Float, fastgltf::AccessorType::Mat2, reinterpret_cast<std::byte*>(mat2.data()), i, false, false));
REQUIRE(transposed[i] == fastgltf::internal::getAccessorComponentAt<float>(
fastgltf::ComponentType::Float, fastgltf::AccessorType::Mat2, reinterpret_cast<std::byte*>(mat2.data()), i, false, true));
}
}

TEST_CASE("Test accessor", "[gltf-tools]") {
auto lightsLamp = sampleModels / "2.0" / "LightsPunctualLamp" / "glTF";

Expand Down

0 comments on commit d433b90

Please sign in to comment.