#pragma once #include #include #include #ifndef AURORA_VEC2_EXTRA #define AURORA_VEC2_EXTRA #endif #ifndef AURORA_VEC3_EXTRA #define AURORA_VEC3_EXTRA #endif #ifndef AURORA_VEC4_EXTRA #define AURORA_VEC4_EXTRA #endif #ifndef AURORA_MAT4X4_EXTRA #define AURORA_MAT4X4_EXTRA #endif #ifndef __has_attribute #define __has_attribute(x) 0 #endif #ifndef __has_builtin #define __has_builtin(x) 0 #endif #if __has_attribute(vector_size) && !defined(__clang__) #define USE_GCC_VECTOR_EXTENSIONS #endif namespace aurora { template struct Vec2 { T x{}; T y{}; constexpr Vec2() = default; constexpr Vec2(T x, T y) : x(x), y(y) {} AURORA_VEC2_EXTRA bool operator==(const Vec2& rhs) const { return x == rhs.x && y == rhs.y; } bool operator!=(const Vec2& rhs) const { return !(*this == rhs); } }; template struct Vec3 { T x{}; T y{}; T z{}; constexpr Vec3() = default; constexpr Vec3(T x, T y, T z) : x(x), y(y), z(z) {} AURORA_VEC3_EXTRA bool operator==(const Vec3& rhs) const { return x == rhs.x && y == rhs.y && z == rhs.z; } bool operator!=(const Vec3& rhs) const { return !(*this == rhs); } }; template struct Vec4 { #ifdef USE_GCC_VECTOR_EXTENSIONS typedef T Vt __attribute__((vector_size(sizeof(T) * 4))); Vt m; #else using Vt = T[4]; Vt m; #endif constexpr Vec4() = default; constexpr Vec4(Vt m) : m(m) {} constexpr Vec4(T x, T y, T z, T w) : m{x, y, z, w} {} // For Vec3 with padding constexpr Vec4(T x, T y, T z) : m{x, y, z, {}} {} // For Vec3 -> Vec4 constexpr Vec4(Vec3 v, T w) : m{v.x, v.y, v.z, w} {} AURORA_VEC4_EXTRA inline Vec4& operator=(const Vec4& other) { memcpy(&m, &other.m, sizeof(Vt)); return *this; } [[nodiscard]] inline T& x() { return m[0]; } [[nodiscard]] inline T x() const { return m[0]; } [[nodiscard]] inline T& y() { return m[1]; } [[nodiscard]] inline T y() const { return m[1]; } [[nodiscard]] inline T& z() { return m[2]; } [[nodiscard]] inline T z() const { return m[2]; } [[nodiscard]] inline T& w() { return m[3]; } [[nodiscard]] inline T w() const { return m[3]; } [[nodiscard]] inline T& operator[](size_t i) { return m[i]; } [[nodiscard]] inline T operator[](size_t i) const { return m[i]; } template [[nodiscard]] constexpr Vec4 shuffle() const { static_assert(x < 4 && y < 4 && z < 4 && w < 4); #if defined(USE_GCC_VECTOR_EXTENSIONS) && __has_builtin(__builtin_shuffle) typedef int Vi __attribute__((vector_size(16))); return __builtin_shuffle(m, Vi{x, y, z, w}); #else return {m[x], m[y], m[z], m[w]}; #endif } bool operator==(const Vec4& rhs) const { #if defined(USE_GCC_VECTOR_EXTENSIONS) && __has_builtin(__builtin_reduce_and) return __builtin_reduce_and(m == rhs.m) != 0; #else return m[0] == rhs.m[0] && m[1] == rhs.m[1] && m[2] == rhs.m[2] && m[3] == rhs.m[3]; #endif } bool operator!=(const Vec4& rhs) const { return !(*this == rhs); } }; template [[nodiscard]] Vec4 operator+(const Vec4& a, const Vec4& b) { #ifdef USE_GCC_VECTOR_EXTENSIONS return a.m + b.m; #else return {a.m[0] + b.m[0], a.m[1] + b.m[1], a.m[2] + b.m[2], a.m[3] + b.m[3]}; #endif } template [[nodiscard]] Vec4 operator*(const Vec4& a, const Vec4& b) { #ifdef USE_GCC_VECTOR_EXTENSIONS return a.m * b.m; #else return {a.m[0] * b.m[0], a.m[1] * b.m[1], a.m[2] * b.m[2], a.m[3] * b.m[3]}; #endif } template struct Mat3x2 { Vec2 m0{}; Vec2 m1{}; Vec2 m2{}; constexpr Mat3x2() = default; constexpr Mat3x2(const Vec2& m0, const Vec2& m1, const Vec2& m2) : m0(m0), m1(m1), m2(m2) {} bool operator==(const Mat3x2& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1 && m2 == rhs.m2; } bool operator!=(const Mat3x2& rhs) const { return !(*this == rhs); } }; template struct Mat4x2 { Vec2 m0{}; Vec2 m1{}; Vec2 m2{}; Vec2 m3{}; constexpr Mat4x2() = default; constexpr Mat4x2(const Vec2& m0, const Vec2& m1, const Vec2& m2, const Vec2& m3) : m0(m0), m1(m1), m2(m2), m3(m3) {} inline Mat4x2 transpose() const { return { {m0.x, m2.x}, {m0.y, m2.y}, {m1.x, m3.x}, {m1.y, m3.y}, }; } bool operator==(const Mat4x2& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1 && m2 == rhs.m2 && m3 == rhs.m3; } bool operator!=(const Mat4x2& rhs) const { return !(*this == rhs); } }; template struct Mat2x4 { Vec4 m0{}; Vec4 m1{}; constexpr Mat2x4() = default; constexpr Mat2x4(const Vec4& m0, const Vec4& m1, const Vec4& m2) : m0(m0), m1(m1) {} bool operator==(const Mat2x4& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1; } bool operator!=(const Mat2x4& rhs) const { return !(*this == rhs); } }; static_assert(sizeof(Mat2x4) == 32); template struct Mat4x4; template struct Mat3x4 { Vec4 m0{}; Vec4 m1{}; Vec4 m2{}; constexpr Mat3x4() = default; constexpr Mat3x4(const Vec4& m0, const Vec4& m1, const Vec4& m2) : m0(m0), m1(m1), m2(m2) {} [[nodiscard]] Mat4x4 to4x4() const; [[nodiscard]] Mat4x4 toTransposed4x4() const; bool operator==(const Mat3x4& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1 && m2 == rhs.m2; } bool operator!=(const Mat3x4& rhs) const { return !(*this == rhs); } }; static_assert(sizeof(Mat3x4) == 48); template struct Mat4x4 { Vec4 m0{}; Vec4 m1{}; Vec4 m2{}; Vec4 m3{}; constexpr Mat4x4() = default; constexpr Mat4x4(const Vec4& m0, const Vec4& m1, const Vec4& m2, const Vec4& m3) : m0(m0), m1(m1), m2(m2), m3(m3) {} AURORA_MAT4X4_EXTRA [[nodiscard]] Mat4x4 transpose() const { return { {m0[0], m1[0], m2[0], m3[0]}, {m0[1], m1[1], m2[1], m3[1]}, {m0[2], m1[2], m2[2], m3[2]}, {m0[3], m1[3], m2[3], m3[3]}, }; } Mat4x4& operator=(const Mat4x4& other) = default; Vec4& operator[](size_t i) { return *(&m0 + i); } const Vec4& operator[](size_t i) const { return *(&m0 + i); } bool operator==(const Mat4x4& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1 && m2 == rhs.m2 && m3 == rhs.m3; } bool operator!=(const Mat4x4& rhs) const { return !(*this == rhs); } }; static_assert(sizeof(Mat4x4) == 64); template [[nodiscard]] Mat4x4 operator*(const Mat4x4& a, const Mat4x4& b) { Mat4x4 out; for (size_t i = 0; i < 4; ++i) { *(&out.m0 + i) = a.m0 * b[i].template shuffle<0, 0, 0, 0>() + a.m1 * b[i].template shuffle<1, 1, 1, 1>() + a.m2 * b[i].template shuffle<2, 2, 2, 2>() + a.m3 * b[i].template shuffle<3, 3, 3, 3>(); } return out; } template [[nodiscard]] Mat4x4 Mat3x4::to4x4() const { return { {m0[0], m0[1], m0[2], 0.f}, {m1[0], m1[1], m1[2], 0.f}, {m2[0], m2[1], m2[2], 0.f}, {m0[3], m1[3], m2[3], 1.f}, }; } template [[nodiscard]] Mat4x4 Mat3x4::toTransposed4x4() const { return Mat4x4{ {m0[0], m1[0], m2[0], 0.f}, {m0[1], m1[1], m2[1], 0.f}, {m0[2], m1[2], m2[2], 0.f}, {m0[3], m1[3], m2[3], 1.f}, }; } constexpr Mat4x4 Mat4x4_Identity{ Vec4{1.f, 0.f, 0.f, 0.f}, Vec4{0.f, 1.f, 0.f, 0.f}, Vec4{0.f, 0.f, 1.f, 0.f}, Vec4{0.f, 0.f, 0.f, 1.f}, }; } // namespace aurora