// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #pragma once #include #include namespace anki { template class TVec; #define ANKI_VEC_METHOD0(returnType, method) \ [[nodiscard]] returnType method() const \ { \ return OutVec(*this).method(); \ } #define ANKI_VEC_METHOD1(returnType, method, argType) \ [[nodiscard]] returnType method(argType arg0) const \ { \ return OutVec(*this).method(arg0); \ } #define ANKI_VEC_METHOD2(returnType, method, argType0, argType1) \ [[nodiscard]] returnType method(argType0 arg0, argType1 arg1) const \ { \ return OutVec(*this).method(arg0, arg1); \ } // The TVecXXXData classes need to re-define those and forward them to the actual TVec class. This is needed in cases we do something like: // a = v4.xyz.normalize(); #define ANKI_VEC_METHODS \ ANKI_VEC_METHOD1(OutVec, operator*, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator*, T) \ ANKI_VEC_METHOD1(OutVec, operator*=, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator*=, T) \ ANKI_VEC_METHOD1(OutVec, operator/, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator/, T) \ ANKI_VEC_METHOD1(OutVec, operator/=, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator/=, T) \ ANKI_VEC_METHOD1(OutVec, operator+, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator+, T) \ ANKI_VEC_METHOD1(OutVec, operator+=, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator+=, T) \ ANKI_VEC_METHOD1(OutVec, operator-, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator-, T) \ ANKI_VEC_METHOD1(OutVec, operator-=, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator-=, T) \ ANKI_VEC_METHOD0(OutVec, operator-) \ ANKI_VEC_METHOD1(OutVec, operator<<, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator<<, T) \ ANKI_VEC_METHOD1(OutVec, operator<<=, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator<<=, T) \ ANKI_VEC_METHOD1(OutVec, operator>>, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator>>, T) \ ANKI_VEC_METHOD1(OutVec, operator>>=, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator>>=, T) \ ANKI_VEC_METHOD1(OutVec, operator|, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator|, T) \ ANKI_VEC_METHOD1(OutVec, operator|=, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator|=, T) \ ANKI_VEC_METHOD1(OutVec, operator^, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator^, T) \ ANKI_VEC_METHOD1(OutVec, operator^=, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator^=, T) \ ANKI_VEC_METHOD1(OutVec, operator&, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator&, T) \ ANKI_VEC_METHOD1(OutVec, operator&=, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator&=, T) \ ANKI_VEC_METHOD1(OutVec, operator%, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator%, T) \ ANKI_VEC_METHOD1(OutVec, operator%=, OutVec) \ ANKI_VEC_METHOD1(OutVec, operator%=, T) \ ANKI_VEC_METHOD1(Bool, operator==, OutVec) \ ANKI_VEC_METHOD1(Bool, operator==, T) \ ANKI_VEC_METHOD1(Bool, operator<, OutVec) \ ANKI_VEC_METHOD1(Bool, operator<, T) \ ANKI_VEC_METHOD1(Bool, operator<=, OutVec) \ ANKI_VEC_METHOD1(Bool, operator<=, T) \ ANKI_VEC_METHOD1(Bool, operator>, OutVec) \ ANKI_VEC_METHOD1(Bool, operator>, T) \ ANKI_VEC_METHOD1(Bool, operator>=, OutVec) \ ANKI_VEC_METHOD1(Bool, operator>=, T) \ ANKI_VEC_METHOD1(T, dot, OutVec) \ ANKI_VEC_METHOD1(OutVec, cross, OutVec) \ ANKI_VEC_METHOD0(T, lengthSquared) \ ANKI_VEC_METHOD0(T, length) \ ANKI_VEC_METHOD0(OutVec, normalize) \ ANKI_VEC_METHOD2(OutVec, clamp, OutVec, OutVec) \ ANKI_VEC_METHOD2(OutVec, clamp, T, T) \ ANKI_VEC_METHOD0(U32, packSnorm4x8) \ ANKI_VEC_METHOD0(String, toString) template class TVecSwizzledData { public: static constexpr U32 kIndexCount = sizeof...(kIndices); using OutVec = TVec; using MainVec = TVec; // For doing something like this: v4.xw = Vec2(1.0f) MainVec& operator=(OutVec in) requires(kComponentCount >= kIndexCount) { const U32 indices[] = {kIndices...}; for(U32 i = 0; i < kIndexCount; ++i) { m_arr[indices[i]] = in.m_arr[i]; } return *reinterpret_cast(this); } // For doing something like this: v2 = v4.xw operator OutVec() const { OutVec vec; const U32 indices[] = {kIndices...}; for(U32 i = 0; i < kIndexCount; ++i) { vec.m_arr[i] = m_arr[indices[i]]; } return vec; } template Bool operator==(const TVecSwizzledData& b) const requires(sizeof...(kIndices) == sizeof...(kYIndices)) { return OutVec(*this) == OutVec(b); } ANKI_VEC_METHODS private: T m_arr[kComponentCount]; }; // Note: kSpecialConst is not of type T because some compilers don't like floats as template constants template class TVec4SpecialData { public: using OutVec = TVec; operator OutVec() const { OutVec vec; for(U32 i = 0; i < kComponentCount; ++i) { vec.m_arr[i] = m_arr[i]; } vec.m_arr[3] = T(kSpecialConst); return vec; } ANKI_VEC_METHODS private: T m_arr[kComponentCount]; }; template class TVecSimdData { public: T m_simd[kComponentCount]; }; template class TVecSimdData { public: #if ANKI_SIMD_SSE __m128 m_simd; #elif ANKI_SIMD_NEON float32x4_t m_simd; #else T m_simd[4]; #endif }; // Skip some warnings cause we really nead anonymous structs inside unions #if ANKI_COMPILER_MSVC # pragma warning(push) # pragma warning(disable : 4201) #elif ANKI_COMPILER_GCC_COMPATIBLE # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wgnu-anonymous-struct" # pragma GCC diagnostic ignored "-Wnested-anon-types" #endif template class TVecData; // Data specializations template class TVecData { public: using Simd = Array; union { struct { T x; T y; }; T m_carr[2]; Array m_arr; Simd m_simd; TVecSwizzledData xx; TVecSwizzledData xy; TVecSwizzledData yx; TVecSwizzledData yy; TVecSwizzledData xxx; TVecSwizzledData xxy; TVecSwizzledData xyx; TVecSwizzledData xyy; TVecSwizzledData yxx; TVecSwizzledData yxy; TVecSwizzledData yyx; TVecSwizzledData yyy; TVecSwizzledData xxxx; TVecSwizzledData xxxy; TVecSwizzledData xxyx; TVecSwizzledData xxyy; TVecSwizzledData xyxx; TVecSwizzledData xyxy; TVecSwizzledData xyyx; TVecSwizzledData xyyy; TVecSwizzledData yxxx; TVecSwizzledData yxxy; TVecSwizzledData yxyx; TVecSwizzledData yxyy; TVecSwizzledData yyxx; TVecSwizzledData yyxy; TVecSwizzledData yyyx; TVecSwizzledData yyyy; }; constexpr TVecData(T x_, T y_) : x(x_) , y(y_) { } constexpr TVecData() : TVecData(T(0.0f), T(0.0f)) { } }; template class TVecData { public: using Simd = Array; union { struct { T x; T y; T z; }; T m_carr[3]; Array m_arr; Simd m_simd; TVec4SpecialData xyz0; TVec4SpecialData xyz1; TVecSwizzledData xx; TVecSwizzledData xy; TVecSwizzledData xz; TVecSwizzledData yx; TVecSwizzledData yy; TVecSwizzledData yz; TVecSwizzledData zx; TVecSwizzledData zy; TVecSwizzledData zz; TVecSwizzledData xxx; TVecSwizzledData xxy; TVecSwizzledData xxz; TVecSwizzledData xyx; TVecSwizzledData xyy; TVecSwizzledData xyz; TVecSwizzledData xzx; TVecSwizzledData xzy; TVecSwizzledData xzz; TVecSwizzledData yxx; TVecSwizzledData yxy; TVecSwizzledData yxz; TVecSwizzledData yyx; TVecSwizzledData yyy; TVecSwizzledData yyz; TVecSwizzledData yzx; TVecSwizzledData yzy; TVecSwizzledData yzz; TVecSwizzledData zxx; TVecSwizzledData zxy; TVecSwizzledData zxz; TVecSwizzledData zyx; TVecSwizzledData zyy; TVecSwizzledData zyz; TVecSwizzledData zzx; TVecSwizzledData zzy; TVecSwizzledData zzz; TVecSwizzledData xxxx; TVecSwizzledData xxxy; TVecSwizzledData xxxz; TVecSwizzledData xxyx; TVecSwizzledData xxyy; TVecSwizzledData xxyz; TVecSwizzledData xxzx; TVecSwizzledData xxzy; TVecSwizzledData xxzz; TVecSwizzledData xyxx; TVecSwizzledData xyxy; TVecSwizzledData xyxz; TVecSwizzledData xyyx; TVecSwizzledData xyyy; TVecSwizzledData xyyz; TVecSwizzledData xyzx; TVecSwizzledData xyzy; TVecSwizzledData xyzz; TVecSwizzledData xzxx; TVecSwizzledData xzxy; TVecSwizzledData xzxz; TVecSwizzledData xzyx; TVecSwizzledData xzyy; TVecSwizzledData xzyz; TVecSwizzledData xzzx; TVecSwizzledData xzzy; TVecSwizzledData xzzz; TVecSwizzledData yxxx; TVecSwizzledData yxxy; TVecSwizzledData yxxz; TVecSwizzledData yxyx; TVecSwizzledData yxyy; TVecSwizzledData yxyz; TVecSwizzledData yxzx; TVecSwizzledData yxzy; TVecSwizzledData yxzz; TVecSwizzledData yyxx; TVecSwizzledData yyxy; TVecSwizzledData yyxz; TVecSwizzledData yyyx; TVecSwizzledData yyyy; TVecSwizzledData yyyz; TVecSwizzledData yyzx; TVecSwizzledData yyzy; TVecSwizzledData yyzz; TVecSwizzledData yzxx; TVecSwizzledData yzxy; TVecSwizzledData yzxz; TVecSwizzledData yzyx; TVecSwizzledData yzyy; TVecSwizzledData yzyz; TVecSwizzledData yzzx; TVecSwizzledData yzzy; TVecSwizzledData yzzz; TVecSwizzledData zxxx; TVecSwizzledData zxxy; TVecSwizzledData zxxz; TVecSwizzledData zxyx; TVecSwizzledData zxyy; TVecSwizzledData zxyz; TVecSwizzledData zxzx; TVecSwizzledData zxzy; TVecSwizzledData zxzz; TVecSwizzledData zyxx; TVecSwizzledData zyxy; TVecSwizzledData zyxz; TVecSwizzledData zyyx; TVecSwizzledData zyyy; TVecSwizzledData zyyz; TVecSwizzledData zyzx; TVecSwizzledData zyzy; TVecSwizzledData zyzz; TVecSwizzledData zzxx; TVecSwizzledData zzxy; TVecSwizzledData zzxz; TVecSwizzledData zzyx; TVecSwizzledData zzyy; TVecSwizzledData zzyz; TVecSwizzledData zzzx; TVecSwizzledData zzzy; TVecSwizzledData zzzz; }; constexpr TVecData(T x_, T y_, T z_) : x(x_) , y(y_) , z(z_) { } constexpr TVecData() : TVecData(T(0.0f), T(0.0f), T(0.0f)) { } }; template class TVecData { public: using Simd = MathSimd::Type; union { struct { T x; T y; T z; T w; }; T m_carr[4]; Array m_arr; Simd m_simd; TVec4SpecialData xyz0; TVec4SpecialData xyz1; TVecSwizzledData xx; TVecSwizzledData xy; TVecSwizzledData xz; TVecSwizzledData xw; TVecSwizzledData yx; TVecSwizzledData yy; TVecSwizzledData yz; TVecSwizzledData yw; TVecSwizzledData zx; TVecSwizzledData zy; TVecSwizzledData zz; TVecSwizzledData zw; TVecSwizzledData wx; TVecSwizzledData wy; TVecSwizzledData wz; TVecSwizzledData ww; TVecSwizzledData xxx; TVecSwizzledData xxy; TVecSwizzledData xxz; TVecSwizzledData xxw; TVecSwizzledData xyx; TVecSwizzledData xyy; TVecSwizzledData xyz; TVecSwizzledData xyw; TVecSwizzledData xzx; TVecSwizzledData xzy; TVecSwizzledData xzz; TVecSwizzledData xzw; TVecSwizzledData xwx; TVecSwizzledData xwy; TVecSwizzledData xwz; TVecSwizzledData xww; TVecSwizzledData yxx; TVecSwizzledData yxy; TVecSwizzledData yxz; TVecSwizzledData yxw; TVecSwizzledData yyx; TVecSwizzledData yyy; TVecSwizzledData yyz; TVecSwizzledData yyw; TVecSwizzledData yzx; TVecSwizzledData yzy; TVecSwizzledData yzz; TVecSwizzledData yzw; TVecSwizzledData ywx; TVecSwizzledData ywy; TVecSwizzledData ywz; TVecSwizzledData yww; TVecSwizzledData zxx; TVecSwizzledData zxy; TVecSwizzledData zxz; TVecSwizzledData zxw; TVecSwizzledData zyx; TVecSwizzledData zyy; TVecSwizzledData zyz; TVecSwizzledData zyw; TVecSwizzledData zzx; TVecSwizzledData zzy; TVecSwizzledData zzz; TVecSwizzledData zzw; TVecSwizzledData zwx; TVecSwizzledData zwy; TVecSwizzledData zwz; TVecSwizzledData zww; TVecSwizzledData wxx; TVecSwizzledData wxy; TVecSwizzledData wxz; TVecSwizzledData wxw; TVecSwizzledData wyx; TVecSwizzledData wyy; TVecSwizzledData wyz; TVecSwizzledData wyw; TVecSwizzledData wzx; TVecSwizzledData wzy; TVecSwizzledData wzz; TVecSwizzledData wzw; TVecSwizzledData wwx; TVecSwizzledData wwy; TVecSwizzledData wwz; TVecSwizzledData www; TVecSwizzledData xxxx; TVecSwizzledData xxxy; TVecSwizzledData xxxz; TVecSwizzledData xxxw; TVecSwizzledData xxyx; TVecSwizzledData xxyy; TVecSwizzledData xxyz; TVecSwizzledData xxyw; TVecSwizzledData xxzx; TVecSwizzledData xxzy; TVecSwizzledData xxzz; TVecSwizzledData xxzw; TVecSwizzledData xxwx; TVecSwizzledData xxwy; TVecSwizzledData xxwz; TVecSwizzledData xxww; TVecSwizzledData xyxx; TVecSwizzledData xyxy; TVecSwizzledData xyxz; TVecSwizzledData xyxw; TVecSwizzledData xyyx; TVecSwizzledData xyyy; TVecSwizzledData xyyz; TVecSwizzledData xyyw; TVecSwizzledData xyzx; TVecSwizzledData xyzy; TVecSwizzledData xyzz; TVecSwizzledData xyzw; TVecSwizzledData xywx; TVecSwizzledData xywy; TVecSwizzledData xywz; TVecSwizzledData xyww; TVecSwizzledData xzxx; TVecSwizzledData xzxy; TVecSwizzledData xzxz; TVecSwizzledData xzxw; TVecSwizzledData xzyx; TVecSwizzledData xzyy; TVecSwizzledData xzyz; TVecSwizzledData xzyw; TVecSwizzledData xzzx; TVecSwizzledData xzzy; TVecSwizzledData xzzz; TVecSwizzledData xzzw; TVecSwizzledData xzwx; TVecSwizzledData xzwy; TVecSwizzledData xzwz; TVecSwizzledData xzww; TVecSwizzledData xwxx; TVecSwizzledData xwxy; TVecSwizzledData xwxz; TVecSwizzledData xwxw; TVecSwizzledData xwyx; TVecSwizzledData xwyy; TVecSwizzledData xwyz; TVecSwizzledData xwyw; TVecSwizzledData xwzx; TVecSwizzledData xwzy; TVecSwizzledData xwzz; TVecSwizzledData xwzw; TVecSwizzledData xwwx; TVecSwizzledData xwwy; TVecSwizzledData xwwz; TVecSwizzledData xwww; TVecSwizzledData yxxx; TVecSwizzledData yxxy; TVecSwizzledData yxxz; TVecSwizzledData yxxw; TVecSwizzledData yxyx; TVecSwizzledData yxyy; TVecSwizzledData yxyz; TVecSwizzledData yxyw; TVecSwizzledData yxzx; TVecSwizzledData yxzy; TVecSwizzledData yxzz; TVecSwizzledData yxzw; TVecSwizzledData yxwx; TVecSwizzledData yxwy; TVecSwizzledData yxwz; TVecSwizzledData yxww; TVecSwizzledData yyxx; TVecSwizzledData yyxy; TVecSwizzledData yyxz; TVecSwizzledData yyxw; TVecSwizzledData yyyx; TVecSwizzledData yyyy; TVecSwizzledData yyyz; TVecSwizzledData yyyw; TVecSwizzledData yyzx; TVecSwizzledData yyzy; TVecSwizzledData yyzz; TVecSwizzledData yyzw; TVecSwizzledData yywx; TVecSwizzledData yywy; TVecSwizzledData yywz; TVecSwizzledData yyww; TVecSwizzledData yzxx; TVecSwizzledData yzxy; TVecSwizzledData yzxz; TVecSwizzledData yzxw; TVecSwizzledData yzyx; TVecSwizzledData yzyy; TVecSwizzledData yzyz; TVecSwizzledData yzyw; TVecSwizzledData yzzx; TVecSwizzledData yzzy; TVecSwizzledData yzzz; TVecSwizzledData yzzw; TVecSwizzledData yzwx; TVecSwizzledData yzwy; TVecSwizzledData yzwz; TVecSwizzledData yzww; TVecSwizzledData ywxx; TVecSwizzledData ywxy; TVecSwizzledData ywxz; TVecSwizzledData ywxw; TVecSwizzledData ywyx; TVecSwizzledData ywyy; TVecSwizzledData ywyz; TVecSwizzledData ywyw; TVecSwizzledData ywzx; TVecSwizzledData ywzy; TVecSwizzledData ywzz; TVecSwizzledData ywzw; TVecSwizzledData ywwx; TVecSwizzledData ywwy; TVecSwizzledData ywwz; TVecSwizzledData ywww; TVecSwizzledData zxxx; TVecSwizzledData zxxy; TVecSwizzledData zxxz; TVecSwizzledData zxxw; TVecSwizzledData zxyx; TVecSwizzledData zxyy; TVecSwizzledData zxyz; TVecSwizzledData zxyw; TVecSwizzledData zxzx; TVecSwizzledData zxzy; TVecSwizzledData zxzz; TVecSwizzledData zxzw; TVecSwizzledData zxwx; TVecSwizzledData zxwy; TVecSwizzledData zxwz; TVecSwizzledData zxww; TVecSwizzledData zyxx; TVecSwizzledData zyxy; TVecSwizzledData zyxz; TVecSwizzledData zyxw; TVecSwizzledData zyyx; TVecSwizzledData zyyy; TVecSwizzledData zyyz; TVecSwizzledData zyyw; TVecSwizzledData zyzx; TVecSwizzledData zyzy; TVecSwizzledData zyzz; TVecSwizzledData zyzw; TVecSwizzledData zywx; TVecSwizzledData zywy; TVecSwizzledData zywz; TVecSwizzledData zyww; TVecSwizzledData zzxx; TVecSwizzledData zzxy; TVecSwizzledData zzxz; TVecSwizzledData zzxw; TVecSwizzledData zzyx; TVecSwizzledData zzyy; TVecSwizzledData zzyz; TVecSwizzledData zzyw; TVecSwizzledData zzzx; TVecSwizzledData zzzy; TVecSwizzledData zzzz; TVecSwizzledData zzzw; TVecSwizzledData zzwx; TVecSwizzledData zzwy; TVecSwizzledData zzwz; TVecSwizzledData zzww; TVecSwizzledData zwxx; TVecSwizzledData zwxy; TVecSwizzledData zwxz; TVecSwizzledData zwxw; TVecSwizzledData zwyx; TVecSwizzledData zwyy; TVecSwizzledData zwyz; TVecSwizzledData zwyw; TVecSwizzledData zwzx; TVecSwizzledData zwzy; TVecSwizzledData zwzz; TVecSwizzledData zwzw; TVecSwizzledData zwwx; TVecSwizzledData zwwy; TVecSwizzledData zwwz; TVecSwizzledData zwww; TVecSwizzledData wxxx; TVecSwizzledData wxxy; TVecSwizzledData wxxz; TVecSwizzledData wxxw; TVecSwizzledData wxyx; TVecSwizzledData wxyy; TVecSwizzledData wxyz; TVecSwizzledData wxyw; TVecSwizzledData wxzx; TVecSwizzledData wxzy; TVecSwizzledData wxzz; TVecSwizzledData wxzw; TVecSwizzledData wxwx; TVecSwizzledData wxwy; TVecSwizzledData wxwz; TVecSwizzledData wxww; TVecSwizzledData wyxx; TVecSwizzledData wyxy; TVecSwizzledData wyxz; TVecSwizzledData wyxw; TVecSwizzledData wyyx; TVecSwizzledData wyyy; TVecSwizzledData wyyz; TVecSwizzledData wyyw; TVecSwizzledData wyzx; TVecSwizzledData wyzy; TVecSwizzledData wyzz; TVecSwizzledData wyzw; TVecSwizzledData wywx; TVecSwizzledData wywy; TVecSwizzledData wywz; TVecSwizzledData wyww; TVecSwizzledData wzxx; TVecSwizzledData wzxy; TVecSwizzledData wzxz; TVecSwizzledData wzxw; TVecSwizzledData wzyx; TVecSwizzledData wzyy; TVecSwizzledData wzyz; TVecSwizzledData wzyw; TVecSwizzledData wzzx; TVecSwizzledData wzzy; TVecSwizzledData wzzz; TVecSwizzledData wzzw; TVecSwizzledData wzwx; TVecSwizzledData wzwy; TVecSwizzledData wzwz; TVecSwizzledData wzww; TVecSwizzledData wwxx; TVecSwizzledData wwxy; TVecSwizzledData wwxz; TVecSwizzledData wwxw; TVecSwizzledData wwyx; TVecSwizzledData wwyy; TVecSwizzledData wwyz; TVecSwizzledData wwyw; TVecSwizzledData wwzx; TVecSwizzledData wwzy; TVecSwizzledData wwzz; TVecSwizzledData wwzw; TVecSwizzledData wwwx; TVecSwizzledData wwwy; TVecSwizzledData wwwz; TVecSwizzledData wwww; }; constexpr TVecData(T x_, T y_, T z_, T w_) : x(x_) , y(y_) , z(z_) , w(w_) { } constexpr TVecData() : TVecData(T(0.0f), T(0.0f), T(0.0f), T(0.0f)) { } }; #if ANKI_COMPILER_MSVC # pragma warning(pop) #elif ANKI_COMPILER_GCC_COMPATIBLE # pragma GCC diagnostic pop #endif template class TVec : public TVecData { public: using Scalar = T; static constexpr Bool kVec4Simd = kTComponentCount == 4 && std::is_same::value && ANKI_ENABLE_SIMD; static constexpr Bool kIsInteger = std::is_integral::value; static constexpr U32 kComponentCount = kTComponentCount; using Base = TVecData; using Base::m_arr; using Base::m_simd; // Constructors constexpr TVec() : Base() { } explicit TVec(T f) { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE m_simd = _mm_set1_ps(f); #else m_simd = vdupq_n_f32(f); #endif } else { for(U32 i = 0; i < kTComponentCount; ++i) { m_arr[i] = f; } } } // Copy TVec(const TVec& b) { if constexpr(kVec4Simd) { m_simd = b.m_simd; } else { for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] = b.m_arr[i]; } } } // Convert from another type. From int to float vectors and the opposite. template explicit TVec(const TVec& b) requires(!std::is_same::value) { for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] = T(b[i]); } } // Convert from the swizzle of another type. From int to float vectors and the opposite. template explicit TVec(const TVecSwizzledData& b) requires(!std::is_same::value) { const TVec bb = b; for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] = T(bb[i]); } } // Convert from the swizzle of another type. From int to float vectors and the opposite. template explicit TVec(const TVec4SpecialData& b) requires(!std::is_same::value && kTComponentCount == 4) { const TVec bb = b; for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] = T(bb[i]); } } explicit TVec(const T arr[]) { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE m_simd = _mm_load_ps(arr); #else m_simd = vld1q_f32(arr); #endif } else { for(U32 i = 0; i < kTComponentCount; ++i) { m_arr[i] = arr[i]; } } } explicit TVec(const Array& arr) : TVec(arr.getBegin()) { } // Vec2 specific constexpr TVec(T x, T y) requires(kTComponentCount == 2) : Base(x, y) { } // Vec2 specific constexpr TVec(T x, T y, T z) requires(kTComponentCount == 3) : Base(x, y, z) { } constexpr TVec(TVec a, T z) requires(kTComponentCount == 3) : Base(a.m_arr[0], a.m_arr[1], z) { } constexpr TVec(T x, TVec a) requires(kTComponentCount == 3) : Base(x, a.m_arr[0], a.m_arr[1]) { } // Vec4 specific explicit TVec(T x, T y, T z, T w) requires(kTComponentCount == 4) { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE m_simd = _mm_set_ps(w, z, y, x); #else alignas(16) T data[4] = {x, y, z, w}; m_simd = vld1q_f32(data); #endif } else { this->m_arr = {x, y, z, w}; } } constexpr TVec(TVec a, T w) requires(kTComponentCount == 4) : Base(a.m_arr[0], a.m_arr[1], a.m_arr[2], w) { } constexpr TVec(T x, TVec a) requires(kTComponentCount == 4) : Base(x, a.m_arr[0], a.m_arr[1], a.m_arr[2]) { } constexpr TVec(TVec a, T z, T w) requires(kTComponentCount == 4) : Base(a.m_arr[0], a.m_arr[1], z, w) { } constexpr TVec(T x, TVec a, T w) requires(kTComponentCount == 4) : Base(x, a.m_arr[0], a.m_arr[1], w) { } constexpr TVec(T x, T y, TVec a) requires(kTComponentCount == 4) : Base(x, y, a.m_arr[0], a.m_arr[1]) { } constexpr TVec(TVec a, TVec b) requires(kTComponentCount == 4) : Base(a.m_arr[0], a.m_arr[1], b.m_arr[0], b.m_arr[1]) { } explicit TVec(Base::Simd simd) requires(kTComponentCount == 4) { m_simd = simd; } // Accessors T& operator[](U32 i) { return m_arr[i]; } T operator[](U32 i) const { return m_arr[i]; } // Operators with the same type // Copy TVec& operator=(const TVec& b) { if constexpr(kVec4Simd) { m_simd = b.m_simd; } else { for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] = b.m_carr[i]; } } return *this; } [[nodiscard]] TVec operator+(TVec b) const { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE return TVec(_mm_add_ps(m_simd, b.m_simd)); #else return TVec(vaddq_f32(m_simd, b.m_simd)); #endif } else { TVec out; for(U32 i = 0; i < kTComponentCount; i++) { out.m_arr[i] = m_arr[i] + b.m_arr[i]; } return out; } } TVec& operator+=(TVec b) { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE m_simd = _mm_add_ps(m_simd, b.m_simd); #else m_simd = vaddq_f32(m_simd, b.m_simd); #endif } else { for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] += b.m_arr[i]; } } return *this; } [[nodiscard]] TVec operator-(TVec b) const { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE return TVec(_mm_sub_ps(m_simd, b.m_simd)); #else return TVec(vsubq_f32(m_simd, b.m_simd)); #endif } else { TVec out; for(U32 i = 0; i < kTComponentCount; i++) { out.m_arr[i] = m_arr[i] - b.m_arr[i]; } return out; } } TVec& operator-=(TVec b) { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE m_simd = _mm_sub_ps(m_simd, b.m_simd); #else m_simd = vsubq_f32(m_simd, b.m_simd); #endif } else { for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] -= b.m_arr[i]; } } return *this; } [[nodiscard]] TVec operator*(TVec b) const { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE return TVec(_mm_mul_ps(m_simd, b.m_simd)); #else return TVec(vmulq_f32(m_simd, b.m_simd)); #endif } else { TVec out; for(U32 i = 0; i < kTComponentCount; i++) { out.m_arr[i] = m_arr[i] * b.m_arr[i]; } return out; } } TVec& operator*=(TVec b) { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE m_simd = _mm_mul_ps(m_simd, b.m_simd); #else m_simd = vmulq_f32(m_simd, b.m_simd); #endif } else { for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] *= b.m_arr[i]; } } return *this; } [[nodiscard]] TVec operator/(TVec b) const { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE return TVec(_mm_div_ps(m_simd, b.m_simd)); #else return TVec(vdivq_f32(m_simd, b.m_simd)); #endif } else { TVec out; for(U32 i = 0; i < kTComponentCount; i++) { ANKI_ASSERT(b.m_arr[i] != 0.0); out.m_arr[i] = m_arr[i] / b.m_arr[i]; } return out; } } TVec& operator/=(TVec b) { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE m_simd = _mm_div_ps(m_simd, b.m_simd); #else m_simd = vdivq_f32(m_simd, b.m_simd); #endif } else { for(U32 i = 0; i < kTComponentCount; i++) { ANKI_ASSERT(b.m_arr[i] != 0.0); m_arr[i] /= b.m_arr[i]; } } return *this; } [[nodiscard]] TVec operator-() const { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE return TVec(_mm_xor_ps(m_simd, _mm_set1_ps(-0.0))); #else return TVec(veorq_s32(m_simd, vdupq_n_f32(-0.0))); #endif } else { TVec out; for(U32 i = 0; i < kTComponentCount; i++) { out.m_arr[i] = -m_arr[i]; } return out; } } [[nodiscard]] TVec operator<<(TVec b) const requires(kIsInteger) { TVec out; for(U32 i = 0; i < kTComponentCount; i++) { out.m_arr[i] = m_arr[i] << b.m_arr[i]; } return out; } TVec& operator<<=(TVec b) requires(kIsInteger) { for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] <<= b.m_arr[i]; } return *this; } [[nodiscard]] TVec operator>>(TVec b) const requires(kIsInteger) { TVec out; for(U32 i = 0; i < kTComponentCount; i++) { out.m_arr[i] = m_arr[i] >> b.m_arr[i]; } return out; } TVec& operator>>=(TVec b) requires(kIsInteger) { for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] >>= b.m_arr[i]; } return *this; } [[nodiscard]] TVec operator&(TVec b) const requires(kIsInteger) { TVec out; for(U32 i = 0; i < kTComponentCount; i++) { out.m_arr[i] = m_arr[i] & b.m_arr[i]; } return out; } TVec& operator&=(TVec b) requires(kIsInteger) { for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] &= b.m_arr[i]; } return *this; } [[nodiscard]] TVec operator|(TVec b) const requires(kIsInteger) { TVec out; for(U32 i = 0; i < kTComponentCount; i++) { out.m_arr[i] = m_arr[i] | b.m_arr[i]; } return out; } TVec& operator|=(TVec b) requires(kIsInteger) { for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] |= b.m_arr[i]; } return *this; } [[nodiscard]] TVec operator^(TVec b) const requires(kIsInteger) { TVec out; for(U32 i = 0; i < kTComponentCount; i++) { out.m_arr[i] = m_arr[i] ^ b.m_arr[i]; } return out; } TVec& operator^=(TVec b) requires(kIsInteger) { for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] ^= b.m_arr[i]; } return *this; } [[nodiscard]] TVec operator%(TVec b) const requires(kIsInteger) { TVec out; for(U32 i = 0; i < kTComponentCount; i++) { out.m_arr[i] = m_arr[i] % b.m_arr[i]; } return out; } TVec& operator%=(TVec b) requires(kIsInteger) { for(U32 i = 0; i < kTComponentCount; i++) { m_arr[i] %= b.m_arr[i]; } return *this; } [[nodiscard]] Bool operator==(TVec b) const { for(U32 i = 0; i < kTComponentCount; i++) { if(!isZero(m_arr[i] - b.m_arr[i])) { return false; } } return true; } [[nodiscard]] Bool operator!=(TVec b) const { return !operator==(b); } [[nodiscard]] Bool operator<(TVec b) const { for(U32 i = 0; i < kTComponentCount; i++) { if(m_arr[i] >= b.m_arr[i]) { return false; } } return true; } [[nodiscard]] Bool operator<=(TVec b) const { for(U32 i = 0; i < kTComponentCount; i++) { if(m_arr[i] > b.m_arr[i]) { return false; } } return true; } [[nodiscard]] Bool operator>(TVec b) const { for(U32 i = 0; i < kTComponentCount; i++) { if(m_arr[i] <= b.m_arr[i]) { return false; } } return true; } [[nodiscard]] Bool operator>=(TVec b) const { for(U32 i = 0; i < kTComponentCount; i++) { if(m_arr[i] < b.m_arr[i]) { return false; } } return true; } // Operators with T [[nodiscard]] TVec operator+(T f) const { return (*this) + TVec(f); } TVec& operator+=(T f) { (*this) += TVec(f); return *this; } [[nodiscard]] TVec operator-(T f) const { return (*this) - TVec(f); } TVec& operator-=(T f) { (*this) -= TVec(f); return *this; } [[nodiscard]] TVec operator*(T f) const { return (*this) * TVec(f); } TVec& operator*=(T f) { (*this) *= TVec(f); return *this; } [[nodiscard]] TVec operator/(T f) const { return (*this) / TVec(f); } TVec& operator/=(T f) { (*this) /= TVec(f); return *this; } [[nodiscard]] TVec operator<<(T f) const requires(kIsInteger) { return (*this) << TVec(f); } TVec& operator<<=(T f) requires(kIsInteger) { (*this) <<= TVec(f); return *this; } [[nodiscard]] TVec operator>>(T f) const requires(kIsInteger) { return (*this) >> TVec(f); } TVec& operator>>=(T f) requires(kIsInteger) { (*this) >>= TVec(f); return *this; } [[nodiscard]] TVec operator&(T f) const requires(kIsInteger) { return (*this) & TVec(f); } TVec& operator&=(T f) requires(kIsInteger) { (*this) &= TVec(f); return *this; } [[nodiscard]] TVec operator|(T f) const requires(kIsInteger) { return (*this) | TVec(f); } TVec& operator|=(T f) requires(kIsInteger) { (*this) |= TVec(f); return *this; } [[nodiscard]] TVec operator^(T f) const requires(kIsInteger) { return (*this) ^ TVec(f); } TVec& operator^=(T f) requires(kIsInteger) { (*this) ^= TVec(f); return *this; } [[nodiscard]] TVec operator%(T f) const requires(kIsInteger) { return (*this) % TVec(f); } TVec& operator%=(T f) requires(kIsInteger) { (*this) %= TVec(f); return *this; } [[nodiscard]] Bool operator==(T f) const { return *this == TVec(f); } [[nodiscard]] Bool operator!=(T f) const { return *this != TVec(f); } [[nodiscard]] Bool operator<(T f) const { return *this < TVec(f); } [[nodiscard]] Bool operator<=(T f) const { return *this <= TVec(f); } [[nodiscard]] Bool operator>(T f) const { return *this > TVec(f); } [[nodiscard]] Bool operator>=(T f) const { return *this >= TVec(f); } // Operators with other [[nodiscard]] TVec operator*(const TMat& m4) const requires(kTComponentCount == 4) { TVec out; out.x = this->x * m4(0, 0) + this->y * m4(1, 0) + this->z * m4(2, 0) + this->w * m4(3, 0); out.y = this->x * m4(0, 1) + this->y * m4(1, 1) + this->z * m4(2, 1) + this->w * m4(3, 1); out.z = this->x * m4(0, 2) + this->y * m4(1, 2) + this->z * m4(2, 2) + this->w * m4(3, 2); out.w = this->x * m4(0, 3) + this->y * m4(1, 3) + this->z * m4(2, 3) + this->w * m4(3, 3); return out; } // Other [[nodiscard]] T dot(TVec b) const { T out = T(0); if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE _mm_store_ss(&out, _mm_dp_ps(m_simd, b.m_simd, 0xF1)); #else out = vaddvq_f32(vmulq_f32(m_simd, b.m_simd)); #endif } else { for(U32 i = 0; i < kTComponentCount; i++) { out += m_arr[i] * b.m_arr[i]; } } return out; } // 6 muls, 3 adds [[nodiscard]] TVec cross(TVec b) const requires(kTComponentCount == 3) { return TVec(this->y * b.z - this->z * b.y, this->z * b.x - this->x * b.z, this->x * b.y - this->y * b.x); } // It's like calculating the cross of a 3 component TVec. [[nodiscard]] TVec cross(TVec b_) const requires(kTComponentCount == 4) { ANKI_ASSERT(this->w == T(0)); ANKI_ASSERT(b_.w == T(0)); #if ANKI_SIMD_SSE const auto& a = m_simd; const auto& b = b_.m_simd; __m128 t1 = _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 2, 1)); t1 = _mm_mul_ps(t1, a); __m128 t2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 2, 1)); t2 = _mm_mul_ps(t2, b); __m128 t3 = _mm_sub_ps(t1, t2); return TVec(_mm_shuffle_ps(t3, t3, _MM_SHUFFLE(0, 0, 2, 1))).xyz0; #elif ANKI_SIMD_NEON const auto& a = m_simd; const auto& b = b_.m_simd; float32x4_t t1 = ANKI_NEON_SHUFFLE_F32x4(b, b, 0, 0, 2, 1); t1 = vmulq_f32(t1, a); float32x4_t t2 = ANKI_NEON_SHUFFLE_F32x4(a, a, 0, 0, 2, 1); t2 = vmulq_f32(t2, b); float32x4_t t3 = vsubq_f32(t1, t2); return TVec(ANKI_NEON_SHUFFLE_F32x4(t3, t3, 0, 0, 2, 1)).xyz0; #else return TVec(xyz.cross(b_.xyz), T(0)); #endif } [[nodiscard]] TVec projectTo(TVec toThis) const { if constexpr(kTComponentCount < 4) { return toThis * ((*this).dot(toThis) / (toThis.dot(toThis))); } else { ANKI_ASSERT(this->w == T(0)); return (toThis * ((*this).dot(toThis) / (toThis.dot(toThis)))).xyz0; } } [[nodiscard]] TVec projectTo(TVec rayOrigin, TVec rayDir) const { if constexpr(kTComponentCount < 4) { const auto& a = *this; return rayOrigin + rayDir * ((a - rayOrigin).dot(rayDir)); } else { ANKI_ASSERT(this->w == T(0)); ANKI_ASSERT(rayOrigin.w == T(0)); ANKI_ASSERT(rayDir.w == T(0)); const auto& a = *this; return rayOrigin + rayDir * ((a - rayOrigin).dot(rayDir)); } } // Perspective divide. Divide the xyzw of this to the w of this. This method will handle some edge cases. [[nodiscard]] TVec perspectiveDivide() const requires(kTComponentCount == 4 && !kIsInteger) { auto invw = T(1) / this->w; // This may become (+-)inf invw = (invw > T(1e+11)) ? T(1e+11) : invw; // Clamp invw = (invw < T(-1e+11)) ? T(-1e+11) : invw; // Clamp return (*this) * invw; } [[nodiscard]] T lengthSquared() const { return dot(*this); } [[nodiscard]] T length() const { return sqrt(lengthSquared()); } [[nodiscard]] T distanceSquared(TVec b) const { return ((*this) - b).lengthSquared(); } [[nodiscard]] T distance(TVec b) const { return sqrt(distance(b)); } [[nodiscard]] TVec normalize() const { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE __m128 v = _mm_dp_ps(m_simd, m_simd, 0xFF); v = _mm_sqrt_ps(v); v = _mm_div_ps(m_simd, v); return TVec(v); #else float32x4_t v = vmulq_f32(m_simd, m_simd); v = vdupq_n_f32(vaddvq_f32(v)); v = vsqrtq_f32(v); v = vdivq_f32(m_simd, v); return TVec(v); #endif } else { return (*this) / length(); } } // Return lerp(this, v1, t) [[nodiscard]] TVec lerp(TVec v1, TVec t) const { TVec out; for(U32 i = 0; i < kTComponentCount; ++i) { out[i] = m_arr[i] * (T(1) - t.m_arr[i]) + v1.m_arr[i] * t.m_arr[i]; } return out; } // Return lerp(this, v1, t) [[nodiscard]] TVec lerp(TVec v1, T t) const { return ((*this) * (T(1) - t)) + (v1 * t); } [[nodiscard]] TVec abs() const { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE const __m128 signMask = _mm_set1_ps(-0.0f); return TVec(_mm_andnot_ps(signMask, m_simd)); #else return TVec(vabsq_f32(m_simd)); #endif } else { TVec out; for(U32 i = 0; i < kTComponentCount; ++i) { out[i] = absolute(m_arr[i]); } return out; } } // Get clamped between two values. [[nodiscard]] TVec clamp(T minv, T maxv) const { return max(TVec(minv)).min(TVec(maxv)); } // Get clamped between two vectors. [[nodiscard]] TVec clamp(TVec minv, TVec maxv) const { return max(minv).min(maxv); } // Get the min of all components. [[nodiscard]] TVec min(TVec b) const { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE return TVec(_mm_min_ps(m_simd, b.m_simd)); #else return TVec(vminq_f32(m_simd, b.m_simd)); #endif } else { TVec out; for(U32 i = 0; i < kTComponentCount; ++i) { out[i] = anki::min(m_arr[i], b[i]); } return out; } } // Get the min of all components. [[nodiscard]] TVec min(T b) const { return min(TVec(b)); } // Get the max of all components. [[nodiscard]] TVec max(TVec b) const { if constexpr(kVec4Simd) { #if ANKI_SIMD_SSE return TVec(_mm_max_ps(m_simd, b.m_simd)); #else return TVec(vmaxq_f32(m_simd, b.m_simd)); #endif } else { TVec out; for(U32 i = 0; i < kTComponentCount; ++i) { out[i] = anki::max(m_arr[i], b[i]); } return out; } } // Get the max of all components. [[nodiscard]] TVec max(T b) const { return max(TVec(b)); } [[nodiscard]] TVec round() const requires(!kIsInteger) { TVec out; for(U32 i = 0; i < kTComponentCount; ++i) { out[i] = T(::round(m_arr[i])); } return out; } // Get a safe 1 / (*this) [[nodiscard]] TVec reciprocal() const { TVec out; for(U32 i = 0; i < kTComponentCount; ++i) { out[i] = T(1) / m_arr[i]; } return out; } // Power [[nodiscard]] TVec pow(TVec b) const { TVec out; for(U32 i = 0; i < kTComponentCount; ++i) { out[i] = anki::pow(m_arr[i], b.m_arr[i]); } return out; } // Power [[nodiscard]] TVec pow(T b) const { return pow(TVec(b)); } [[nodiscard]] static TVec xAxis() requires(kTComponentCount == 2) { return TVec(T(1), T(0)); } [[nodiscard]] static TVec xAxis() requires(kTComponentCount == 3) { return TVec(T(1), T(0), T(0)); } [[nodiscard]] static TVec xAxis() requires(kTComponentCount == 4) { return TVec(T(1), T(0), T(0), T(0)); } [[nodiscard]] static TVec yAxis() requires(kTComponentCount == 2) { return TVec(T(0), T(1)); } [[nodiscard]] static TVec yAxis() requires(kTComponentCount == 3) { return TVec(T(0), T(1), T(0)); } [[nodiscard]] static TVec yAxis() requires(kTComponentCount == 4) { return TVec(T(0), T(1), T(0), T(0)); } [[nodiscard]] static TVec zAxis() requires(kTComponentCount == 3) { return TVec(T(0), T(0), T(1)); } [[nodiscard]] static TVec zAxis() requires(kTComponentCount == 4) { return TVec(T(0), T(0), T(1), T(0)); } // Serialize the structure. void serialize(void* data, PtrSize& size) const { size = sizeof(*this); if(data) { memcpy(data, this, sizeof(*this)); } } // De-serialize the structure. void deserialize(const void* data) { ANKI_ASSERT(data); memcpy(this, data, sizeof(*this)); } [[nodiscard]] static constexpr U8 getSize() { return U8(kTComponentCount); } U32 packSnorm4x8() const requires(std::is_floating_point_v&& kTComponentCount == 4) { union { I8 in[4]; U32 out; } u; const TVec result = (clamp(-1.0f, 1.0f) * 127.0f).round(); u.in[0] = I8(result[0]); u.in[1] = I8(result[1]); u.in[2] = I8(result[2]); u.in[3] = I8(result[3]); return u.out; } U32 packUnorm4x8() const requires(std::is_floating_point_v&& kTComponentCount == 4) { ANKI_ASSERT((*this <= TVec(T(1)) && *this >= TVec(T(0)))); const TVec packed(*this * T(255)); return packed.x | (U32(packed.y) << 8u) | (U32(packed.z) << 16u) | (U32(packed.w) << 24u); } // Opposite of packUnorm4x8 void unpackUnorm4x8(const U32 value) requires(std::is_floating_point_v&& kTComponentCount == 4) { const TVec packed(value & 0xFF, (value >> 8u) & 0xFF, (value >> 16u) & 0xff, value >> 24u); *this = packed / T(255); } void setFromSphericalToCartesian(T polar, T azimuth) requires(std::is_floating_point_v&& kTComponentCount == 3) { TVec& out = *this; out.x = cos(polar) * sin(azimuth); out.y = cos(polar) * cos(azimuth); out.z = sin(polar); } [[nodiscard]] String toString() const requires(std::is_floating_point::value) { String str; for(U32 i = 0; i < kTComponentCount; ++i) { str += String().sprintf((i < i - kTComponentCount) ? "%f " : "%f", m_arr[i]); } return str; } static constexpr Bool kClangWorkaround = std::is_integral::value && std::is_unsigned::value; [[nodiscard]] String toString() const requires(kClangWorkaround) { String str; for(U32 i = 0; i < kTComponentCount; ++i) { str += String().sprintf((i < i - kTComponentCount) ? "%u " : "%u", m_arr[i]); } return str; } static constexpr Bool kClangWorkaround2 = std::is_integral::value && std::is_signed::value; [[nodiscard]] String toString() const requires(kClangWorkaround2) { String str; for(U32 i = 0; i < kTComponentCount; ++i) { str += String().sprintf((i < i - kTComponentCount) ? "%d " : "%d", m_arr[i]); } return str; } }; template TVec operator+(T f, TVec v) { return v + f; } template TVec operator-(T f, TVec v) { return TVec(f) - v; } template TVec operator*(T f, TVec v) { return v * f; } template TVec operator/(T f, TVec v) { return TVec(f) / v; } // All vectors using Vec2 = TVec; using HVec2 = TVec; using IVec2 = TVec; using I16Vec2 = TVec; using I8Vec2 = TVec; using UVec2 = TVec; using U16Vec2 = TVec; using U8Vec2 = TVec; using Vec3 = TVec; using HVec3 = TVec; using IVec3 = TVec; using I16Vec3 = TVec; using I8Vec3 = TVec; using UVec3 = TVec; using U16Vec3 = TVec; using U8Vec3 = TVec; using Vec4 = TVec; using HVec4 = TVec; using IVec4 = TVec; using I16Vec4 = TVec; using I8Vec4 = TVec; using UVec4 = TVec; using U16Vec4 = TVec; using U8Vec4 = TVec; } // end namespace anki