diff --git a/libs/math/include/math/TQuatHelpers.h b/libs/math/include/math/TQuatHelpers.h index e2a89dc0d7..0439b9712b 100644 --- a/libs/math/include/math/TQuatHelpers.h +++ b/libs/math/include/math/TQuatHelpers.h @@ -58,7 +58,7 @@ public: /* compound assignment products by a scalar */ - template + template>> constexpr QUATERNION& operator*=(U v) { QUATERNION& lhs = static_cast&>(*this); for (size_t i = 0; i < QUATERNION::size(); i++) { @@ -67,7 +67,7 @@ public: return lhs; } - template + template>> constexpr QUATERNION& operator/=(U v) { QUATERNION& lhs = static_cast&>(*this); for (size_t i = 0; i < QUATERNION::size(); i++) { @@ -125,25 +125,25 @@ public: * q.w*r.z + q.x*r.y - q.y*r.x + q.z*r.w); * */ - template + template>> friend inline constexpr QUATERNION> MATH_PURE operator*(QUATERNION q, U scalar) { // don't pass q by reference because we need a copy anyway - return q *= scalar; + return QUATERNION>(q *= scalar); } - template + template>> friend inline constexpr - QUATERNION> MATH_PURE operator*(T scalar, QUATERNION q) { + QUATERNION> MATH_PURE operator*(U scalar, QUATERNION q) { // don't pass q by reference because we need a copy anyway - return q *= scalar; + return QUATERNION>(q *= scalar); } - template + template>> friend inline constexpr QUATERNION> MATH_PURE operator/(QUATERNION q, U scalar) { // don't pass q by reference because we need a copy anyway - return q /= scalar; + return QUATERNION>(q /= scalar); } }; diff --git a/libs/math/tests/test_quat.cpp b/libs/math/tests/test_quat.cpp index 6a5849875e..044a272a7e 100644 --- a/libs/math/tests/test_quat.cpp +++ b/libs/math/tests/test_quat.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -324,3 +325,103 @@ TEST_F(QuatTest, NaN) { EXPECT_NEAR(qs[2], 0.5, 0.1); EXPECT_NEAR(qs[3], 0.5, 0.1); } + +TEST_F(QuatTest, Conversions) { + quat qd; + quatf qf; + float3 vf; + double3 vd; + double d = 0.0; + float f = 0.0f; + + static_assert(std::is_same, float>::value); + static_assert(std::is_same, double>::value); + static_assert(std::is_same, double>::value); + static_assert(std::is_same, double>::value); + + { + auto r1 = qd * d; + auto r2 = qd * f; + auto r3 = qf * d; + auto r4 = qf * f; + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + } + { + auto r1 = qd / d; + auto r2 = qd / f; + auto r3 = qf / d; + auto r4 = qf / f; + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + } + { + auto r1 = d * qd; + auto r2 = f * qd; + auto r3 = d * qf; + auto r4 = f * qf; + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + } + { + auto r1 = qd * vd; + auto r2 = qf * vd; + auto r3 = qd * vf; + auto r4 = qf * vf; + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + } + { + auto r1 = qd * qd; + auto r2 = qf * qd; + auto r3 = qd * qf; + auto r4 = qf * qf; + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + } + { + auto r1 = dot(qd, qd); + auto r2 = dot(qf, qd); + auto r3 = dot(qd, qf); + auto r4 = dot(qf, qf); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + } + { + auto r1 = cross(qd, qd); + auto r2 = cross(qf, qd); + auto r3 = cross(qd, qf); + auto r4 = cross(qf, qf); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + static_assert(std::is_same::value); + } +} + +template +struct has_divide_assign : std::false_type {}; + +template +struct has_divide_assign() /= std::declval(), void())> : std::true_type {}; + +// Static assertions to validate the availability of the /= operator for specific type +// combinations. The first static_assert checks that the quat does not have a /= operator with Foo. +// This ensures that quat does not provide an inappropriate overload that could be erroneously +// selected. +struct Foo {}; +static_assert(!has_divide_assign::value); +static_assert(has_divide_assign::value);