/* SPDX-License-Identifier: GPL-2.0-or-later * Copyright 2022 Blender Foundation. */ #pragma once /** \file * \ingroup bli */ #include #include #include #include #include "BLI_math_vector.hh" #include "BLI_utildefines.h" namespace blender { /* clang-format off */ template using as_uint_type = std::conditional_t>>>; /* clang-format on */ template struct vec_struct_base { std::array values; }; template struct vec_struct_base { T x, y; }; template struct vec_struct_base { T x, y, z; }; template struct vec_struct_base { T x, y, z, w; }; template struct vec_base : public vec_struct_base { static constexpr int type_length = Size; using base_type = T; using uint_type = vec_base, Size>; vec_base() = default; explicit vec_base(uint value) { for (int i = 0; i < Size; i++) { (*this)[i] = static_cast(value); } } explicit vec_base(int value) { for (int i = 0; i < Size; i++) { (*this)[i] = static_cast(value); } } explicit vec_base(float value) { for (int i = 0; i < Size; i++) { (*this)[i] = static_cast(value); } } explicit vec_base(double value) { for (int i = 0; i < Size; i++) { (*this)[i] = static_cast(value); } } /* Workaround issue with template BLI_ENABLE_IF((Size == 2)) not working. */ #define BLI_ENABLE_IF_VEC(_size, _test) int S = _size, BLI_ENABLE_IF((S _test)) template vec_base(T _x, T _y) { (*this)[0] = _x; (*this)[1] = _y; } template vec_base(T _x, T _y, T _z) { (*this)[0] = _x; (*this)[1] = _y; (*this)[2] = _z; } template vec_base(T _x, T _y, T _z, T _w) { (*this)[0] = _x; (*this)[1] = _y; (*this)[2] = _z; (*this)[3] = _w; } /** Mixed scalar-vector constructors. */ template constexpr vec_base(const vec_base &xy, T z) : vec_base(static_cast(xy.x), static_cast(xy.y), z) { } template constexpr vec_base(T x, const vec_base &yz) : vec_base(x, static_cast(yz.x), static_cast(yz.y)) { } template vec_base(vec_base xyz, T w) : vec_base( static_cast(xyz.x), static_cast(xyz.y), static_cast(xyz.z), static_cast(w)) { } template vec_base(T x, vec_base yzw) : vec_base( static_cast(x), static_cast(yzw.x), static_cast(yzw.y), static_cast(yzw.z)) { } template vec_base(vec_base xy, vec_base zw) : vec_base( static_cast(xy.x), static_cast(xy.y), static_cast(zw.x), static_cast(zw.y)) { } template vec_base(vec_base xy, T z, T w) : vec_base(static_cast(xy.x), static_cast(xy.y), static_cast(z), static_cast(w)) { } template vec_base(T x, vec_base yz, T w) : vec_base(static_cast(x), static_cast(yz.x), static_cast(yz.y), static_cast(w)) { } template vec_base(T x, T y, vec_base zw) : vec_base(static_cast(x), static_cast(y), static_cast(zw.x), static_cast(zw.y)) { } /** Masking. */ template Size)> explicit vec_base(const vec_base &other) { for (int i = 0; i < Size; i++) { (*this)[i] = static_cast(other[i]); } } #undef BLI_ENABLE_IF_VEC /** Conversion from pointers (from C-style vectors). */ vec_base(const T *ptr) { for (int i = 0; i < Size; i++) { (*this)[i] = ptr[i]; } } vec_base(const T (*ptr)[Size]) : vec_base(static_cast(ptr[0])) { } /** Conversion from other vector types. */ template explicit vec_base(const vec_base &vec) { for (int i = 0; i < Size; i++) { (*this)[i] = static_cast(vec[i]); } } /** C-style pointer dereference. */ operator const T *() const { return reinterpret_cast(this); } operator T *() { return reinterpret_cast(this); } /** Array access. */ const T &operator[](int index) const { BLI_assert(index >= 0); BLI_assert(index < Size); return reinterpret_cast(this)[index]; } T &operator[](int index) { BLI_assert(index >= 0); BLI_assert(index < Size); return reinterpret_cast(this)[index]; } /** Internal Operators Macro. */ #define BLI_INT_OP(_T) template))> #define BLI_VEC_OP_IMPL(_result, _i, _op) \ vec_base _result; \ for (int _i = 0; _i < Size; _i++) { \ _op; \ } \ return _result; #define BLI_VEC_OP_IMPL_SELF(_i, _op) \ for (int _i = 0; _i < Size; _i++) { \ _op; \ } \ return *this; /** Arithmetic operators. */ friend vec_base operator+(const vec_base &a, const vec_base &b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] + b[i]); } friend vec_base operator+(const vec_base &a, const T &b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] + b); } friend vec_base operator+(const T &a, const vec_base &b) { return b + a; } vec_base &operator+=(const vec_base &b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] += b[i]); } vec_base &operator+=(const T &b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] += b); } friend vec_base operator-(const vec_base &a) { BLI_VEC_OP_IMPL(ret, i, ret[i] = -a[i]); } friend vec_base operator-(const vec_base &a, const vec_base &b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] - b[i]); } friend vec_base operator-(const vec_base &a, const T &b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] - b); } friend vec_base operator-(const T &a, const vec_base &b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a - b[i]); } vec_base &operator-=(const vec_base &b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] -= b[i]); } vec_base &operator-=(const T &b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] -= b); } friend vec_base operator*(const vec_base &a, const vec_base &b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] * b[i]); } friend vec_base operator*(const vec_base &a, T b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] * b); } friend vec_base operator*(T a, const vec_base &b) { return b * a; } vec_base &operator*=(T b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] *= b); } vec_base &operator*=(const vec_base &b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] *= b[i]); } friend vec_base operator/(const vec_base &a, const vec_base &b) { BLI_assert(!math::is_any_zero(b)); BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] / b[i]); } friend vec_base operator/(const vec_base &a, T b) { BLI_assert(b != T(0)); BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] / b); } friend vec_base operator/(T a, const vec_base &b) { BLI_assert(!math::is_any_zero(b)); BLI_VEC_OP_IMPL(ret, i, ret[i] = a / b[i]); } vec_base &operator/=(T b) { BLI_assert(b != T(0)); BLI_VEC_OP_IMPL_SELF(i, (*this)[i] /= b); } vec_base &operator/=(const vec_base &b) { BLI_assert(!math::is_any_zero(b)); BLI_VEC_OP_IMPL_SELF(i, (*this)[i] /= b[i]); } /** Binary operators. */ BLI_INT_OP(T) friend vec_base operator&(const vec_base &a, const vec_base &b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] & b[i]); } BLI_INT_OP(T) friend vec_base operator&(const vec_base &a, T b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] & b); } BLI_INT_OP(T) friend vec_base operator&(T a, const vec_base &b) { return b & a; } BLI_INT_OP(T) vec_base &operator&=(T b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] &= b); } BLI_INT_OP(T) vec_base &operator&=(const vec_base &b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] &= b[i]); } BLI_INT_OP(T) friend vec_base operator|(const vec_base &a, const vec_base &b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] | b[i]); } BLI_INT_OP(T) friend vec_base operator|(const vec_base &a, T b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] | b); } BLI_INT_OP(T) friend vec_base operator|(T a, const vec_base &b) { return b | a; } BLI_INT_OP(T) vec_base &operator|=(T b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] |= b); } BLI_INT_OP(T) vec_base &operator|=(const vec_base &b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] |= b[i]); } BLI_INT_OP(T) friend vec_base operator^(const vec_base &a, const vec_base &b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] ^ b[i]); } BLI_INT_OP(T) friend vec_base operator^(const vec_base &a, T b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] ^ b); } BLI_INT_OP(T) friend vec_base operator^(T a, const vec_base &b) { return b ^ a; } BLI_INT_OP(T) vec_base &operator^=(T b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] ^= b); } BLI_INT_OP(T) vec_base &operator^=(const vec_base &b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] ^= b[i]); } BLI_INT_OP(T) friend vec_base operator~(const vec_base &a) { BLI_VEC_OP_IMPL(ret, i, ret[i] = ~a[i]); } /** Bit-shift operators. */ BLI_INT_OP(T) friend vec_base operator<<(const vec_base &a, const vec_base &b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] << b[i]); } BLI_INT_OP(T) friend vec_base operator<<(const vec_base &a, T b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] << b); } BLI_INT_OP(T) vec_base &operator<<=(T b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] <<= b); } BLI_INT_OP(T) vec_base &operator<<=(const vec_base &b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] <<= b[i]); } BLI_INT_OP(T) friend vec_base operator>>(const vec_base &a, const vec_base &b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] >> b[i]); } BLI_INT_OP(T) friend vec_base operator>>(const vec_base &a, T b) { BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] >> b); } BLI_INT_OP(T) vec_base &operator>>=(T b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] >>= b); } BLI_INT_OP(T) vec_base &operator>>=(const vec_base &b) { BLI_VEC_OP_IMPL_SELF(i, (*this)[i] >>= b[i]); } /** Modulo operators. */ BLI_INT_OP(T) friend vec_base operator%(const vec_base &a, const vec_base &b) { BLI_assert(!math::is_any_zero(b)); BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] % b[i]); } BLI_INT_OP(T) friend vec_base operator%(const vec_base &a, T b) { BLI_assert(b != 0); BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] % b); } BLI_INT_OP(T) friend vec_base operator%(T a, const vec_base &b) { BLI_assert(!math::is_any_zero(b)); BLI_VEC_OP_IMPL(ret, i, ret[i] = a % b[i]); } #undef BLI_INT_OP #undef BLI_VEC_OP_IMPL #undef BLI_VEC_OP_IMPL_SELF /** Compare. */ friend bool operator==(const vec_base &a, const vec_base &b) { for (int i = 0; i < Size; i++) { if (a[i] != b[i]) { return false; } } return true; } friend bool operator!=(const vec_base &a, const vec_base &b) { return !(a == b); } /** Misc. */ uint64_t hash() const { return math::vector_hash(*this); } friend std::ostream &operator<<(std::ostream &stream, const vec_base &v) { stream << "("; for (int i = 0; i < Size; i++) { stream << v[i]; if (i != Size - 1) { stream << ", "; } } stream << ")"; return stream; } }; using int2 = vec_base; using int3 = vec_base; using int4 = vec_base; using uint2 = vec_base; using uint3 = vec_base; using uint4 = vec_base; using float2 = vec_base; using float3 = vec_base; using float4 = vec_base; using double2 = vec_base; using double3 = vec_base; using double4 = vec_base; } // namespace blender