// Copyright (C) 2009-2021, 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 { /// @addtogroup math /// @{ /// Common code for all vectors /// @tparam T The scalar type. Eg float. /// @tparam N The number of the vector components (2, 3 or 4). template class alignas(MathSimd::ALIGNMENT) TVec { public: using Scalar = T; using Simd = typename MathSimd::Type; static constexpr U COMPONENT_COUNT = N; static constexpr Bool IS_INTEGER = std::is_integral::value; static constexpr Bool HAS_VEC4_SIMD = N == 4 && std::is_same::value && ANKI_ENABLE_SIMD; /// @name Constructors /// @{ /// Defaut constructor. IT WILL NOT INITIALIZE ANYTHING. TVec() { } /// Copy. TVec(ANKI_ENABLE_ARG(const TVec&, !HAS_VEC4_SIMD) b) { for(U i = 0; i < N; i++) { m_arr[i] = b.m_arr[i]; } } /// Copy. TVec(ANKI_ENABLE_ARG(const TVec&, HAS_VEC4_SIMD) b) { m_simd = b.m_simd; } /// Convert from another type. From int to float vectors and the opposite. template::value)> explicit TVec(const TVec& b) { for(U i = 0; i < N; i++) { m_arr[i] = T(b[i]); } } ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) explicit TVec(const T f) { for(U i = 0; i < N; ++i) { m_arr[i] = f; } } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) explicit TVec(const T f) { # if ANKI_SIMD_SSE m_simd = _mm_set1_ps(f); # else m_simd = vdupq_n_f32(f); # endif } #endif ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) explicit TVec(const T arr[]) { for(U i = 0; i < N; ++i) { m_arr[i] = arr[i]; } } ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) explicit TVec(const T arr[]) { m_simd = _mm_load_ps(arr); } explicit TVec(const Array& arr) { for(U i = 0; i < N; ++i) { m_arr[i] = arr[i]; } } explicit TVec(const Simd& simd) { m_simd = simd; } ANKI_ENABLE_METHOD(N == 2) TVec(const T x_, const T y_) { x() = x_; y() = y_; } // Vec3 specific ANKI_ENABLE_METHOD(N == 3) TVec(const T x_, const T y_, const T z_) { x() = x_; y() = y_; z() = z_; } ANKI_ENABLE_METHOD(N == 3) TVec(const TVec& a, const T z_) { x() = a.x(); y() = a.y(); z() = z_; } ANKI_ENABLE_METHOD(N == 3) TVec(const T x_, const TVec& a) { x() = x_; y() = a.x(); z() = a.y(); } // Vec4 specific ANKI_ENABLE_METHOD(N == 4 && !HAS_VEC4_SIMD) TVec(const T x_, const T y_, const T z_, const T w_) { x() = x_; y() = y_; z() = z_; w() = w_; } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec(const T x_, const T y_, const T z_, const T w_) { # if ANKI_SIMD_SSE m_simd = _mm_set_ps(w_, z_, y_, x_); # else m_simd = {x_, y_, z_, w_}; # endif } #endif ANKI_ENABLE_METHOD(N == 4) TVec(const TVec& a, const T w_) { x() = a.x(); y() = a.y(); z() = a.z(); w() = w_; } ANKI_ENABLE_METHOD(N == 4) TVec(const T x_, const TVec& a) { x() = x_; y() = a.x(); z() = a.y(); w() = a.z(); } ANKI_ENABLE_METHOD(N == 4) TVec(const TVec& a, const T z_, const T w_) { x() = a.x(); y() = a.y(); z() = z_; w() = w_; } ANKI_ENABLE_METHOD(N == 4) TVec(const T x_, const TVec& a, const T w_) { x() = x_; y() = a.x(); z() = a.y(); w() = w_; } ANKI_ENABLE_METHOD(N == 4) TVec(const T x_, const T y_, const TVec& a) { x() = x_; y() = y_; z() = a.x(); w() = a.y(); } ANKI_ENABLE_METHOD(N == 4) TVec(const TVec& a, const TVec& b) { x() = a.x(); y() = a.y(); z() = b.x(); w() = b.y(); } /// @} /// @name Accessors /// @{ T& x() { return m_arr[0]; } T x() const { return m_arr[0]; } T& y() { return m_arr[1]; } T y() const { return m_arr[1]; } ANKI_ENABLE_METHOD(N > 2) T& z() { return m_arr[2]; } ANKI_ENABLE_METHOD(N > 2) T z() const { return m_arr[2]; } ANKI_ENABLE_METHOD(N > 3) T& w() { return m_arr[3]; } ANKI_ENABLE_METHOD(N > 3) T w() const { return m_arr[3]; } ANKI_ENABLE_METHOD(N > 2) TVec xyz1() const { return TVec(x(), y(), z(), T(1)); } ANKI_ENABLE_METHOD(N > 2) TVec xyz0() const { return TVec(x(), y(), z(), T(0)); } T& operator[](const U i) { return m_arr[i]; } const T& operator[](const U i) const { return m_arr[i]; } Simd& getSimd() { return m_simd; } const Simd& getSimd() const { return m_simd; } // Swizzled accessors ANKI_ENABLE_METHOD(N > 0) TVec xx() const { return TVec(m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec xy() const { return TVec(m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xz() const { return TVec(m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xw() const { return TVec(m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 1) TVec yx() const { return TVec(m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec yy() const { return TVec(m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yz() const { return TVec(m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yw() const { return TVec(m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zx() const { return TVec(m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zy() const { return TVec(m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zz() const { return TVec(m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zw() const { return TVec(m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wx() const { return TVec(m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wy() const { return TVec(m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wz() const { return TVec(m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec ww() const { return TVec(m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 0) TVec xxx() const { return TVec(m_carr[0], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec xxy() const { return TVec(m_carr[0], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xxz() const { return TVec(m_carr[0], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xxw() const { return TVec(m_carr[0], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 1) TVec xyx() const { return TVec(m_carr[0], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec xyy() const { return TVec(m_carr[0], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xyz() const { return TVec(m_carr[0], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xyw() const { return TVec(m_carr[0], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec xzx() const { return TVec(m_carr[0], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec xzy() const { return TVec(m_carr[0], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xzz() const { return TVec(m_carr[0], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xzw() const { return TVec(m_carr[0], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec xwx() const { return TVec(m_carr[0], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec xwy() const { return TVec(m_carr[0], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec xwz() const { return TVec(m_carr[0], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xww() const { return TVec(m_carr[0], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 1) TVec yxx() const { return TVec(m_carr[1], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec yxy() const { return TVec(m_carr[1], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yxz() const { return TVec(m_carr[1], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yxw() const { return TVec(m_carr[1], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 1) TVec yyx() const { return TVec(m_carr[1], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec yyy() const { return TVec(m_carr[1], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yyz() const { return TVec(m_carr[1], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yyw() const { return TVec(m_carr[1], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec yzx() const { return TVec(m_carr[1], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec yzy() const { return TVec(m_carr[1], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yzz() const { return TVec(m_carr[1], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yzw() const { return TVec(m_carr[1], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec ywx() const { return TVec(m_carr[1], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec ywy() const { return TVec(m_carr[1], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec ywz() const { return TVec(m_carr[1], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yww() const { return TVec(m_carr[1], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zxx() const { return TVec(m_carr[2], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zxy() const { return TVec(m_carr[2], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zxz() const { return TVec(m_carr[2], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zxw() const { return TVec(m_carr[2], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zyx() const { return TVec(m_carr[2], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zyy() const { return TVec(m_carr[2], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zyz() const { return TVec(m_carr[2], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zyw() const { return TVec(m_carr[2], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zzx() const { return TVec(m_carr[2], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zzy() const { return TVec(m_carr[2], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zzz() const { return TVec(m_carr[2], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zzw() const { return TVec(m_carr[2], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec zwx() const { return TVec(m_carr[2], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec zwy() const { return TVec(m_carr[2], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec zwz() const { return TVec(m_carr[2], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zww() const { return TVec(m_carr[2], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wxx() const { return TVec(m_carr[3], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wxy() const { return TVec(m_carr[3], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wxz() const { return TVec(m_carr[3], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wxw() const { return TVec(m_carr[3], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wyx() const { return TVec(m_carr[3], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wyy() const { return TVec(m_carr[3], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wyz() const { return TVec(m_carr[3], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wyw() const { return TVec(m_carr[3], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wzx() const { return TVec(m_carr[3], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wzy() const { return TVec(m_carr[3], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wzz() const { return TVec(m_carr[3], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wzw() const { return TVec(m_carr[3], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wwx() const { return TVec(m_carr[3], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wwy() const { return TVec(m_carr[3], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wwz() const { return TVec(m_carr[3], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec www() const { return TVec(m_carr[3], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 0) TVec xxxx() const { return TVec(m_carr[0], m_carr[0], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec xxxy() const { return TVec(m_carr[0], m_carr[0], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xxxz() const { return TVec(m_carr[0], m_carr[0], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xxxw() const { return TVec(m_carr[0], m_carr[0], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 1) TVec xxyx() const { return TVec(m_carr[0], m_carr[0], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec xxyy() const { return TVec(m_carr[0], m_carr[0], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xxyz() const { return TVec(m_carr[0], m_carr[0], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xxyw() const { return TVec(m_carr[0], m_carr[0], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec xxzx() const { return TVec(m_carr[0], m_carr[0], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec xxzy() const { return TVec(m_carr[0], m_carr[0], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xxzz() const { return TVec(m_carr[0], m_carr[0], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xxzw() const { return TVec(m_carr[0], m_carr[0], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec xxwx() const { return TVec(m_carr[0], m_carr[0], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec xxwy() const { return TVec(m_carr[0], m_carr[0], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec xxwz() const { return TVec(m_carr[0], m_carr[0], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xxww() const { return TVec(m_carr[0], m_carr[0], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 1) TVec xyxx() const { return TVec(m_carr[0], m_carr[1], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec xyxy() const { return TVec(m_carr[0], m_carr[1], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xyxz() const { return TVec(m_carr[0], m_carr[1], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xyxw() const { return TVec(m_carr[0], m_carr[1], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 1) TVec xyyx() const { return TVec(m_carr[0], m_carr[1], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec xyyy() const { return TVec(m_carr[0], m_carr[1], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xyyz() const { return TVec(m_carr[0], m_carr[1], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xyyw() const { return TVec(m_carr[0], m_carr[1], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec xyzx() const { return TVec(m_carr[0], m_carr[1], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec xyzy() const { return TVec(m_carr[0], m_carr[1], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xyzz() const { return TVec(m_carr[0], m_carr[1], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xyzw() const { return TVec(m_carr[0], m_carr[1], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec xywx() const { return TVec(m_carr[0], m_carr[1], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec xywy() const { return TVec(m_carr[0], m_carr[1], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec xywz() const { return TVec(m_carr[0], m_carr[1], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xyww() const { return TVec(m_carr[0], m_carr[1], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec xzxx() const { return TVec(m_carr[0], m_carr[2], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec xzxy() const { return TVec(m_carr[0], m_carr[2], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xzxz() const { return TVec(m_carr[0], m_carr[2], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xzxw() const { return TVec(m_carr[0], m_carr[2], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec xzyx() const { return TVec(m_carr[0], m_carr[2], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec xzyy() const { return TVec(m_carr[0], m_carr[2], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xzyz() const { return TVec(m_carr[0], m_carr[2], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xzyw() const { return TVec(m_carr[0], m_carr[2], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec xzzx() const { return TVec(m_carr[0], m_carr[2], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec xzzy() const { return TVec(m_carr[0], m_carr[2], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec xzzz() const { return TVec(m_carr[0], m_carr[2], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xzzw() const { return TVec(m_carr[0], m_carr[2], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec xzwx() const { return TVec(m_carr[0], m_carr[2], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec xzwy() const { return TVec(m_carr[0], m_carr[2], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec xzwz() const { return TVec(m_carr[0], m_carr[2], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xzww() const { return TVec(m_carr[0], m_carr[2], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec xwxx() const { return TVec(m_carr[0], m_carr[3], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec xwxy() const { return TVec(m_carr[0], m_carr[3], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec xwxz() const { return TVec(m_carr[0], m_carr[3], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xwxw() const { return TVec(m_carr[0], m_carr[3], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec xwyx() const { return TVec(m_carr[0], m_carr[3], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec xwyy() const { return TVec(m_carr[0], m_carr[3], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec xwyz() const { return TVec(m_carr[0], m_carr[3], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xwyw() const { return TVec(m_carr[0], m_carr[3], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec xwzx() const { return TVec(m_carr[0], m_carr[3], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec xwzy() const { return TVec(m_carr[0], m_carr[3], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec xwzz() const { return TVec(m_carr[0], m_carr[3], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xwzw() const { return TVec(m_carr[0], m_carr[3], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec xwwx() const { return TVec(m_carr[0], m_carr[3], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec xwwy() const { return TVec(m_carr[0], m_carr[3], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec xwwz() const { return TVec(m_carr[0], m_carr[3], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec xwww() const { return TVec(m_carr[0], m_carr[3], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 1) TVec yxxx() const { return TVec(m_carr[1], m_carr[0], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec yxxy() const { return TVec(m_carr[1], m_carr[0], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yxxz() const { return TVec(m_carr[1], m_carr[0], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yxxw() const { return TVec(m_carr[1], m_carr[0], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 1) TVec yxyx() const { return TVec(m_carr[1], m_carr[0], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec yxyy() const { return TVec(m_carr[1], m_carr[0], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yxyz() const { return TVec(m_carr[1], m_carr[0], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yxyw() const { return TVec(m_carr[1], m_carr[0], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec yxzx() const { return TVec(m_carr[1], m_carr[0], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec yxzy() const { return TVec(m_carr[1], m_carr[0], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yxzz() const { return TVec(m_carr[1], m_carr[0], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yxzw() const { return TVec(m_carr[1], m_carr[0], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec yxwx() const { return TVec(m_carr[1], m_carr[0], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec yxwy() const { return TVec(m_carr[1], m_carr[0], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec yxwz() const { return TVec(m_carr[1], m_carr[0], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yxww() const { return TVec(m_carr[1], m_carr[0], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 1) TVec yyxx() const { return TVec(m_carr[1], m_carr[1], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec yyxy() const { return TVec(m_carr[1], m_carr[1], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yyxz() const { return TVec(m_carr[1], m_carr[1], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yyxw() const { return TVec(m_carr[1], m_carr[1], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 1) TVec yyyx() const { return TVec(m_carr[1], m_carr[1], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 1) TVec yyyy() const { return TVec(m_carr[1], m_carr[1], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yyyz() const { return TVec(m_carr[1], m_carr[1], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yyyw() const { return TVec(m_carr[1], m_carr[1], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec yyzx() const { return TVec(m_carr[1], m_carr[1], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec yyzy() const { return TVec(m_carr[1], m_carr[1], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yyzz() const { return TVec(m_carr[1], m_carr[1], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yyzw() const { return TVec(m_carr[1], m_carr[1], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec yywx() const { return TVec(m_carr[1], m_carr[1], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec yywy() const { return TVec(m_carr[1], m_carr[1], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec yywz() const { return TVec(m_carr[1], m_carr[1], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yyww() const { return TVec(m_carr[1], m_carr[1], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec yzxx() const { return TVec(m_carr[1], m_carr[2], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec yzxy() const { return TVec(m_carr[1], m_carr[2], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yzxz() const { return TVec(m_carr[1], m_carr[2], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yzxw() const { return TVec(m_carr[1], m_carr[2], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec yzyx() const { return TVec(m_carr[1], m_carr[2], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec yzyy() const { return TVec(m_carr[1], m_carr[2], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yzyz() const { return TVec(m_carr[1], m_carr[2], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yzyw() const { return TVec(m_carr[1], m_carr[2], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec yzzx() const { return TVec(m_carr[1], m_carr[2], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec yzzy() const { return TVec(m_carr[1], m_carr[2], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec yzzz() const { return TVec(m_carr[1], m_carr[2], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yzzw() const { return TVec(m_carr[1], m_carr[2], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec yzwx() const { return TVec(m_carr[1], m_carr[2], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec yzwy() const { return TVec(m_carr[1], m_carr[2], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec yzwz() const { return TVec(m_carr[1], m_carr[2], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec yzww() const { return TVec(m_carr[1], m_carr[2], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec ywxx() const { return TVec(m_carr[1], m_carr[3], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec ywxy() const { return TVec(m_carr[1], m_carr[3], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec ywxz() const { return TVec(m_carr[1], m_carr[3], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec ywxw() const { return TVec(m_carr[1], m_carr[3], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec ywyx() const { return TVec(m_carr[1], m_carr[3], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec ywyy() const { return TVec(m_carr[1], m_carr[3], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec ywyz() const { return TVec(m_carr[1], m_carr[3], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec ywyw() const { return TVec(m_carr[1], m_carr[3], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec ywzx() const { return TVec(m_carr[1], m_carr[3], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec ywzy() const { return TVec(m_carr[1], m_carr[3], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec ywzz() const { return TVec(m_carr[1], m_carr[3], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec ywzw() const { return TVec(m_carr[1], m_carr[3], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec ywwx() const { return TVec(m_carr[1], m_carr[3], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec ywwy() const { return TVec(m_carr[1], m_carr[3], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec ywwz() const { return TVec(m_carr[1], m_carr[3], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec ywww() const { return TVec(m_carr[1], m_carr[3], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zxxx() const { return TVec(m_carr[2], m_carr[0], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zxxy() const { return TVec(m_carr[2], m_carr[0], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zxxz() const { return TVec(m_carr[2], m_carr[0], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zxxw() const { return TVec(m_carr[2], m_carr[0], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zxyx() const { return TVec(m_carr[2], m_carr[0], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zxyy() const { return TVec(m_carr[2], m_carr[0], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zxyz() const { return TVec(m_carr[2], m_carr[0], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zxyw() const { return TVec(m_carr[2], m_carr[0], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zxzx() const { return TVec(m_carr[2], m_carr[0], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zxzy() const { return TVec(m_carr[2], m_carr[0], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zxzz() const { return TVec(m_carr[2], m_carr[0], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zxzw() const { return TVec(m_carr[2], m_carr[0], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec zxwx() const { return TVec(m_carr[2], m_carr[0], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec zxwy() const { return TVec(m_carr[2], m_carr[0], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec zxwz() const { return TVec(m_carr[2], m_carr[0], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zxww() const { return TVec(m_carr[2], m_carr[0], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zyxx() const { return TVec(m_carr[2], m_carr[1], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zyxy() const { return TVec(m_carr[2], m_carr[1], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zyxz() const { return TVec(m_carr[2], m_carr[1], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zyxw() const { return TVec(m_carr[2], m_carr[1], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zyyx() const { return TVec(m_carr[2], m_carr[1], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zyyy() const { return TVec(m_carr[2], m_carr[1], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zyyz() const { return TVec(m_carr[2], m_carr[1], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zyyw() const { return TVec(m_carr[2], m_carr[1], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zyzx() const { return TVec(m_carr[2], m_carr[1], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zyzy() const { return TVec(m_carr[2], m_carr[1], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zyzz() const { return TVec(m_carr[2], m_carr[1], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zyzw() const { return TVec(m_carr[2], m_carr[1], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec zywx() const { return TVec(m_carr[2], m_carr[1], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec zywy() const { return TVec(m_carr[2], m_carr[1], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec zywz() const { return TVec(m_carr[2], m_carr[1], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zyww() const { return TVec(m_carr[2], m_carr[1], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zzxx() const { return TVec(m_carr[2], m_carr[2], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zzxy() const { return TVec(m_carr[2], m_carr[2], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zzxz() const { return TVec(m_carr[2], m_carr[2], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zzxw() const { return TVec(m_carr[2], m_carr[2], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zzyx() const { return TVec(m_carr[2], m_carr[2], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zzyy() const { return TVec(m_carr[2], m_carr[2], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zzyz() const { return TVec(m_carr[2], m_carr[2], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zzyw() const { return TVec(m_carr[2], m_carr[2], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 2) TVec zzzx() const { return TVec(m_carr[2], m_carr[2], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 2) TVec zzzy() const { return TVec(m_carr[2], m_carr[2], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 2) TVec zzzz() const { return TVec(m_carr[2], m_carr[2], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zzzw() const { return TVec(m_carr[2], m_carr[2], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec zzwx() const { return TVec(m_carr[2], m_carr[2], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec zzwy() const { return TVec(m_carr[2], m_carr[2], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec zzwz() const { return TVec(m_carr[2], m_carr[2], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zzww() const { return TVec(m_carr[2], m_carr[2], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec zwxx() const { return TVec(m_carr[2], m_carr[3], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec zwxy() const { return TVec(m_carr[2], m_carr[3], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec zwxz() const { return TVec(m_carr[2], m_carr[3], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zwxw() const { return TVec(m_carr[2], m_carr[3], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec zwyx() const { return TVec(m_carr[2], m_carr[3], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec zwyy() const { return TVec(m_carr[2], m_carr[3], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec zwyz() const { return TVec(m_carr[2], m_carr[3], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zwyw() const { return TVec(m_carr[2], m_carr[3], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec zwzx() const { return TVec(m_carr[2], m_carr[3], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec zwzy() const { return TVec(m_carr[2], m_carr[3], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec zwzz() const { return TVec(m_carr[2], m_carr[3], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zwzw() const { return TVec(m_carr[2], m_carr[3], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec zwwx() const { return TVec(m_carr[2], m_carr[3], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec zwwy() const { return TVec(m_carr[2], m_carr[3], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec zwwz() const { return TVec(m_carr[2], m_carr[3], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec zwww() const { return TVec(m_carr[2], m_carr[3], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wxxx() const { return TVec(m_carr[3], m_carr[0], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wxxy() const { return TVec(m_carr[3], m_carr[0], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wxxz() const { return TVec(m_carr[3], m_carr[0], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wxxw() const { return TVec(m_carr[3], m_carr[0], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wxyx() const { return TVec(m_carr[3], m_carr[0], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wxyy() const { return TVec(m_carr[3], m_carr[0], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wxyz() const { return TVec(m_carr[3], m_carr[0], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wxyw() const { return TVec(m_carr[3], m_carr[0], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wxzx() const { return TVec(m_carr[3], m_carr[0], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wxzy() const { return TVec(m_carr[3], m_carr[0], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wxzz() const { return TVec(m_carr[3], m_carr[0], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wxzw() const { return TVec(m_carr[3], m_carr[0], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wxwx() const { return TVec(m_carr[3], m_carr[0], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wxwy() const { return TVec(m_carr[3], m_carr[0], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wxwz() const { return TVec(m_carr[3], m_carr[0], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wxww() const { return TVec(m_carr[3], m_carr[0], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wyxx() const { return TVec(m_carr[3], m_carr[1], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wyxy() const { return TVec(m_carr[3], m_carr[1], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wyxz() const { return TVec(m_carr[3], m_carr[1], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wyxw() const { return TVec(m_carr[3], m_carr[1], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wyyx() const { return TVec(m_carr[3], m_carr[1], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wyyy() const { return TVec(m_carr[3], m_carr[1], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wyyz() const { return TVec(m_carr[3], m_carr[1], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wyyw() const { return TVec(m_carr[3], m_carr[1], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wyzx() const { return TVec(m_carr[3], m_carr[1], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wyzy() const { return TVec(m_carr[3], m_carr[1], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wyzz() const { return TVec(m_carr[3], m_carr[1], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wyzw() const { return TVec(m_carr[3], m_carr[1], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wywx() const { return TVec(m_carr[3], m_carr[1], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wywy() const { return TVec(m_carr[3], m_carr[1], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wywz() const { return TVec(m_carr[3], m_carr[1], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wyww() const { return TVec(m_carr[3], m_carr[1], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wzxx() const { return TVec(m_carr[3], m_carr[2], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wzxy() const { return TVec(m_carr[3], m_carr[2], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wzxz() const { return TVec(m_carr[3], m_carr[2], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wzxw() const { return TVec(m_carr[3], m_carr[2], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wzyx() const { return TVec(m_carr[3], m_carr[2], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wzyy() const { return TVec(m_carr[3], m_carr[2], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wzyz() const { return TVec(m_carr[3], m_carr[2], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wzyw() const { return TVec(m_carr[3], m_carr[2], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wzzx() const { return TVec(m_carr[3], m_carr[2], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wzzy() const { return TVec(m_carr[3], m_carr[2], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wzzz() const { return TVec(m_carr[3], m_carr[2], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wzzw() const { return TVec(m_carr[3], m_carr[2], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wzwx() const { return TVec(m_carr[3], m_carr[2], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wzwy() const { return TVec(m_carr[3], m_carr[2], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wzwz() const { return TVec(m_carr[3], m_carr[2], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wzww() const { return TVec(m_carr[3], m_carr[2], m_carr[3], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wwxx() const { return TVec(m_carr[3], m_carr[3], m_carr[0], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wwxy() const { return TVec(m_carr[3], m_carr[3], m_carr[0], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wwxz() const { return TVec(m_carr[3], m_carr[3], m_carr[0], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wwxw() const { return TVec(m_carr[3], m_carr[3], m_carr[0], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wwyx() const { return TVec(m_carr[3], m_carr[3], m_carr[1], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wwyy() const { return TVec(m_carr[3], m_carr[3], m_carr[1], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wwyz() const { return TVec(m_carr[3], m_carr[3], m_carr[1], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wwyw() const { return TVec(m_carr[3], m_carr[3], m_carr[1], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wwzx() const { return TVec(m_carr[3], m_carr[3], m_carr[2], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wwzy() const { return TVec(m_carr[3], m_carr[3], m_carr[2], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wwzz() const { return TVec(m_carr[3], m_carr[3], m_carr[2], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wwzw() const { return TVec(m_carr[3], m_carr[3], m_carr[2], m_carr[3]); } ANKI_ENABLE_METHOD(N > 3) TVec wwwx() const { return TVec(m_carr[3], m_carr[3], m_carr[3], m_carr[0]); } ANKI_ENABLE_METHOD(N > 3) TVec wwwy() const { return TVec(m_carr[3], m_carr[3], m_carr[3], m_carr[1]); } ANKI_ENABLE_METHOD(N > 3) TVec wwwz() const { return TVec(m_carr[3], m_carr[3], m_carr[3], m_carr[2]); } ANKI_ENABLE_METHOD(N > 3) TVec wwww() const { return TVec(m_carr[3], m_carr[3], m_carr[3], m_carr[3]); } /// @} /// @name Operators with same type /// @{ // Copy TVec& operator=(ANKI_ENABLE_ARG(const TVec&, !HAS_VEC4_SIMD) b) { for(U i = 0; i < N; i++) { m_arr[i] = b.m_carr[i]; } return *this; } // Copy TVec& operator=(ANKI_ENABLE_ARG(const TVec&, HAS_VEC4_SIMD) b) { m_simd = b.m_simd; return *this; } ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec operator+(const TVec& b) const { TVec out; for(U i = 0; i < N; i++) { out.m_arr[i] = m_arr[i] + b.m_arr[i]; } return out; } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec operator+(const TVec& b) const { # if ANKI_SIMD_SSE return TVec(_mm_add_ps(m_simd, b.m_simd)); # else return TVec(m_simd + b.m_simd); # endif } #endif ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec& operator+=(const TVec& b) { for(U i = 0; i < N; i++) { m_arr[i] += b.m_arr[i]; } return *this; } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec& operator+=(const TVec& b) { # if ANKI_SIMD_SSE m_simd = _mm_add_ps(m_simd, b.m_simd); # else m_simd += b.m_simd; # endif return *this; } #endif ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec operator-(const TVec& b) const { TVec out; for(U i = 0; i < N; i++) { out.m_arr[i] = m_arr[i] - b.m_arr[i]; } return out; } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec operator-(const TVec& b) const { # if ANKI_SIMD_SSE return TVec(_mm_sub_ps(m_simd, b.m_simd)); # else return TVec(m_simd - b.m_simd); # endif } #endif ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec& operator-=(const TVec& b) { for(U i = 0; i < N; i++) { m_arr[i] -= b.m_arr[i]; } return *this; } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec& operator-=(const TVec& b) { # if ANKI_SIMD_SSE m_simd = _mm_sub_ps(m_simd, b.m_simd); # else m_simd -= b.m_simd; # endif return *this; } #endif ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec operator*(const TVec& b) const { TVec out; for(U i = 0; i < N; i++) { out.m_arr[i] = m_arr[i] * b.m_arr[i]; } return out; } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec operator*(const TVec& b) const { # if ANKI_SIMD_SSE return TVec(_mm_mul_ps(m_simd, b.m_simd)); # else return TVec(m_simd * b.m_simd); # endif } #endif ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec& operator*=(const TVec& b) { for(U i = 0; i < N; i++) { m_arr[i] *= b.m_arr[i]; } return *this; } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec& operator*=(const TVec& b) { # if ANKI_SIMD_SSE m_simd = _mm_mul_ps(m_simd, b.m_simd); # else m_simd *= b.m_simd; # endif return *this; } #endif ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec operator/(const TVec& b) const { TVec out; for(U i = 0; i < N; i++) { ANKI_ASSERT(b.m_arr[i] != 0.0); out.m_arr[i] = m_arr[i] / b.m_arr[i]; } return out; } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec operator/(const TVec& b) const { # if ANKI_SIMD_SSE return TVec(_mm_div_ps(m_simd, b.m_simd)); # else return TVec(m_simd / b.m_simd); # endif } #endif ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec& operator/=(const TVec& b) { for(U i = 0; i < N; i++) { ANKI_ASSERT(b.m_arr[i] != 0.0); m_arr[i] /= b.m_arr[i]; } return *this; } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec& operator/=(const TVec& b) { # if ANKI_SIMD_SSE m_simd = _mm_div_ps(m_simd, b.m_simd); # else m_simd /= b.m_simd; # endif return *this; } #endif ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec operator-() const { TVec out; for(U i = 0; i < N; i++) { out.m_arr[i] = -m_arr[i]; } return out; } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec operator-() const { # if ANKI_SIMD_SSE return TVec(_mm_xor_ps(m_simd, _mm_set1_ps(-0.0))); # else return TVec(-m_simd); # endif } #endif ANKI_ENABLE_METHOD(IS_INTEGER) TVec operator<<(const TVec& b) const { TVec out; for(U i = 0; i < N; i++) { out.m_carr[i] = m_carr[i] << b.m_carr[i]; } return out; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec& operator<<=(const TVec& b) { for(U i = 0; i < N; i++) { m_carr[i] <<= b.m_carr[i]; } return *this; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec operator>>(const TVec& b) const { TVec out; for(U i = 0; i < N; i++) { out.m_carr[i] = m_carr[i] >> b.m_carr[i]; } return out; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec& operator>>=(const TVec& b) { for(U i = 0; i < N; i++) { m_carr[i] >>= b.m_carr[i]; } return *this; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec operator&(const TVec& b) const { TVec out; for(U i = 0; i < N; i++) { out.m_carr[i] = m_carr[i] & b.m_carr[i]; } return out; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec& operator&=(const TVec& b) { for(U i = 0; i < N; i++) { m_carr[i] &= b.m_carr[i]; } return *this; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec operator|(const TVec& b) const { TVec out; for(U i = 0; i < N; i++) { out.m_carr[i] = m_carr[i] | b.m_carr[i]; } return out; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec& operator|=(const TVec& b) { for(U i = 0; i < N; i++) { m_carr[i] |= b.m_carr[i]; } return *this; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec operator^(const TVec& b) const { TVec out; for(U i = 0; i < N; i++) { out.m_carr[i] = m_carr[i] ^ b.m_carr[i]; } return out; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec& operator^=(const TVec& b) { for(U i = 0; i < N; i++) { m_carr[i] ^= b.m_carr[i]; } return *this; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec operator%(const TVec& b) const { TVec out; for(U i = 0; i < N; i++) { out.m_carr[i] = m_carr[i] % b.m_carr[i]; } return out; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec& operator%=(const TVec& b) { for(U i = 0; i < N; i++) { m_carr[i] %= b.m_carr[i]; } return *this; } Bool operator==(const TVec& b) const { for(U i = 0; i < N; i++) { if(!isZero(m_arr[i] - b.m_arr[i])) { return false; } } return true; } Bool operator!=(const TVec& b) const { return !operator==(b); } Bool operator<(const TVec& b) const { for(U i = 0; i < N; i++) { if(m_arr[i] >= b.m_arr[i]) { return false; } } return true; } Bool operator<=(const TVec& b) const { for(U i = 0; i < N; i++) { if(m_arr[i] > b.m_arr[i]) { return false; } } return true; } Bool operator>(const TVec& b) const { for(U i = 0; i < N; i++) { if(m_arr[i] <= b.m_arr[i]) { return false; } } return true; } Bool operator>=(const TVec& b) const { for(U i = 0; i < N; i++) { if(m_arr[i] < b.m_arr[i]) { return false; } } return true; } /// @} /// @name Operators with T /// @{ TVec operator+(const T f) const { return (*this) + TVec(f); } TVec& operator+=(const T f) { (*this) += TVec(f); return *this; } TVec operator-(const T f) const { return (*this) - TVec(f); } TVec& operator-=(const T f) { (*this) -= TVec(f); return *this; } TVec operator*(const T f) const { return (*this) * TVec(f); } TVec& operator*=(const T f) { (*this) *= TVec(f); return *this; } TVec operator/(const T f) const { return (*this) / TVec(f); } TVec& operator/=(const T f) { (*this) /= TVec(f); return *this; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec operator<<(const T f) const { return (*this) << TVec(f); } ANKI_ENABLE_METHOD(IS_INTEGER) TVec& operator<<=(const T f) { (*this) <<= TVec(f); return *this; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec operator>>(const T f) const { return (*this) >> TVec(f); } ANKI_ENABLE_METHOD(IS_INTEGER) TVec& operator>>=(const T f) { (*this) >>= TVec(f); return *this; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec operator&(const T f) const { return (*this) & TVec(f); } ANKI_ENABLE_METHOD(IS_INTEGER) TVec& operator&=(const T f) { (*this) &= TVec(f); return *this; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec operator|(const T f) const { return (*this) | TVec(f); } ANKI_ENABLE_METHOD(IS_INTEGER) TVec& operator|=(const T f) { (*this) |= TVec(f); return *this; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec operator^(const T f) const { return (*this) ^ TVec(f); } ANKI_ENABLE_METHOD(IS_INTEGER) TVec& operator^=(const T f) { (*this) ^= TVec(f); return *this; } ANKI_ENABLE_METHOD(IS_INTEGER) TVec operator%(const T f) const { return (*this) % TVec(f); } ANKI_ENABLE_METHOD(IS_INTEGER) TVec& operator%=(const T f) { (*this) %= TVec(f); return *this; } Bool operator==(const T f) const { return *this == TVec(f); } Bool operator!=(const T f) const { return *this != TVec(f); } Bool operator<(const T f) const { return *this < TVec(f); } Bool operator<=(const T f) const { return *this <= TVec(f); } Bool operator>(const T f) const { return *this > TVec(f); } Bool operator>=(const T f) const { return *this >= TVec(f); } /// @} /// @name Operators with other /// @{ /// @note 16 muls 12 adds ANKI_ENABLE_METHOD(N == 4) TVec operator*(const TMat& m4) const { return TVec(x() * m4(0, 0) + y() * m4(1, 0) + z() * m4(2, 0) + w() * m4(3, 0), x() * m4(0, 1) + y() * m4(1, 1) + z() * m4(2, 1) + w() * m4(3, 1), x() * m4(0, 2) + y() * m4(1, 2) + z() * m4(2, 2) + w() * m4(3, 2), x() * m4(0, 3) + y() * m4(1, 3) + z() * m4(2, 3) + w() * m4(3, 3)); } /// @} /// @name Other /// @{ ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) T dot(const TVec& b) const { T out = T(0); for(U i = 0; i < N; i++) { out += m_arr[i] * b.m_arr[i]; } return out; } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) T dot(const TVec& b) const { T o; # if ANKI_SIMD_SSE _mm_store_ss(&o, _mm_dp_ps(m_simd, b.m_simd, 0xF1)); # else const float32x4_t tmp = m_simd * b.m_simd; float32x2_t sum = vpadd_f32(vget_low_f32(tmp), vget_high_f32(tmp)); sum = vpadd_f32(sum, sum); o = sum[0]; # endif return o; } #endif /// 6 muls, 3 adds ANKI_ENABLE_METHOD(N == 3) TVec cross(const TVec& b) const { return TVec(y() * b.z() - z() * b.y(), z() * b.x() - x() * b.z(), x() * b.y() - y() * b.x()); } /// It's like calculating the cross of a 3 component TVec. ANKI_ENABLE_METHOD(N == 4 && !HAS_VEC4_SIMD) TVec cross(const TVec& b) const { ANKI_ASSERT(w() == T(0)); ANKI_ASSERT(b.w() == T(0)); return TVec(xyz().cross(b.xyz()), T(0)); } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(N == 4 && HAS_VEC4_SIMD) TVec cross(const TVec& b) const { ANKI_ASSERT(w() == T(0)); ANKI_ASSERT(b.w() == T(0)); # if ANKI_SIMD_SSE const auto& a = *this; constexpr unsigned int mask0 = _MM_SHUFFLE(3, 0, 2, 1); constexpr unsigned int mask1 = _MM_SHUFFLE(3, 1, 0, 2); const __m128 tmp0 = _mm_mul_ps(_mm_shuffle_ps(a.m_simd, a.m_simd, U8(mask0)), _mm_shuffle_ps(b.m_simd, b.m_simd, U8(mask1))); const __m128 tmp1 = _mm_mul_ps(_mm_shuffle_ps(a.m_simd, a.m_simd, U8(mask1)), _mm_shuffle_ps(b.m_simd, b.m_simd, U8(mask0))); return TVec(_mm_sub_ps(tmp0, tmp1)); # else TVec out; float32x4_t& c = out.m_simd; const float32x4_t& v0 = m_simd; const float32x4_t& v1 = b.m_simd; c = v0 * __builtin_shufflevector(v1, v1, 1, 2, 0, 3); c = vfmsq_f32(c, __builtin_shufflevector(v0, v0, 1, 2, 0, 3), v1); c = __builtin_shufflevector(c, c, 1, 2, 0, 3); return out; # endif } #endif ANKI_ENABLE_METHOD(N == 3) TVec projectTo(const TVec& toThis) const { return toThis * ((*this).dot(toThis) / (toThis.dot(toThis))); } ANKI_ENABLE_METHOD(N == 4) TVec projectTo(const TVec& toThis) const { ANKI_ASSERT(w() == T(0)); return (toThis * ((*this).dot(toThis) / (toThis.dot(toThis)))).xyz0(); } ANKI_ENABLE_METHOD(N == 3) TVec projectTo(const TVec& rayOrigin, const TVec& rayDir) const { const auto& a = *this; return rayOrigin + rayDir * ((a - rayOrigin).dot(rayDir)); } ANKI_ENABLE_METHOD(N == 4) TVec projectTo(const TVec& rayOrigin, const TVec& rayDir) const { ANKI_ASSERT(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. ANKI_ENABLE_METHOD(N == 4) TVec perspectiveDivide() const { auto invw = T(1) / w(); // This may become (+-)inf invw = (invw > 1e+11) ? 1e+11 : invw; // Clamp invw = (invw < -1e+11) ? -1e+11 : invw; // Clamp return (*this) * invw; } ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) T getLengthSquared() const { T out = T(0); for(U i = 0; i < N; i++) { out += m_arr[i] * m_arr[i]; } return out; } ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) T getLengthSquared() const { return dot(*this); } T getLength() const { return sqrt(getLengthSquared()); } T getDistanceSquared(const TVec& b) const { return ((*this) - b).getLengthSquared(); } T getDistance(const TVec& b) const { return sqrt(getDistance(b)); } ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) void normalize() { (*this) /= getLength(); } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) void normalize() { # if ANKI_SIMD_SSE const __m128 inverseNorm = _mm_rsqrt_ps(_mm_dp_ps(m_simd, m_simd, 0xFF)); m_simd = _mm_mul_ps(m_simd, inverseNorm); # else // Dot (len squared) float32x4_t tmp = m_simd * m_simd; float32x2_t sum = vpadd_f32(vget_low_f32(tmp), vget_high_f32(tmp)); sum = vpadd_f32(sum, sum); float32x4_t lensq = vdupq_lane_f32(sum, 0); // 1/sqrt(lensq) float32x4_t mul = vrsqrteq_f32(lensq); // Multiply m_simd *= mul; # endif } #endif ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec getNormalized() const { return (*this) / getLength(); } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec getNormalized() const { # if ANKI_SIMD_SSE const __m128 inverse_norm = _mm_rsqrt_ps(_mm_dp_ps(m_simd, m_simd, 0xFF)); return TVec(_mm_mul_ps(m_simd, inverse_norm)); # else // Dot (len squared) float32x4_t tmp = m_simd * m_simd; float32x2_t sum = vpadd_f32(vget_low_f32(tmp), vget_high_f32(tmp)); sum = vpadd_f32(sum, sum); float32x4_t lensq = vdupq_lane_f32(sum, 0); // 1/sqrt(lensq) float32x4_t mul = vrsqrteq_f32(lensq); // Multiply return TVec(m_simd * mul); # endif } #endif /// Return lerp(this, v1, t) TVec lerp(const TVec& v1, T t) const { return ((*this) * (1.0 - t)) + (v1 * t); } ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec abs() const { TVec out; for(U i = 0; i < N; ++i) { out[i] = absolute(m_arr[i]); } return out; } #if ANKI_ENABLE_SIMD ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec abs() const { # 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 } #endif /// Get clamped between two values. TVec clamp(const T minv, const T maxv) const { return max(TVec(minv)).min(TVec(maxv)); } /// Get clamped between two vectors. TVec clamp(const TVec& minv, const TVec& maxv) const { return max(minv).min(maxv); } /// Get the min of all components. ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec min(const TVec& b) const { TVec out; for(U i = 0; i < N; ++i) { out[i] = anki::min(m_arr[i], b[i]); } return out; } #if ANKI_ENABLE_SIMD /// Get the min of all components. ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec min(const TVec& b) const { # 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 } #endif /// Get the min of all components. TVec min(const T b) const { return min(TVec(b)); } /// Get the max of all components. ANKI_ENABLE_METHOD(!HAS_VEC4_SIMD) TVec max(const TVec& b) const { TVec out; for(U i = 0; i < N; ++i) { out[i] = anki::max(m_arr[i], b[i]); } return out; } #if ANKI_ENABLE_SIMD /// Get the max of all components. ANKI_ENABLE_METHOD(HAS_VEC4_SIMD) TVec max(const TVec& b) const { # 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 } #endif /// Get the max of all components. TVec max(const T b) const { return max(TVec(b)); } /// Get a safe 1 / (*this) TVec reciprocal() const { TVec out; for(U i = 0; i < N; ++i) { out[i] = T(1) / m_arr[i]; } return out; } /// 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)); } static constexpr U8 getSize() { return U8(N); } ANKI_ENABLE_METHOD(std::is_floating_point::value) void toString(StringAuto& str) const { for(U i = 0; i < N; ++i) { str.append(StringAuto(str.getAllocator()).sprintf((i < i - N) ? "%f " : "%f", m_arr[i])); } } static constexpr Bool CLANG_WORKAROUND = std::is_integral::value && std::is_unsigned::value; ANKI_ENABLE_METHOD(CLANG_WORKAROUND) void toString(StringAuto& str) const { for(U i = 0; i < N; ++i) { str.append(StringAuto(str.getAllocator()).sprintf((i < i - N) ? "%u " : "%u", m_arr[i])); } } static constexpr Bool CLANG_WORKAROUND2 = std::is_integral::value && std::is_signed::value; ANKI_ENABLE_METHOD(CLANG_WORKAROUND2) void toString(StringAuto& str) const { for(U i = 0; i < N; ++i) { str.append(StringAuto(str.getAllocator()).sprintf((i < i - N) ? "%d " : "%d", m_arr[i])); } } /// @} private: /// @name Data /// @{ union { Array m_arr; T m_carr[N]; ///< To avoid bound checks on debug builds. Simd m_simd; }; /// @} }; /// @memberof TVec template TVec operator+(const T f, const TVec& v) { return v + f; } /// @memberof TVec template TVec operator-(const T f, const TVec& v) { return TVec(f) - v; } /// @memberof TVec template TVec operator*(const T f, const TVec& v) { return v * f; } /// @memberof TVec template TVec operator/(const T f, const TVec& v) { return TVec(f) / v; } // Types /// F32 2D vector using Vec2 = TVec; static_assert(sizeof(Vec2) == sizeof(F32) * 2, "Incorrect size"); /// Half float 2D vector using HVec2 = TVec; /// 32bit signed integer 2D vector using IVec2 = TVec; /// 16bit signed integer 2D vector using I16Vec2 = TVec; /// 8bit signed integer 2D vector using I8Vec2 = TVec; /// 32bit unsigned integer 2D vector using UVec2 = TVec; /// 16bit unsigned integer 2D vector using U16Vec2 = TVec; /// 8bit unsigned integer 2D vector using U8Vec2 = TVec; /// F32 3D vector using Vec3 = TVec; static_assert(sizeof(Vec3) == sizeof(F32) * 3, "Incorrect size"); /// Half float 3D vector using HVec3 = TVec; /// 32bit signed integer 3D vector using IVec3 = TVec; /// 16bit signed integer 3D vector using I16Vec3 = TVec; /// 8bit signed integer 3D vector using I8Vec3 = TVec; /// 32bit unsigned integer 3D vector using UVec3 = TVec; /// 16bit unsigned integer 3D vector using U16Vec3 = TVec; /// 8bit unsigned integer 3D vector using U8Vec3 = TVec; /// F32 4D vector using Vec4 = TVec; static_assert(sizeof(Vec4) == sizeof(F32) * 4, "Incorrect size"); /// Half float 4D vector using HVec4 = TVec; /// 32bit signed integer 4D vector using IVec4 = TVec; /// 16bit signed integer 4D vector using I16Vec4 = TVec; /// 8bit signed integer 4D vector using I8Vec4 = TVec; /// 32bit unsigned integer 4D vector using UVec4 = TVec; /// 16bit unsigned integer 4D vector using U16Vec4 = TVec; /// 8bit unsigned integer 4D vector using U8Vec4 = TVec; /// @} } // end namespace anki