#ifndef MATH_VECTOR_HPP #define MATH_VECTOR_HPP #include namespace engine::math { namespace vector_coords { enum class VectorCoord { x, y, z, w }; template struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> struct transpose { template static constexpr VectorCoord id(); }; template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::x; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::y; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::z; } template<> constexpr VectorCoord transpose::id() { return VectorCoord::w; } } struct Vector2; struct Vector3; struct Vector4; template concept VectorTypeConcept = std::is_same_v || std::is_same_v || std::is_same_v; constexpr Vector2 operator*(float n, const Vector2& other); constexpr Vector2 operator/(const Vector2& other, float n); struct Vector2 { static constexpr size_t size = 2; static constexpr Vector2 bilerp(const Vector2& v1, const Vector2& v2, const Vector2& v3, float b0, float b1) { return b0 * v1 + b1 * v2 + (1.f - b0 - b1) * v3; } float x, y; constexpr Vector2() {} constexpr Vector2(float x, float y) : x { x }, y { y } {} template constexpr float& v() & requires (id == vector_coords::VectorCoord::x || id == vector_coords::VectorCoord::y) { if constexpr (id == vector_coords::VectorCoord::x) return x; else return y; } template constexpr const float& v() const & requires (id == vector_coords::VectorCoord::x || id == vector_coords::VectorCoord::y) { if constexpr (id == vector_coords::VectorCoord::x) return x; else return y; } constexpr bool operator==(const Vector2& other) const & { return x == other.x && y == other.y; } constexpr bool operator!=(const Vector2& other) const & { return !(*this == other); } constexpr Vector2 operator+() const & { return *this; } constexpr Vector2 operator-() const & { return { -x, -y }; } constexpr Vector2 operator+(const Vector2& other) const & { return { x + other.x, y + other.y }; } constexpr Vector2 operator-(const Vector2& other) const & { return *this + (-other); } constexpr Vector2 operator+=(const Vector2& other) & { x += other.x; y += other.y; return *this; } constexpr float det(const Vector2& other) const & { return this->x * other.y - other.x * this->y; } constexpr Vector2 round() const & { return { std::round(x), std::round(y) }; } constexpr Vector2 mul_term(const Vector2& other) const & { return { x * other.x, y * other.y }; } constexpr Vector2 map(const Vector2& from1, const Vector2& from2, const Vector2& to1, const Vector2& to2) { return { to1.x + (x - from1.x) * (to2.x - to1.x) / (from2.x - from1.x), to1.y + (y - from1.y) * (to2.y - to1.y) / (from2.y - from1.y), }; } }; constexpr Vector2 operator*(float n, const Vector2& other) { return { n * other.x, n * other.y }; } constexpr Vector2 operator*(const Vector2& other, float n) { return n * other; } constexpr Vector2 operator/(const Vector2& other, float n) { return { other.x / n, other.y / n }; } constexpr Vector2 operator+(const Vector2& other, float n) { return { other.x + n, other.y + n }; } constexpr Vector2 operator-(const Vector2& other, float n) { return { other.x - n, other.y - n }; } constexpr Vector3 operator*(float n, const Vector3& other); constexpr Vector3 operator/(const Vector3& other, float n); struct Vector3 { static constexpr size_t size = 3; static constexpr Vector3 bilerp(const Vector3& v1, const Vector3& v2, const Vector3& v3, float b0, float b1) { return b0 * v1 + b1 * v2 + (1.f - b0 - b1) * v3; } float x, y, z; constexpr Vector3() {} constexpr Vector3(float x, float y, float z) : x { x }, y { y }, z { z } {} constexpr Vector3(const Vector2& v, float z) : x { v.x }, y { v.y }, z { z } {} template constexpr float& v() & requires (id == vector_coords::VectorCoord::x || id == vector_coords::VectorCoord::y || id == vector_coords::VectorCoord::z) { if constexpr (id == vector_coords::VectorCoord::x) return x; else if constexpr (id == vector_coords::VectorCoord::y) return y; else return z; } template constexpr const float& v() const & requires (id == vector_coords::VectorCoord::x || id == vector_coords::VectorCoord::y || id == vector_coords::VectorCoord::z) { if constexpr (id == vector_coords::VectorCoord::x) return x; else if constexpr (id == vector_coords::VectorCoord::y) return y; else return z; } constexpr bool operator==(const Vector3& other) const & { return x == other.x && y == other.y && z == other.z; } constexpr bool operator!=(const Vector3& other) const & { return !(*this == other); } constexpr Vector3 operator+() const & { return *this; } constexpr Vector3 operator-() const & { return { -x, -y, -z }; } constexpr Vector3 operator+(const Vector3& other) const & { return { x + other.x, y + other.y, z + other.z }; } constexpr Vector3 operator-(const Vector3& other) const & { return *this + (-other); } constexpr Vector3 operator+=(const Vector3& other) & { x += other.x; y += other.y; z += other.z; return *this; } constexpr Vector2 xy() const & { return { x, y }; } constexpr Vector3 round() { return { std::round(x), std::round(y), std::round(z) }; } constexpr Vector3 cross(const Vector3& other) const & { return { y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x }; } constexpr float dot(const Vector3& other) const & { return x * other.x + y * other.y + z * other.z; } constexpr float length_squared() const & { return dot(*this); } constexpr float length() const & { return std::sqrt(length_squared()); } constexpr Vector3 normalize() const & { return *this / length(); } constexpr Vector3 map(const Vector3& from1, const Vector3& from2, const Vector3& to1, const Vector3& to2) { return { to1.x + (x - from1.x) * (to2.x - to1.x) / (from2.x - from1.x), to1.y + (y - from1.y) * (to2.y - to1.y) / (from2.y - from1.y), to1.z + (z - from1.z) * (to2.z - to1.z) / (from2.z - from1.z), }; } }; constexpr Vector3 operator*(float n, const Vector3& other) { return { n * other.x, n * other.y, n * other.z }; } constexpr Vector3 operator*(const Vector3& other, float n) { return n * other; } constexpr Vector3 operator/(float n, const Vector3& other) { return { n / other.x, n / other.y, n / other.z }; } constexpr Vector3 operator/(const Vector3& other, float n) { return { other.x / n, other.y / n, other.z / n }; } struct Vector4 { static constexpr size_t size = 4; float x, y, z, w; template constexpr float& v() & { if constexpr (id == vector_coords::VectorCoord::x) return x; else if constexpr (id == vector_coords::VectorCoord::y) return y; else if constexpr (id == vector_coords::VectorCoord::z) return z; else return w; } template constexpr const float& v() const & { if constexpr (id == vector_coords::VectorCoord::x) return x; else if constexpr (id == vector_coords::VectorCoord::y) return y; else if constexpr (id == vector_coords::VectorCoord::z) return z; else return w; } constexpr Vector4() {} constexpr Vector4(float x, float y, float z, float w) : x{x}, y{y}, z{z}, w{w} {} constexpr Vector4(const Vector2& v, float z, float w) : x{v.x}, y{v.y}, z{z}, w{w} {} constexpr Vector4(const Vector3& v, float w) : x{v.x}, y{v.y}, z{v.z}, w{w} {} constexpr bool operator==(const Vector4& other) const & { return x == other.x && y == other.y && z == other.z && w == other.w; } constexpr bool operator!=(const Vector4& other) const & { return !(*this == other); } constexpr Vector4 operator+() const & { return *this; } constexpr Vector4 operator-() const & { return { -x, -y, -z, -w }; } constexpr Vector4 operator+(const Vector4& other) const & { return { x + other.x, y + other.y, z + other.z, w + other.w }; } constexpr Vector4 operator-(const Vector4& other) const & { return *this + (-other); } constexpr Vector4 round() const & { return { std::round(x), std::round(y), std::round(z), std::round(w) }; } constexpr Vector2 xy() const & { return { x, y }; } constexpr Vector3 xyz() const & { return { x, y, z }; } constexpr Vector3 div_by_w() const & { return { x / w, y / w, w }; } constexpr Vector4 map(const Vector4& from1, const Vector4& from2, const Vector4& to1, const Vector4& to2) { return { to1.x + (x - from1.x) * (to2.x - to1.x) / (from2.x - from1.x), to1.y + (y - from1.y) * (to2.y - to1.y) / (from2.y - from1.y), to1.z + (z - from1.z) * (to2.z - to1.z) / (from2.z - from1.z), to1.w + (w - from1.w) * (to2.w - to1.w) / (from2.w - from1.w), }; } }; constexpr Vector4 operator*(float n, const Vector4& other) { return { n * other.x, n * other.y, n * other.z, n * other.w }; } constexpr Vector4 operator*(const Vector4& other, float n) { return n * other; } constexpr Vector4 operator/(const Vector4& other, float n) { return { other.x / n, other.y / n, other.z / n, other.w / n }; } } #endif // MATH_VECTOR_HPP