Common/Matrix: Allow TVec classes to be used in constexpr contexts

Much of these classes are operating on integral types and are pretty
standard behavior as far as vectors go. Some member functions can be
made constexpr to make them more flexible and allow them to be used in
constexpr contexts.
This commit is contained in:
Lioncash 2020-10-21 17:41:38 -04:00
parent de96fe0860
commit dcb0c910af

View file

@ -17,24 +17,24 @@ namespace Common
template <typename T> template <typename T>
union TVec3 union TVec3
{ {
TVec3() = default; constexpr TVec3() = default;
TVec3(T _x, T _y, T _z) : data{_x, _y, _z} {} constexpr TVec3(T _x, T _y, T _z) : data{_x, _y, _z} {}
template <typename OtherT> template <typename OtherT>
explicit TVec3(const TVec3<OtherT>& other) : TVec3(other.x, other.y, other.z) constexpr explicit TVec3(const TVec3<OtherT>& other) : TVec3(other.x, other.y, other.z)
{ {
} }
TVec3 Cross(const TVec3& rhs) const constexpr TVec3 Cross(const TVec3& rhs) const
{ {
return {(y * rhs.z) - (rhs.y * z), (z * rhs.x) - (rhs.z * x), (x * rhs.y) - (rhs.x * y)}; return {(y * rhs.z) - (rhs.y * z), (z * rhs.x) - (rhs.z * x), (x * rhs.y) - (rhs.x * y)};
} }
T Dot(const TVec3& other) const { return x * other.x + y * other.y + z * other.z; } constexpr T Dot(const TVec3& other) const { return x * other.x + y * other.y + z * other.z; }
T LengthSquared() const { return Dot(*this); } constexpr T LengthSquared() const { return Dot(*this); }
T Length() const { return std::sqrt(LengthSquared()); } T Length() const { return std::sqrt(LengthSquared()); }
TVec3 Normalized() const { return *this / Length(); } TVec3 Normalized() const { return *this / Length(); }
TVec3& operator+=(const TVec3& rhs) constexpr TVec3& operator+=(const TVec3& rhs)
{ {
x += rhs.x; x += rhs.x;
y += rhs.y; y += rhs.y;
@ -42,7 +42,7 @@ union TVec3
return *this; return *this;
} }
TVec3& operator-=(const TVec3& rhs) constexpr TVec3& operator-=(const TVec3& rhs)
{ {
x -= rhs.x; x -= rhs.x;
y -= rhs.y; y -= rhs.y;
@ -50,7 +50,7 @@ union TVec3
return *this; return *this;
} }
TVec3& operator*=(const TVec3& rhs) constexpr TVec3& operator*=(const TVec3& rhs)
{ {
x *= rhs.x; x *= rhs.x;
y *= rhs.y; y *= rhs.y;
@ -58,7 +58,7 @@ union TVec3
return *this; return *this;
} }
TVec3& operator/=(const TVec3& rhs) constexpr TVec3& operator/=(const TVec3& rhs)
{ {
x /= rhs.x; x /= rhs.x;
y /= rhs.y; y /= rhs.y;
@ -66,7 +66,7 @@ union TVec3
return *this; return *this;
} }
TVec3 operator-() const { return {-x, -y, -z}; } constexpr TVec3 operator-() const { return {-x, -y, -z}; }
// Apply function to each element and return the result. // Apply function to each element and return the result.
template <typename F> template <typename F>
@ -103,7 +103,7 @@ TVec3<bool> operator<(const TVec3<T>& lhs, const TVec3<T>& rhs)
return lhs.Map(std::less<T>{}, rhs); return lhs.Map(std::less<T>{}, rhs);
} }
inline TVec3<bool> operator!(const TVec3<bool>& vec) constexpr TVec3<bool> operator!(const TVec3<bool>& vec)
{ {
return {!vec.x, !vec.y, !vec.z}; return {!vec.x, !vec.y, !vec.z};
} }
@ -150,13 +150,16 @@ using DVec3 = TVec3<double>;
template <typename T> template <typename T>
union TVec4 union TVec4
{ {
TVec4() = default; constexpr TVec4() = default;
TVec4(TVec3<T> _vec, T _w) : TVec4{_vec.x, _vec.y, _vec.z, _w} {} constexpr TVec4(TVec3<T> _vec, T _w) : TVec4{_vec.x, _vec.y, _vec.z, _w} {}
TVec4(T _x, T _y, T _z, T _w) : data{_x, _y, _z, _w} {} constexpr TVec4(T _x, T _y, T _z, T _w) : data{_x, _y, _z, _w} {}
T Dot(const TVec4& other) const { return x * other.x + y * other.y + z * other.z + w * other.w; } constexpr T Dot(const TVec4& other) const
{
return x * other.x + y * other.y + z * other.z + w * other.w;
}
TVec4& operator*=(const TVec4& rhs) constexpr TVec4& operator*=(const TVec4& rhs)
{ {
x *= rhs.x; x *= rhs.x;
y *= rhs.y; y *= rhs.y;
@ -165,7 +168,7 @@ union TVec4
return *this; return *this;
} }
TVec4& operator/=(const TVec4& rhs) constexpr TVec4& operator/=(const TVec4& rhs)
{ {
x /= rhs.x; x /= rhs.x;
y /= rhs.y; y /= rhs.y;
@ -174,8 +177,8 @@ union TVec4
return *this; return *this;
} }
TVec4& operator*=(T scalar) { return *this *= TVec4{scalar, scalar, scalar, scalar}; } constexpr TVec4& operator*=(T scalar) { return *this *= TVec4{scalar, scalar, scalar, scalar}; }
TVec4& operator/=(T scalar) { return *this /= TVec4{scalar, scalar, scalar, scalar}; } constexpr TVec4& operator/=(T scalar) { return *this /= TVec4{scalar, scalar, scalar, scalar}; }
std::array<T, 4> data = {}; std::array<T, 4> data = {};
@ -189,13 +192,13 @@ union TVec4
}; };
template <typename T> template <typename T>
TVec4<T> operator*(TVec4<T> lhs, std::common_type_t<T> scalar) constexpr TVec4<T> operator*(TVec4<T> lhs, std::common_type_t<T> scalar)
{ {
return lhs *= scalar; return lhs *= scalar;
} }
template <typename T> template <typename T>
TVec4<T> operator/(TVec4<T> lhs, std::common_type_t<T> scalar) constexpr TVec4<T> operator/(TVec4<T> lhs, std::common_type_t<T> scalar)
{ {
return lhs /= scalar; return lhs /= scalar;
} }
@ -206,63 +209,63 @@ using DVec4 = TVec4<double>;
template <typename T> template <typename T>
union TVec2 union TVec2
{ {
TVec2() = default; constexpr TVec2() = default;
TVec2(T _x, T _y) : data{_x, _y} {} constexpr TVec2(T _x, T _y) : data{_x, _y} {}
template <typename OtherT> template <typename OtherT>
explicit TVec2(const TVec2<OtherT>& other) : TVec2(other.x, other.y) constexpr explicit TVec2(const TVec2<OtherT>& other) : TVec2(other.x, other.y)
{ {
} }
T Cross(const TVec2& rhs) const { return (x * rhs.y) - (y * rhs.x); } constexpr T Cross(const TVec2& rhs) const { return (x * rhs.y) - (y * rhs.x); }
T Dot(const TVec2& rhs) const { return (x * rhs.x) + (y * rhs.y); } constexpr T Dot(const TVec2& rhs) const { return (x * rhs.x) + (y * rhs.y); }
T LengthSquared() const { return Dot(*this); } constexpr T LengthSquared() const { return Dot(*this); }
T Length() const { return std::sqrt(LengthSquared()); } T Length() const { return std::sqrt(LengthSquared()); }
TVec2 Normalized() const { return *this / Length(); } TVec2 Normalized() const { return *this / Length(); }
TVec2& operator+=(const TVec2& rhs) constexpr TVec2& operator+=(const TVec2& rhs)
{ {
x += rhs.x; x += rhs.x;
y += rhs.y; y += rhs.y;
return *this; return *this;
} }
TVec2& operator-=(const TVec2& rhs) constexpr TVec2& operator-=(const TVec2& rhs)
{ {
x -= rhs.x; x -= rhs.x;
y -= rhs.y; y -= rhs.y;
return *this; return *this;
} }
TVec2& operator*=(const TVec2& rhs) constexpr TVec2& operator*=(const TVec2& rhs)
{ {
x *= rhs.x; x *= rhs.x;
y *= rhs.y; y *= rhs.y;
return *this; return *this;
} }
TVec2& operator/=(const TVec2& rhs) constexpr TVec2& operator/=(const TVec2& rhs)
{ {
x /= rhs.x; x /= rhs.x;
y /= rhs.y; y /= rhs.y;
return *this; return *this;
} }
TVec2& operator*=(T scalar) constexpr TVec2& operator*=(T scalar)
{ {
x *= scalar; x *= scalar;
y *= scalar; y *= scalar;
return *this; return *this;
} }
TVec2& operator/=(T scalar) constexpr TVec2& operator/=(T scalar)
{ {
x /= scalar; x /= scalar;
y /= scalar; y /= scalar;
return *this; return *this;
} }
TVec2 operator-() const { return {-x, -y}; } constexpr TVec2 operator-() const { return {-x, -y}; }
std::array<T, 2> data = {}; std::array<T, 2> data = {};
@ -274,48 +277,48 @@ union TVec2
}; };
template <typename T> template <typename T>
TVec2<bool> operator<(const TVec2<T>& lhs, const TVec2<T>& rhs) constexpr TVec2<bool> operator<(const TVec2<T>& lhs, const TVec2<T>& rhs)
{ {
return {lhs.x < rhs.x, lhs.y < rhs.y}; return {lhs.x < rhs.x, lhs.y < rhs.y};
} }
inline TVec2<bool> operator!(const TVec2<bool>& vec) constexpr TVec2<bool> operator!(const TVec2<bool>& vec)
{ {
return {!vec.x, !vec.y}; return {!vec.x, !vec.y};
} }
template <typename T> template <typename T>
TVec2<T> operator+(TVec2<T> lhs, const TVec2<T>& rhs) constexpr TVec2<T> operator+(TVec2<T> lhs, const TVec2<T>& rhs)
{ {
return lhs += rhs; return lhs += rhs;
} }
template <typename T> template <typename T>
TVec2<T> operator-(TVec2<T> lhs, const TVec2<T>& rhs) constexpr TVec2<T> operator-(TVec2<T> lhs, const TVec2<T>& rhs)
{ {
return lhs -= rhs; return lhs -= rhs;
} }
template <typename T> template <typename T>
TVec2<T> operator*(TVec2<T> lhs, const TVec2<T>& rhs) constexpr TVec2<T> operator*(TVec2<T> lhs, const TVec2<T>& rhs)
{ {
return lhs *= rhs; return lhs *= rhs;
} }
template <typename T> template <typename T>
TVec2<T> operator/(TVec2<T> lhs, const TVec2<T>& rhs) constexpr TVec2<T> operator/(TVec2<T> lhs, const TVec2<T>& rhs)
{ {
return lhs /= rhs; return lhs /= rhs;
} }
template <typename T, typename T2> template <typename T, typename T2>
auto operator*(TVec2<T> lhs, T2 scalar) constexpr auto operator*(TVec2<T> lhs, T2 scalar)
{ {
return TVec2<decltype(lhs.x * scalar)>(lhs) *= scalar; return TVec2<decltype(lhs.x * scalar)>(lhs) *= scalar;
} }
template <typename T, typename T2> template <typename T, typename T2>
auto operator/(TVec2<T> lhs, T2 scalar) constexpr auto operator/(TVec2<T> lhs, T2 scalar)
{ {
return TVec2<decltype(lhs.x / scalar)>(lhs) /= scalar; return TVec2<decltype(lhs.x / scalar)>(lhs) /= scalar;
} }