diff --git a/src/Magnum/Math/Color.h b/src/Magnum/Math/Color.h index 4a59d1f8f..3ffcb5028 100644 --- a/src/Magnum/Math/Color.h +++ b/src/Magnum/Math/Color.h @@ -715,6 +715,10 @@ template class Color3: public Vector3 { MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(3, Color3) }; +#ifdef CORRADE_MSVC2015_COMPATIBILITY +MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, Color3) +#endif + /** @brief Color in linear RGBA color space @@ -1184,6 +1188,10 @@ class Color4: public Vector4 { MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(4, Color4) }; +#ifdef CORRADE_MSVC2015_COMPATIBILITY +MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, Color4) +#endif + /** @relatesalso Color3 @brief Convert color from [CIE xyY representation](https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space) to CIE XYZ diff --git a/src/Magnum/Math/Test/ColorTest.cpp b/src/Magnum/Math/Test/ColorTest.cpp index c51fdb6f9..5d00ace53 100644 --- a/src/Magnum/Math/Test/ColorTest.cpp +++ b/src/Magnum/Math/Test/ColorTest.cpp @@ -125,6 +125,8 @@ struct ColorTest: TestSuite::Tester { void fromXyzDefaultAlpha(); void xyY(); + void multiplyDivideIntegral(); + void strictWeakOrdering(); void swizzleType(); @@ -253,6 +255,8 @@ ColorTest::ColorTest() { &ColorTest::fromXyzDefaultAlpha, &ColorTest::xyY, + &ColorTest::multiplyDivideIntegral, + &ColorTest::strictWeakOrdering, &ColorTest::swizzleType, @@ -1069,6 +1073,23 @@ void ColorTest::xyY() { CORRADE_COMPARE(xyYToXyz(xyY), xyz); } +void ColorTest::multiplyDivideIntegral() { + typedef Math::Color3 Color3i; + typedef Math::Color4 Color4i; + + const Color3i vector3{32, 10, -6}; + const Color4i vector4{32, 10, -6, 2}; + const Color3i multiplied3{-48, -15, 9}; + const Color4i multiplied4{-48, -15, 9, -3}; + + CORRADE_COMPARE(vector3*-1.5f, multiplied3); + CORRADE_COMPARE(vector4*-1.5f, multiplied4); + /* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong + result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ + CORRADE_COMPARE(-1.5f*vector3, multiplied3); + CORRADE_COMPARE(-1.5f*vector4, multiplied4); +} + void ColorTest::strictWeakOrdering() { StrictWeakOrdering o; diff --git a/src/Magnum/Math/Test/Vector2Test.cpp b/src/Magnum/Math/Test/Vector2Test.cpp index 823c97eeb..74bf98bd9 100644 --- a/src/Magnum/Math/Test/Vector2Test.cpp +++ b/src/Magnum/Math/Test/Vector2Test.cpp @@ -71,6 +71,8 @@ struct Vector2Test: TestSuite::Tester { void perpendicular(); void aspectRatio(); + void multiplyDivideIntegral(); + void strictWeakOrdering(); void swizzleType(); @@ -95,6 +97,8 @@ Vector2Test::Vector2Test() { &Vector2Test::perpendicular, &Vector2Test::aspectRatio, + &Vector2Test::multiplyDivideIntegral, + &Vector2Test::strictWeakOrdering, &Vector2Test::swizzleType, @@ -249,6 +253,16 @@ void Vector2Test::aspectRatio() { CORRADE_COMPARE(Vector2(3.0f, 4.0f).aspectRatio(), 0.75f); } +void Vector2Test::multiplyDivideIntegral() { + const Vector2i vector{32, -6}; + const Vector2i multiplied{-48, 9}; + + CORRADE_COMPARE(vector*-1.5f, multiplied); + /* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong + result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ + CORRADE_COMPARE(-1.5f*vector, multiplied); +} + void Vector2Test::strictWeakOrdering() { StrictWeakOrdering o; const Vector2 v2a{1.0f, 2.0f}; diff --git a/src/Magnum/Math/Test/Vector3Test.cpp b/src/Magnum/Math/Test/Vector3Test.cpp index 0e297e742..d125d686f 100644 --- a/src/Magnum/Math/Test/Vector3Test.cpp +++ b/src/Magnum/Math/Test/Vector3Test.cpp @@ -71,6 +71,8 @@ struct Vector3Test: TestSuite::Tester { void scales(); void twoComponent(); + void multiplyDivideIntegral(); + void strictWeakOrdering(); void swizzleType(); @@ -96,6 +98,8 @@ Vector3Test::Vector3Test() { &Vector3Test::scales, &Vector3Test::twoComponent, + &Vector3Test::multiplyDivideIntegral, + &Vector3Test::strictWeakOrdering, &Vector3Test::swizzleType, @@ -273,6 +277,16 @@ void Vector3Test::twoComponent() { CORRADE_COMPARE(d2, 2.0f); } +void Vector3Test::multiplyDivideIntegral() { + const Vector3i vector{32, 10, -6}; + const Vector3i multiplied{-48, -15, 9}; + + CORRADE_COMPARE(vector*-1.5f, multiplied); + /* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong + result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ + CORRADE_COMPARE(-1.5f*vector, multiplied); +} + void Vector3Test::strictWeakOrdering() { StrictWeakOrdering o; const Vector3 v3a{1.0f, 2.0f, 3.0f}; diff --git a/src/Magnum/Math/Test/Vector4Test.cpp b/src/Magnum/Math/Test/Vector4Test.cpp index 309ef4bc0..298d5e724 100644 --- a/src/Magnum/Math/Test/Vector4Test.cpp +++ b/src/Magnum/Math/Test/Vector4Test.cpp @@ -70,6 +70,8 @@ struct Vector4Test: TestSuite::Tester { void threeComponent(); void twoComponent(); + void multiplyDivideIntegral(); + void planeEquationThreePoints(); void planeEquationNormalPoint(); @@ -98,6 +100,8 @@ Vector4Test::Vector4Test() { &Vector4Test::threeComponent, &Vector4Test::twoComponent, + &Vector4Test::multiplyDivideIntegral, + &Vector4Test::planeEquationThreePoints, &Vector4Test::planeEquationNormalPoint, @@ -283,6 +287,16 @@ void Vector4Test::twoComponent() { CORRADE_COMPARE(d, 1.0f); } +void Vector4Test::multiplyDivideIntegral() { + const Vector4i vector{32, 10, -6, 2}; + const Vector4i multiplied{-48, -15, 9, -3}; + + CORRADE_COMPARE(vector*-1.5f, multiplied); + /* On MSVC 2015 this picks an int*Vector2i overload, leading to a wrong + result, unless MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() is used */ + CORRADE_COMPARE(-1.5f*vector, multiplied); +} + void Vector4Test::planeEquationThreePoints() { const Vector3 a{1.0f, 0.5f, 3.0f}; const Vector3 b{1.5f, 1.5f, 2.5f}; diff --git a/src/Magnum/Math/Test/VectorTest.cpp b/src/Magnum/Math/Test/VectorTest.cpp index 9fd4c8f7d..456fe6c92 100644 --- a/src/Magnum/Math/Test/VectorTest.cpp +++ b/src/Magnum/Math/Test/VectorTest.cpp @@ -734,6 +734,10 @@ template class BasicVec2: public Math::Vector<2, T> { MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(2, BasicVec2) }; +#ifdef CORRADE_MSVC2015_COMPATIBILITY +MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(2, BasicVec2) +#endif + typedef BasicVec2 Vec2; typedef BasicVec2 Vec2i; diff --git a/src/Magnum/Math/Vector.h b/src/Magnum/Math/Vector.h index ab42bed13..f4715f1bb 100644 --- a/src/Magnum/Math/Vector.h +++ b/src/Magnum/Math/Vector.h @@ -493,6 +493,10 @@ template class Vector { * * Same as @ref operator*(FloatingPoint) const. */ + /* Note that this one isn't correctly picked up on MSVC 2015, there's + an out-of-class overload wrapped in CORRADE_MSVC2015_COMPATIBILITY + which is (and the two don't conflict, apparently, so both are + present) */ #ifdef DOXYGEN_GENERATING_OUTPUT template friend Vector #else @@ -1442,6 +1446,25 @@ extern template MAGNUM_EXPORT Debug& operator<<(Debug&, const Vector<4, Double>& } #endif +#ifdef CORRADE_MSVC2015_COMPATIBILITY +/* MSVC 2015 doesn't correctly pick up the in-class inline friend that does + this, resulting in float*VectorNi expressions being wrongly executed as + int*VectorNi due to an implicit conversion fallback. This overload is picked + up correctly (and doesn't conflict with the in-class one), subclasses then + need to use the MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION() overloads as well + to return a correct subtype. See VectorTest::multiplyDivideIntegral(), + VectorTest::subclass() and corresponding cases in Vector2Test, Vector3Test, + Vector4Test and ColorTest for regression tests. */ +template inline typename std::enable_if::value && std::is_floating_point::value, Vector>::type operator*(FloatingPoint scalar, const Vector& vector) { + return vector*scalar; +} + +#define MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(size, Type) \ + template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(FloatingPoint scalar, const Type& vector) { \ + return vector*scalar; \ + } +#endif + template inline BitVector Vector::operator<(const Vector& other) const { BitVector out; diff --git a/src/Magnum/Math/Vector2.h b/src/Magnum/Math/Vector2.h index 7162e2d47..2ba33b8c9 100644 --- a/src/Magnum/Math/Vector2.h +++ b/src/Magnum/Math/Vector2.h @@ -235,6 +235,10 @@ template class Vector2: public Vector<2, T> { template friend U cross(const Vector2&, const Vector2&); }; +#ifdef CORRADE_MSVC2015_COMPATIBILITY +MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(2, Vector2) +#endif + namespace Implementation { template struct TypeForSize; template struct TypeForSize<2, T> { typedef Math::Vector2 Type; }; diff --git a/src/Magnum/Math/Vector3.h b/src/Magnum/Math/Vector3.h index 3cea7e3d2..49fe93ebc 100644 --- a/src/Magnum/Math/Vector3.h +++ b/src/Magnum/Math/Vector3.h @@ -262,6 +262,10 @@ template class Vector3: public Vector<3, T> { template friend Vector3 cross(const Vector3&, const Vector3&); }; +#ifdef CORRADE_MSVC2015_COMPATIBILITY +MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, Vector3) +#endif + #ifndef MAGNUM_NO_MATH_STRICT_WEAK_ORDERING namespace Implementation { template struct TypeForSize<3, T> { typedef Math::Vector3 Type; }; diff --git a/src/Magnum/Math/Vector4.h b/src/Magnum/Math/Vector4.h index 5e827f7c9..b3885a1e5 100644 --- a/src/Magnum/Math/Vector4.h +++ b/src/Magnum/Math/Vector4.h @@ -236,6 +236,10 @@ template class Vector4: public Vector<4, T> { MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(4, Vector4) }; +#ifdef CORRADE_MSVC2015_COMPATIBILITY +MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, Vector4) +#endif + /** @relatesalso Vector4 @brief Create a plane equation from three points