From c23022d47f2418ef1c90bb2f86cf6e63f46ac439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 5 Aug 2012 12:54:22 +0200 Subject: [PATCH] Another, more convenient way to swizzle. On the other hand everything of this is done at runtime, so it's less performant than the previous version, mainly when used in loops. When the result is declared as constexpr, it is done at compile time, just like the previous version. I don't know which version to keep, so there will be both until a good decision. --- src/Math/Matrix.h | 10 ------- src/Math/Swizzle.h | 51 +++++++++++++++++++++++++++++++++++ src/Math/Test/SwizzleTest.cpp | 21 +++++++++++++-- src/Math/Test/SwizzleTest.h | 1 + src/Math/Vector.h | 18 ++++++++++--- 5 files changed, 85 insertions(+), 16 deletions(-) diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index 47d6c41ee..8dfd40d93 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -26,16 +26,6 @@ namespace Magnum { namespace Math { #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template class MatrixDeterminant; - - template struct Sequence {}; - - /* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */ - template struct GenerateSequence: - GenerateSequence {}; - - template struct GenerateSequence<0, sequence...> { - typedef Sequence Type; - }; } #endif diff --git a/src/Math/Swizzle.h b/src/Math/Swizzle.h index cfbec9290..e964948a6 100644 --- a/src/Math/Swizzle.h +++ b/src/Math/Swizzle.h @@ -48,6 +48,26 @@ namespace Implementation { template struct TypeForSize<2, T> { typedef Vector2 Type; }; template struct TypeForSize<3, T> { typedef Vector3 Type; }; template struct TypeForSize<4, T> { typedef Vector4 Type; }; + + inline constexpr size_t getPosition(size_t size, size_t position) { + return size > position ? position : throw; + } + + template inline constexpr size_t getComponent(char component) { + return component == 'x' ? getPosition(size, 0) : + component == 'y' ? getPosition(size, 1) : + component == 'z' ? getPosition(size, 2) : + component == 'w' ? getPosition(size, 3) : + component == 'r' ? getPosition(size, 0) : + component == 'g' ? getPosition(size, 1) : + component == 'b' ? getPosition(size, 2) : + component == 'a' ? getPosition(size, 3) : + throw; + } + + template inline constexpr Vector swizzleFrom(Sequence, const Vector& vector, const char(&components)[sizeof...(sequence)+1]) { + return {vector[getComponent(components[sequence])]...}; + } } #endif @@ -66,12 +86,43 @@ elements is unlimited, but must be at least one. If the resulting vector is two, three or four-component, corresponding Vector2, Vector3 or Vector4 specialization is returned. +@attention This function is less convenient to write than +swizzle(const Vector&, const char(&)[newSize]), but the evaluation of +the swizzling operation is guaranteed to be always done at compile time +instead of at runtime. + @see Vector4::xyz(), Vector4::rgb(), Vector4::xy(), Vector3::xy() */ template inline constexpr typename Implementation::TypeForSize::Type swizzle(const Vector& vector) { return {vector[Implementation::GetComponent::value()]...}; } +/** +@brief Swizzle Vector components + +Creates new vector from given components. Example: +@code +Vector4 original(1, 2, 3, 4); + +auto vec = swizzle(original, "abbgrr"); +// vec == { 4, 3, 3, 2, 1, 1 } +@endcode +You can use letters `x`, `y`, `z`, `w` and `r`, `g`, `b`, `a`. Count of +elements is unlimited, but must be at least one. If the resulting vector is +two, three or four-component, corresponding Vector2, Vector3 or Vector4 +specialization is returned. + +@attention This function is more convenient to write than +swizzle(const Vector&), but unless the result is marked with +`constexpr`, the evaluation of the swizzling operation probably won't be +evaluated at compile time, but at runtime. + +@see Vector4::xyz(), Vector4::rgb(), Vector4::xy(), Vector3::xy() +*/ +template inline constexpr typename Implementation::TypeForSize::Type swizzle(const Vector& vector, const char(&components)[newSize]) { + return Implementation::swizzleFrom(typename Implementation::GenerateSequence::Type(), vector, components); +} + }} #endif diff --git a/src/Math/Test/SwizzleTest.cpp b/src/Math/Test/SwizzleTest.cpp index f71cc8d6d..52f590ae8 100644 --- a/src/Math/Test/SwizzleTest.cpp +++ b/src/Math/Test/SwizzleTest.cpp @@ -32,31 +32,48 @@ template using Vector = Math::Vector; SwizzleTest::SwizzleTest() { addTests(&SwizzleTest::xyzw, &SwizzleTest::rgba, + &SwizzleTest::fromSmall, &SwizzleTest::type, &SwizzleTest::defaultType); } void SwizzleTest::xyzw() { Vector4 orig(2, 4, 5, 7); - CORRADE_COMPARE((swizzle<'z', 'x', 'w', 'y'>(orig)), Vector4(5, 2, 7, 4)); + Vector4 swizzled(5, 2, 7, 4); + CORRADE_COMPARE(swizzle(orig, "zxwy"), swizzled); + CORRADE_COMPARE((swizzle<'z', 'x', 'w', 'y'>(orig)), swizzled); } void SwizzleTest::rgba() { Vector4 orig(2, 4, 5, 7); - CORRADE_COMPARE((swizzle<'b', 'r', 'a', 'g'>(orig)), Vector4(5, 2, 7, 4)); + Vector4 swizzled(5, 2, 7, 4); + CORRADE_COMPARE(swizzle(orig, "brag"), swizzled); + CORRADE_COMPARE((swizzle<'b', 'r', 'a', 'g'>(orig)), swizzled); +} + +void SwizzleTest::fromSmall() { + /* Force compile-time evaluation for both */ + constexpr Vector2 orig(1, 2); + CORRADE_VERIFY((integral_constant::value)); + CORRADE_COMPARE((swizzle<'g', 'x', 'r'>(orig)), Vector3(2, 1, 1)); } void SwizzleTest::type() { Vector4 orig; CORRADE_VERIFY((is_same(orig)), Vector2>::value)); + CORRADE_VERIFY((is_same::value)); CORRADE_VERIFY((is_same(orig)), Vector3>::value)); + CORRADE_VERIFY((is_same::value)); CORRADE_VERIFY((is_same(orig)), Vector4>::value)); + CORRADE_VERIFY((is_same::value)); } void SwizzleTest::defaultType() { Vector4 orig(1, 2, 3, 4); CORRADE_COMPARE(swizzle<'b'>(orig), Vector<1>(3)); + CORRADE_COMPARE(swizzle(orig, "b"), Vector<1>(3)); CORRADE_COMPARE((swizzle<'b', 'r', 'a', 'g', 'z', 'y', 'x'>(orig)), Vector<7>(3, 1, 4, 2, 3, 2, 1)); + CORRADE_COMPARE(swizzle(orig, "bragzyx"), Vector<7>(3, 1, 4, 2, 3, 2, 1)); } }}} diff --git a/src/Math/Test/SwizzleTest.h b/src/Math/Test/SwizzleTest.h index f68a05e45..a08dfdd17 100644 --- a/src/Math/Test/SwizzleTest.h +++ b/src/Math/Test/SwizzleTest.h @@ -25,6 +25,7 @@ class SwizzleTest: public Corrade::TestSuite::Tester { void xyzw(); void rgba(); + void fromSmall(); void type(); void defaultType(); }; diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 0a56fa479..7bd884fbc 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -26,11 +26,21 @@ namespace Magnum { namespace Math { -/** -@brief %Vector +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + template struct Sequence {}; -@todo Swizzling -*/ + /* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */ + template struct GenerateSequence: + GenerateSequence {}; + + template struct GenerateSequence<0, sequence...> { + typedef Sequence Type; + }; +} +#endif + +/** @brief %Vector */ template class Vector { public: const static size_t Size = size; /**< @brief %Vector size */