diff --git a/doc/changelog.dox b/doc/changelog.dox index bd3d05597..00b1c766d 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -110,6 +110,11 @@ See also: @subsubsection changelog-latest-new-math Math library +- New @ref Magnum/Math/PackingBatch.h header with batch + @ref Math::packInto(), @ref Math::unpackInto(), + @ref Math::packHalfInto(), @ref Math::unpackHalfInto() and + @ref Math::castInto() functions for optimized (un)packing and casting of + large amounts of data (see also [mosra/magnum#275](https://github.com/mosra/magnum/pull/275)) - Added @ref Math::Quaternion::toEuler() and documented how to convert Euler angles to a quaternion (see [mosra/magnum#397](https://github.com/mosra/magnum/pull/397)) - Added @ref Math::DualComplex::transformVector(), @@ -262,11 +267,6 @@ See also: - Functions in @ref Magnum/Math/FunctionsBatch.h now accept any type that's convertible to a @ref Corrade::Containers::StridedArrayView without having to add explicit casts or template parameters -- New @ref Magnum/Math/PackingBatch.h header with batch - @ref Math::packInto(), @ref Math::unpackInto(), - @ref Math::packHalfInto(), @ref Math::unpackHalfInto() and - @ref Math::castInto() functions for optimized (un)packing of large amounts - of data (see also [mosra/magnum#275](https://github.com/mosra/magnum/pull/275)) - @ref Math::slerp(const Quaternion&, const Quaternion&, T) and @ref Math::slerpShortestPath(const Quaternion&, const Quaternion&, T) now fall back to linear interpolation when the quaternions are close to diff --git a/src/Magnum/Math/PackingBatch.cpp b/src/Magnum/Math/PackingBatch.cpp index 49cc74c9d..3dc9e7ae4 100644 --- a/src/Magnum/Math/PackingBatch.cpp +++ b/src/Magnum/Math/PackingBatch.cpp @@ -240,6 +240,38 @@ void castInto(const Corrade::Containers::StridedArrayView2D& src, c castIntoImplementation(src, dst); } +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + +void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst) { + castIntoImplementation(src, dst); +} + static_assert(sizeof(HalfMantissaTable) + sizeof(HalfOffsetTable) + sizeof(HalfExponentTable) == 8576, "improper size of half->float conversion tables"); diff --git a/src/Magnum/Math/PackingBatch.h b/src/Magnum/Math/PackingBatch.h index dc07e4c01..45ec7fdd5 100644 --- a/src/Magnum/Math/PackingBatch.h +++ b/src/Magnum/Math/PackingBatch.h @@ -265,6 +265,65 @@ MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); +/** +@brief Cast integer values into a differently sized type +@param[in] src Source values +@param[out] dst Destination values +@m_since_latest + +Second dimension is meant to contain vector/matrix components, or have a size +of 1 for scalars. Expects that @p src and @p dst have the same size and that +the second dimension in both is contiguous. + +@attention Values that don't fit into the resulting type will have undefined + values. + +@see @ref Corrade::Containers::StridedArrayView::isContiguous() +*/ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + +/** + * @overload + * @m_since_latest + */ +MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D& src, const Corrade::Containers::StridedArrayView2D& dst); + /*@}*/ }} diff --git a/src/Magnum/Math/Test/PackingBatchTest.cpp b/src/Magnum/Math/Test/PackingBatchTest.cpp index 59c1be2fa..3ee15cda4 100644 --- a/src/Magnum/Math/Test/PackingBatchTest.cpp +++ b/src/Magnum/Math/Test/PackingBatchTest.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "Magnum/Math/Color.h" #include "Magnum/Math/Packing.h" @@ -51,12 +52,15 @@ struct PackingBatchTest: Corrade::TestSuite::Tester { void unpackHalf(); void packHalf(); - template void castUnsigned(); - template void castSigned(); + template void castUnsignedFloat(); + template void castSignedFloat(); + + template void castUnsignedInteger(); + template void castSignedInteger(); template void assertionsPackUnpack(); void assertionsPackUnpackHalf(); - template void assertionsCast(); + template void assertionsCast(); }; PackingBatchTest::PackingBatchTest() { @@ -72,24 +76,33 @@ PackingBatchTest::PackingBatchTest() { &PackingBatchTest::unpackHalf, &PackingBatchTest::packHalf, - &PackingBatchTest::castUnsigned, - &PackingBatchTest::castUnsigned, - &PackingBatchTest::castUnsigned, - &PackingBatchTest::castSigned, - &PackingBatchTest::castSigned, - &PackingBatchTest::castSigned, + &PackingBatchTest::castUnsignedFloat, + &PackingBatchTest::castUnsignedFloat, + &PackingBatchTest::castUnsignedFloat, + &PackingBatchTest::castSignedFloat, + &PackingBatchTest::castSignedFloat, + &PackingBatchTest::castSignedFloat, + + &PackingBatchTest::castUnsignedInteger, + &PackingBatchTest::castUnsignedInteger, + &PackingBatchTest::castSignedInteger, + &PackingBatchTest::castSignedInteger, &PackingBatchTest::assertionsPackUnpack, &PackingBatchTest::assertionsPackUnpack, &PackingBatchTest::assertionsPackUnpack, &PackingBatchTest::assertionsPackUnpack, &PackingBatchTest::assertionsPackUnpackHalf, - &PackingBatchTest::assertionsCast, - &PackingBatchTest::assertionsCast, - &PackingBatchTest::assertionsCast, - &PackingBatchTest::assertionsCast, - &PackingBatchTest::assertionsCast, - &PackingBatchTest::assertionsCast}); + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast, + &PackingBatchTest::assertionsCast}); } typedef Math::Constants Constants; @@ -98,6 +111,8 @@ typedef Math::Vector2 Vector2us; typedef Math::Vector2 Vector2b; typedef Math::Vector2 Vector2s; typedef Math::Vector2 Vector2; +typedef Math::Vector2 Vector2ui; +typedef Math::Vector2 Vector2i; typedef Math::Vector3 Vector3; typedef Math::Vector4 Vector4; @@ -399,7 +414,7 @@ void PackingBatchTest::packHalf() { CORRADE_COMPARE(Math::packHalf(data[i].src), data[i].dst); } -template void PackingBatchTest::castUnsigned() { +template void PackingBatchTest::castUnsignedFloat() { setTestCaseTemplateName(TypeTraits::name()); struct Data { @@ -439,7 +454,7 @@ template void PackingBatchTest::castUnsigned() { Corrade::TestSuite::Compare::Container); } -template void PackingBatchTest::castSigned() { +template void PackingBatchTest::castSignedFloat() { setTestCaseTemplateName(TypeTraits::name()); struct Data { @@ -479,6 +494,86 @@ template void PackingBatchTest::castSigned() { Corrade::TestSuite::Compare::Container); } +template void PackingBatchTest::castUnsignedInteger() { + setTestCaseTemplateName(TypeTraits::name()); + + struct Data { + Math::Vector2 src; + Vector2ui dst; + } data[]{ + {{0, 89}, {}}, + {{149, 22}, {}}, + {{13, 255}, {}} + }; + + /* GCC 4.8 doesn't like constexpr here (cannot initialize aggregate of type + ‘const Vector2 [3]’ with a compound literal), wtf */ + const Vector2ui expectedTargetType[] { + {0, 89}, + {149, 22}, + {13, 255} + }; + + constexpr Math::Vector2 expectedOriginalType[] { + {0, 89}, + {149, 22}, + {13, 255} + }; + + Corrade::Containers::StridedArrayView1D> src{data, &data[0].src, 3, sizeof(Data)}; + Corrade::Containers::StridedArrayView1D dst{data, &data[0].dst, 3, sizeof(Data)}; + castInto(Corrade::Containers::arrayCast<2, T>(src), + Corrade::Containers::arrayCast<2, UnsignedInt>(dst)); + CORRADE_COMPARE_AS(dst, Corrade::Containers::stridedArrayView(expectedTargetType), + Corrade::TestSuite::Compare::Container); + + /* Test the other way around as well */ + castInto(Corrade::Containers::arrayCast<2, UnsignedInt>(dst), + Corrade::Containers::arrayCast<2, T>(src)); + CORRADE_COMPARE_AS(src, Corrade::Containers::stridedArrayView(expectedOriginalType), + Corrade::TestSuite::Compare::Container); +} + +template void PackingBatchTest::castSignedInteger() { + setTestCaseTemplateName(TypeTraits::name()); + + struct Data { + Math::Vector2 src; + Vector2i dst; + } data[]{ + {{0, -89}, {}}, + {{-119, 22}, {}}, + {{13, 127}, {}} + }; + + /* GCC 4.8 doesn't like constexpr here (cannot initialize aggregate of type + ‘const Vector2 [3]’ with a compound literal), wtf */ + const Vector2i expectedTargetType[] { + {0, -89}, + {-119, 22}, + {13, 127} + }; + + constexpr Math::Vector2 expectedOriginalType[] { + {0, -89}, + {-119, 22}, + {13, 127} + }; + + Corrade::Containers::StridedArrayView1D> src{data, &data[0].src, 3, sizeof(Data)}; + Corrade::Containers::StridedArrayView1D dst{data, &data[0].dst, 3, sizeof(Data)}; + castInto(Corrade::Containers::arrayCast<2, T>(src), + Corrade::Containers::arrayCast<2, Int>(dst)); + CORRADE_COMPARE_AS(dst, Corrade::Containers::stridedArrayView(expectedTargetType), + Corrade::TestSuite::Compare::Container); + + /* Test the other way around as well */ + castInto(Corrade::Containers::arrayCast<2, Int>(dst), + Corrade::Containers::arrayCast<2, T>(src)); + CORRADE_COMPARE_AS(src, Corrade::Containers::stridedArrayView(expectedOriginalType), + Corrade::TestSuite::Compare::Container); +} + template void PackingBatchTest::assertionsPackUnpack() { Math::Vector2 data[2]{}; Vector2 resultWrongCount[1]{}; @@ -543,19 +638,21 @@ void PackingBatchTest::assertionsPackUnpackHalf() { "Math::packHalfInto(): second view dimension is not contiguous\n"); } -template void PackingBatchTest::assertionsCast() { +template void PackingBatchTest::assertionsCast() { + setTestCaseTemplateName(Corrade::Utility::formatString("{}, {}", TypeTraits::name(), TypeTraits::name())); + Math::Vector2 data[2]{}; - Vector2 resultWrongCount[1]{}; - Vector3 resultWrongVectorSize[2]{}; - Vector4 resultNonContiguous[2]{}; + Math::Vector2 resultWrongCount[1]{}; + Math::Vector3 resultWrongVectorSize[2]{}; + Math::Vector4 resultNonContiguous[2]{}; auto src = Corrade::Containers::arrayCast<2, T>( Corrade::Containers::arrayView(data)); - auto dstWrongCount = Corrade::Containers::arrayCast<2, Float>( + auto dstWrongCount = Corrade::Containers::arrayCast<2, U>( Corrade::Containers::arrayView(resultWrongCount)); - auto dstWrongVectorSize = Corrade::Containers::arrayCast<2, Float>( + auto dstWrongVectorSize = Corrade::Containers::arrayCast<2, U>( Corrade::Containers::arrayView(resultWrongVectorSize)); - auto dstNotContiguous = Corrade::Containers::arrayCast<2, Float>( + auto dstNotContiguous = Corrade::Containers::arrayCast<2, U>( Corrade::Containers::arrayView(resultNonContiguous)).every({1, 2}); std::ostringstream out;