From 279856f239ed4f68f3ae686b1f0c49bc7ed9742a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 5 Mar 2024 13:40:37 +0100 Subject: [PATCH] Math: allow creating a Vector from a BitVector. And document the more flexible alternative using lerp(). --- doc/snippets/Math.cpp | 8 ++++++++ src/Magnum/Math/Color.h | 6 ++++++ src/Magnum/Math/Functions.h | 1 + src/Magnum/Math/Test/ColorTest.cpp | 23 +++++++++++++++++++++++ src/Magnum/Math/Test/Vector2Test.cpp | 16 ++++++++++++++++ src/Magnum/Math/Test/Vector3Test.cpp | 16 ++++++++++++++++ src/Magnum/Math/Test/Vector4Test.cpp | 16 ++++++++++++++++ src/Magnum/Math/Test/VectorTest.cpp | 16 ++++++++++++++++ src/Magnum/Math/Vector.h | 17 +++++++++++++++++ src/Magnum/Math/Vector2.h | 3 +++ src/Magnum/Math/Vector3.h | 3 +++ src/Magnum/Math/Vector4.h | 4 ++++ 12 files changed, 129 insertions(+) diff --git a/doc/snippets/Math.cpp b/doc/snippets/Math.cpp index 7a07eb991..5ff2f4430 100644 --- a/doc/snippets/Math.cpp +++ b/doc/snippets/Math.cpp @@ -1346,6 +1346,14 @@ Vector4i integral{floatingPoint}; // {1, 2, -15, 7} /* [Vector-conversion] */ } +{ +/* [Vector-conversion-bit] */ +BitVector3 mask = DOXYGEN_ELLIPSIS({}); +Vector3ub a = Math::lerp(Vector3ub{0}, Vector3ub{255}, mask); +/* [Vector-conversion-bit] */ +static_cast(a); +} + { /* [Vector-length-integer] */ Vector2i a{25, -1}; diff --git a/src/Magnum/Math/Color.h b/src/Magnum/Math/Color.h index 3b58fa2ec..81ac7bf81 100644 --- a/src/Magnum/Math/Color.h +++ b/src/Magnum/Math/Color.h @@ -571,6 +571,9 @@ template class Color3: public Vector3 { */ template constexpr explicit Color3(const Vector<3, U>& other) noexcept: Vector3(other) {} + /** @copydoc Vector::Vector(const BitVector&) */ + constexpr explicit Color3(const BitVector3& other) noexcept: Vector3{other} {} + /** @brief Construct color from external representation */ template { */ template constexpr explicit Color4(const Vector<4, U>& other) noexcept: Vector4(other) {} + /** @copydoc Vector::Vector(const BitVector&) */ + constexpr explicit Color4(const BitVector4& other) noexcept: Vector4{other} {} + /** @brief Construct color from external representation */ template inline T lerp(const T& a, const T& b, bool t) { Similar to the above, but instead of multiplication and addition it just does component-wise selection from either @p a or @p b based on values in @p t. @m_keyword{mix(),GLSL mix(),} +@see @ref Vector::Vector(const BitVector&) */ template inline Vector lerp(const Vector& a, const Vector& b, const BitVector& t) { Vector out{Magnum::NoInit}; diff --git a/src/Magnum/Math/Test/ColorTest.cpp b/src/Magnum/Math/Test/ColorTest.cpp index ac14200bd..382572ef0 100644 --- a/src/Magnum/Math/Test/ColorTest.cpp +++ b/src/Magnum/Math/Test/ColorTest.cpp @@ -84,6 +84,7 @@ struct ColorTest: TestSuite::Tester { void constructOneValue(); void constructParts(); void constructConversion(); + void constructBit(); void constructPacking(); void constructCopy(); void convert(); @@ -212,6 +213,7 @@ ColorTest::ColorTest() { &ColorTest::constructOneValue, &ColorTest::constructParts, &ColorTest::constructConversion, + &ColorTest::constructBit, &ColorTest::constructPacking, &ColorTest::constructCopy, &ColorTest::convert, @@ -426,6 +428,27 @@ void ColorTest::constructConversion() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void ColorTest::constructBit() { + BitVector3 a3{'\x5'}; /* 0b101 */ + BitVector4 a4{'\xa'}; /* 0b1010 */ + CORRADE_COMPARE(Color3{a3}, (Color3{1.0f, 0.0f, 1.0f})); + CORRADE_COMPARE(Color4ub{a4}, (Color4ub{0, 1, 0, 1})); + + constexpr BitVector3 ca3{'\x5'}; /* 0b101 */ + constexpr BitVector4 ca4{'\xa'}; /* 0b1010 */ + constexpr Color3 cb3{ca3}; + constexpr Color4ub cb4{ca4}; + CORRADE_COMPARE(cb3, (Color3{1.0f, 0.0f, 1.0f})); + CORRADE_COMPARE(cb4, (Color4ub{0, 1, 0, 1})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); + CORRADE_VERIFY(std::is_nothrow_constructible::value); +} + void ColorTest::constructPacking() { constexpr Color3 a(1.0f, 0.5f, 0.75f); auto b = Math::pack(a); diff --git a/src/Magnum/Math/Test/Vector2Test.cpp b/src/Magnum/Math/Test/Vector2Test.cpp index 8f81396e9..bc753bb4c 100644 --- a/src/Magnum/Math/Test/Vector2Test.cpp +++ b/src/Magnum/Math/Test/Vector2Test.cpp @@ -61,6 +61,7 @@ struct Vector2Test: TestSuite::Tester { void constructNoInit(); void constructOneValue(); void constructConversion(); + void constructBit(); void constructCopy(); void convert(); @@ -87,6 +88,7 @@ Vector2Test::Vector2Test() { &Vector2Test::constructNoInit, &Vector2Test::constructOneValue, &Vector2Test::constructConversion, + &Vector2Test::constructBit, &Vector2Test::constructCopy, &Vector2Test::convert, @@ -165,6 +167,20 @@ void Vector2Test::constructConversion() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void Vector2Test::constructBit() { + BitVector2 a{'\x1'}; /* 0b01 */ + CORRADE_COMPARE(Vector2{a}, (Vector2{1.0f, 0.0f})); + + constexpr BitVector2 ca{'\x1'}; /* 0b01 */ + constexpr Vector2 cb{ca}; + CORRADE_COMPARE(cb, (Vector2{1.0f, 0.0f})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); +} + void Vector2Test::constructCopy() { constexpr Vector<2, Float> a(1.5f, 2.5f); #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Why can't be copy constexpr? */ diff --git a/src/Magnum/Math/Test/Vector3Test.cpp b/src/Magnum/Math/Test/Vector3Test.cpp index 912033a5f..daa20ae01 100644 --- a/src/Magnum/Math/Test/Vector3Test.cpp +++ b/src/Magnum/Math/Test/Vector3Test.cpp @@ -62,6 +62,7 @@ struct Vector3Test: TestSuite::Tester { void constructOneValue(); void constructParts(); void constructConversion(); + void constructBit(); void constructCopy(); void convert(); @@ -89,6 +90,7 @@ Vector3Test::Vector3Test() { &Vector3Test::constructOneValue, &Vector3Test::constructParts, &Vector3Test::constructConversion, + &Vector3Test::constructBit, &Vector3Test::constructCopy, &Vector3Test::convert, @@ -174,6 +176,20 @@ void Vector3Test::constructConversion() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void Vector3Test::constructBit() { + BitVector3 a{'\x5'}; /* 0b101 */ + CORRADE_COMPARE(Vector3{a}, (Vector3{1.0f, 0.0f, 1.0f})); + + constexpr BitVector3 ca{'\x5'}; /* 0b101 */ + constexpr Vector3 cb{ca}; + CORRADE_COMPARE(cb, (Vector3{1.0f, 0.0f, 1.0f})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); +} + void Vector3Test::constructCopy() { constexpr Vector<3, Float> a(1.0f, 2.5f, -3.0f); #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Why can't be copy constexpr? */ diff --git a/src/Magnum/Math/Test/Vector4Test.cpp b/src/Magnum/Math/Test/Vector4Test.cpp index e0318709e..f94899e02 100644 --- a/src/Magnum/Math/Test/Vector4Test.cpp +++ b/src/Magnum/Math/Test/Vector4Test.cpp @@ -63,6 +63,7 @@ struct Vector4Test: TestSuite::Tester { void constructOneValue(); void constructParts(); void constructConversion(); + void constructBit(); void constructCopy(); void convert(); @@ -93,6 +94,7 @@ Vector4Test::Vector4Test() { &Vector4Test::constructOneValue, &Vector4Test::constructParts, &Vector4Test::constructConversion, + &Vector4Test::constructBit, &Vector4Test::constructCopy, &Vector4Test::convert, @@ -195,6 +197,20 @@ void Vector4Test::constructConversion() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void Vector4Test::constructBit() { + BitVector4 a{'\xa'}; /* 0b1010 */ + CORRADE_COMPARE(Vector4{a}, (Vector4{0.0f, 1.0f, 0.0f, 1.0f})); + + constexpr BitVector4 ca{'\xa'}; /* 0b1010 */ + constexpr Vector4 cb{ca}; + CORRADE_COMPARE(cb, (Vector4{0.0f, 1.0f, 0.0f, 1.0f})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); +} + void Vector4Test::constructCopy() { constexpr Vector<4, Float> a(1.0f, -2.5f, 3.0f, 4.1f); #ifndef CORRADE_MSVC2015_COMPATIBILITY /* Why can't be copy constexpr? */ diff --git a/src/Magnum/Math/Test/VectorTest.cpp b/src/Magnum/Math/Test/VectorTest.cpp index eb57ad4f1..bd90de797 100644 --- a/src/Magnum/Math/Test/VectorTest.cpp +++ b/src/Magnum/Math/Test/VectorTest.cpp @@ -66,6 +66,7 @@ struct VectorTest: TestSuite::Tester { void constructOneValue(); void constructOneComponent(); void constructConversion(); + void constructBit(); void constructCopy(); void convert(); @@ -144,6 +145,7 @@ VectorTest::VectorTest() { &VectorTest::constructOneValue, &VectorTest::constructOneComponent, &VectorTest::constructConversion, + &VectorTest::constructBit, &VectorTest::constructCopy, &VectorTest::convert, @@ -294,6 +296,20 @@ void VectorTest::constructConversion() { CORRADE_VERIFY(std::is_nothrow_constructible::value); } +void VectorTest::constructBit() { + BitVector4 a{'\xa'}; /* 0b1010 */ + CORRADE_COMPARE(Vector4{a}, (Vector4{0.0f, 1.0f, 0.0f, 1.0f})); + + constexpr BitVector4 ca{'\xa'}; /* 0b1010 */ + constexpr Vector4 cb{ca}; + CORRADE_COMPARE(cb, (Vector4{0.0f, 1.0f, 0.0f, 1.0f})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); +} + void VectorTest::constructCopy() { constexpr Vector4 a(1.0f, 3.5f, 4.0f, -2.7f); constexpr Vector4 b(a); diff --git a/src/Magnum/Math/Vector.h b/src/Magnum/Math/Vector.h index 21aaa3697..7c6d603d0 100644 --- a/src/Magnum/Math/Vector.h +++ b/src/Magnum/Math/Vector.h @@ -235,6 +235,20 @@ template class Vector { */ template constexpr explicit Vector(const Vector& other) noexcept: Vector(typename Containers::Implementation::GenerateSequence::Type{}, other) {} + /** + * @brief Construct a vector from a BitVector + * @m_since_latest + * + * Bits that are unset are converted to @cpp 0 @ce, set bits to + * @cpp 1 @ce. If you need a different behavior, for example converting + * a bit mask to @cpp 0 @ce or @cpp 255 @ce for a color representation, + * use @ref lerp(const Vector&, const Vector&, const BitVector&) + * instead, for example: + * + * @snippet Math.cpp Vector-conversion-bit + */ + constexpr explicit Vector(const BitVector& other) noexcept: Vector{typename Containers::Implementation::GenerateSequence::Type{}, other} {} + /** @brief Construct a vector from external representation */ template::from(std::declval()))> constexpr explicit Vector(const U& other) noexcept: Vector(Implementation::VectorConverter::from(other)) {} @@ -1252,6 +1266,9 @@ template class Vector { /* Implementation for Vector::Vector(const Vector&) */ template constexpr explicit Vector(Containers::Implementation::Sequence, const Vector& vector) noexcept: _data{T(vector._data[sequence])...} {} + /* Implementation for Vector::Vector(const BitVector&) */ + template constexpr explicit Vector(Containers::Implementation::Sequence, const BitVector& bitVector) noexcept: _data{T(bitVector[sequence])...} {} + /* Implementation for Vector::Vector(U) */ template constexpr explicit Vector(Containers::Implementation::Sequence, T value) noexcept: _data{Implementation::repeat(value, sequence)...} {} diff --git a/src/Magnum/Math/Vector2.h b/src/Magnum/Math/Vector2.h index a43d65a85..2bad26c23 100644 --- a/src/Magnum/Math/Vector2.h +++ b/src/Magnum/Math/Vector2.h @@ -140,6 +140,9 @@ template class Vector2: public Vector<2, T> { /** @copydoc Vector::Vector(const Vector&) */ template constexpr explicit Vector2(const Vector<2, U>& other) noexcept: Vector<2, T>(other) {} + /** @copydoc Vector::Vector(const BitVector&) */ + constexpr explicit Vector2(const BitVector2& other) noexcept: Vector<2, T>{other} {} + /** @brief Construct a vector from external representation */ template class Vector3: public Vector<3, T> { /** @copydoc Vector::Vector(const Vector&) */ template constexpr explicit Vector3(const Vector<3, U>& other) noexcept: Vector<3, T>(other) {} + /** @copydoc Vector::Vector(const BitVector&) */ + constexpr explicit Vector3(const BitVector3& other) noexcept: Vector<3, T>{other} {} + /** @brief Construct a vector from external representation */ template class Vector4: public Vector<4, T> { fire! FFS. */ template constexpr explicit Vector4(const Vector<4, U>& other) noexcept: Vector<4, T>(other) {} + /** @copydoc Magnum::Math::Vector::Vector(const BitVector&) */ + /* Lol and here too */ + constexpr explicit Vector4(const BitVector4& other) noexcept: Vector<4, T>{other} {} + /** @brief Construct a vector from external representation */ template::from(std::declval()))> constexpr explicit Vector4(const U& other): Vector<4, T>(Implementation::VectorConverter<4, T, U>::from(other)) {}