Browse Source

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.
pull/279/head
Vladimír Vondruš 14 years ago
parent
commit
c23022d47f
  1. 10
      src/Math/Matrix.h
  2. 51
      src/Math/Swizzle.h
  3. 21
      src/Math/Test/SwizzleTest.cpp
  4. 1
      src/Math/Test/SwizzleTest.h
  5. 18
      src/Math/Vector.h

10
src/Math/Matrix.h

@ -26,16 +26,6 @@ namespace Magnum { namespace Math {
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<size_t size, class T> class MatrixDeterminant;
template<size_t ...> struct Sequence {};
/* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */
template<size_t N, size_t ...sequence> struct GenerateSequence:
GenerateSequence<N-1, N-1, sequence...> {};
template<size_t ...sequence> struct GenerateSequence<0, sequence...> {
typedef Sequence<sequence...> Type;
};
}
#endif

51
src/Math/Swizzle.h

@ -48,6 +48,26 @@ namespace Implementation {
template<class T> struct TypeForSize<2, T> { typedef Vector2<T> Type; };
template<class T> struct TypeForSize<3, T> { typedef Vector3<T> Type; };
template<class T> struct TypeForSize<4, T> { typedef Vector4<T> Type; };
inline constexpr size_t getPosition(size_t size, size_t position) {
return size > position ? position : throw;
}
template<size_t size> 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<size_t size, class T, size_t ...sequence> inline constexpr Vector<sizeof...(sequence), T> swizzleFrom(Sequence<sequence...>, const Vector<size, T>& vector, const char(&components)[sizeof...(sequence)+1]) {
return {vector[getComponent<size>(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<size, T>&, 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<char ...components, size_t size, class T> inline constexpr typename Implementation::TypeForSize<sizeof...(components), T>::Type swizzle(const Vector<size, T>& vector) {
return {vector[Implementation::GetComponent<size, components>::value()]...};
}
/**
@brief Swizzle Vector components
Creates new vector from given components. Example:
@code
Vector4<int> 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<size, T>&), 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<size_t size, class T, size_t newSize> inline constexpr typename Implementation::TypeForSize<newSize-1, T>::Type swizzle(const Vector<size, T>& vector, const char(&components)[newSize]) {
return Implementation::swizzleFrom(typename Implementation::GenerateSequence<newSize-1>::Type(), vector, components);
}
}}
#endif

21
src/Math/Test/SwizzleTest.cpp

@ -32,31 +32,48 @@ template<size_t size> using Vector = Math::Vector<size, int>;
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<bool, swizzle(orig, "gxr").x() == 2>::value));
CORRADE_COMPARE((swizzle<'g', 'x', 'r'>(orig)), Vector3(2, 1, 1));
}
void SwizzleTest::type() {
Vector4 orig;
CORRADE_VERIFY((is_same<decltype(swizzle<'y', 'a'>(orig)), Vector2>::value));
CORRADE_VERIFY((is_same<decltype(swizzle(orig, "ya")), Vector2>::value));
CORRADE_VERIFY((is_same<decltype(swizzle<'y', 'z', 'a'>(orig)), Vector3>::value));
CORRADE_VERIFY((is_same<decltype(swizzle(orig, "yza")), Vector3>::value));
CORRADE_VERIFY((is_same<decltype(swizzle<'y', 'a', 'y', 'x'>(orig)), Vector4>::value));
CORRADE_VERIFY((is_same<decltype(swizzle(orig, "yayx")), Vector4>::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));
}
}}}

1
src/Math/Test/SwizzleTest.h

@ -25,6 +25,7 @@ class SwizzleTest: public Corrade::TestSuite::Tester<SwizzleTest> {
void xyzw();
void rgba();
void fromSmall();
void type();
void defaultType();
};

18
src/Math/Vector.h

@ -26,11 +26,21 @@
namespace Magnum { namespace Math {
/**
@brief %Vector
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<size_t ...> struct Sequence {};
@todo Swizzling
*/
/* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */
template<size_t N, size_t ...sequence> struct GenerateSequence:
GenerateSequence<N-1, N-1, sequence...> {};
template<size_t ...sequence> struct GenerateSequence<0, sequence...> {
typedef Sequence<sequence...> Type;
};
}
#endif
/** @brief %Vector */
template<size_t size, class T> class Vector {
public:
const static size_t Size = size; /**< @brief %Vector size */

Loading…
Cancel
Save