#pragma once #include #include namespace Blah { static constexpr double epsilon = 0.000001; template struct Vec2; template struct Vec3; template struct Vec4; template struct Mat3x2; template struct Mat4x4; template struct Rect; template struct Quad; template struct Line; template struct Circle; using Vec2f = Vec2; using Vec2d = Vec2; using Vec2i = Vec2; using Point = Vec2; using Vec3f = Vec3; using Vec3d = Vec3; using Vec4f = Vec4; using Vec4d = Vec4; using Mat3x2f = Mat3x2; using Mat3x2d = Mat3x2; using Mat4x4f = Mat4x4; using Mat4x4d = Mat4x4; using Rectf = Rect; using Rectd = Rect; using Recti = Rect; using Quadf = Quad; using Quadd = Quad; using Linef = Line; using Lined = Line; using Circlef = Circle; using Circled = Circle; template struct Vec2 { T x; T y; constexpr Vec2(); template constexpr Vec2(X x, Y y); template constexpr Vec2(const Vec2& vector); constexpr Vec2 operator+(const Vec2& rhs) const; constexpr Vec2 operator-(const Vec2& rhs) const; constexpr Vec2 operator/(const T rhs) const; constexpr Vec2 operator*(const T rhs) const; constexpr Vec2 operator*(const Vec2& rhs); constexpr Vec2 operator-() const; constexpr Vec2& operator+=(const Vec2& rhs); constexpr Vec2& operator-=(const Vec2& rhs); constexpr Vec2& operator/=(const Vec2& rhs); constexpr Vec2& operator*=(const Vec2& rhs); constexpr Vec2& operator/=(T rhs); constexpr Vec2& operator*=(T rhs); constexpr bool operator==(const Vec2& rhs) const; constexpr bool operator!=(const Vec2& rhs) const; constexpr Vec2 abs() const; Vec2 normal() const; constexpr Vec2 turn_right() const; constexpr Vec2 turn_left() const; T length() const; constexpr T length_squared() const; T angle() const; static constexpr T dot(const Vec2& a, const Vec2& b); static constexpr Vec2 transform(const Vec2& vec, const Mat3x2& matrix); static constexpr Vec2 transform_normal(const Vec2& vec, const Mat3x2& matrix); static Vec2 from_angle(T radians, T length = 1); static constexpr Vec2 approach(const Vec2& t, const Vec2& target, T delta); static constexpr Vec2 lerp(const Vec2& a, const Vec2& b, T t); static constexpr Vec2 lerp_bezier(const Vec2& a, const Vec2& b, const Vec2& end, T t); static constexpr Vec2 lerp_bezier(const Vec2& a, const Vec2& b, const Vec2& c, const Vec2& end, T t); static constexpr Vec2 reflect(const Vec2& vector, const Vec2& normal); static constexpr Vec2 min(const Vec2& a, const Vec2& b); static constexpr Vec2 max(const Vec2& a, const Vec2& b); static const Vec2 unit_x; static const Vec2 unit_y; static const Vec2 right; static const Vec2 up; static const Vec2 down; static const Vec2 left; static const Vec2 zero; static const Vec2 one; }; template const Vec2 Vec2::unit_x = Vec2(1, 0); template const Vec2 Vec2::unit_y = Vec2(0, 1); template const Vec2 Vec2::right = Vec2(1, 0); template const Vec2 Vec2::up = Vec2(0, -1); template const Vec2 Vec2::down = Vec2(0, 1); template const Vec2 Vec2::left = Vec2(-1, 0); template const Vec2 Vec2::zero = Vec2(0, 0); template const Vec2 Vec2::one = Vec2(1, 1); template struct Vec3 { T x; T y; T z; constexpr Vec3(); template constexpr Vec3(X x, Y y, Z z); template constexpr Vec3(const Vec3& vector); constexpr Vec3 operator +(const Vec3& rhs) const; constexpr Vec3 operator -(const Vec3& rhs) const; T length() const; Vec3 normal() const; static constexpr T dot(const Vec3& a, const Vec3& b); static constexpr Vec3 cross(const Vec3& a, const Vec3& b); }; template struct Vec4 { T x; T y; T z; T w; constexpr Vec4(); template constexpr Vec4(X x, Y y, Z z, W w); template constexpr Vec4(const Vec4& vector); }; template struct Rect { T x; T y; T w; T h; constexpr Rect(); constexpr Rect(T x, T y, T w, T h); template constexpr Rect(X x, Y y, W w, H h); template constexpr Rect(const Rect& rect); constexpr Rect operator+(const Vec2& rhs) const; constexpr Rect operator-(const Vec2& rhs) const; constexpr Rect& operator+=(const Vec2& rhs); constexpr Rect& operator-=(const Vec2& rhs); constexpr bool operator==(const Rect& rhs) const; constexpr bool operator!=(const Rect& rhs) const; constexpr T left() const; constexpr T right() const; constexpr T top() const; constexpr T bottom() const; constexpr Vec2 center() const; constexpr T center_x() const; constexpr T center_y() const; constexpr Vec2 top_left() const; constexpr Vec2 top_right() const; constexpr Vec2 bottom_right() const; constexpr Vec2 bottom_left() const; constexpr Vec2 center_left() const; constexpr Vec2 center_right() const; constexpr Vec2 middle_top() const; constexpr Vec2 middle_bottom() const; constexpr Line left_line() const; constexpr Line right_line() const; constexpr Line top_line() const; constexpr Line bottom_line() const; constexpr bool contains(const Vec2& pt) const; constexpr bool contains(const Rect& rect) const; constexpr bool overlaps(const Rect& rect) const; constexpr Rect overlap_rect(const Rect& other) const; constexpr bool intersects(const Line& line) const; constexpr bool intersects(const Line& line, Vec2* out_intersection_point) const; constexpr bool intersects(const Vec2& line_from, const Vec2& line_to) const; constexpr bool intersects(const Vec2& line_from, const Vec2& line_to, Vec2* out_intersection_point) const; constexpr Vec2 intersection_point(const Line& line) const; constexpr Vec2 intersection_point(const Vec2& line_from, const Vec2& line_to) const; constexpr Rect scale(T s) const; constexpr Rect scale(T sx, T sy) const; constexpr Rect inflate(T amount) const; constexpr Rect inflate(T amount_x, T amount_y) const; // Rect Sectors: // 0101 0100 0110 // 0001 0000 0010 // 1001 1000 1010 // 0000 = inside rectangle, all others refer to sectors relative to the rectangle constexpr u8 get_sector(const Vec2& pt) const; static constexpr Rect transform(const Rect& rect, const Mat3x2& matrix); static constexpr Rect from_points(const Vec2& from, const Vec2& to); }; template struct Circle { Vec2 center; T radius; constexpr Circle(); constexpr Circle(T x, T y, T radius); constexpr Circle(const Vec2& center, T radius); template constexpr Circle(const Circle& circle); constexpr void project(const Vec2& axis, T* min, T* max) const; }; template struct Quad { Vec2 a; Vec2 b; Vec2 c; Vec2 d; constexpr Quad(); constexpr Quad(const Vec2& a, const Vec2& b, const Vec2& c, const Vec2& d); constexpr void project(const Vec2& axis, T* min, T* max) const; }; template struct Line { Vec2 a; Vec2 b; constexpr Line(); constexpr Line(const Vec2& a, const Vec2& b); constexpr Line(T x0, T y0, T x1, T y1); constexpr Rect bounds() const; constexpr Vec2 closest_point(const Vec2& pt) const; constexpr bool intersects(const Rect& rect, Vec2* out_intersection_point = nullptr) const; constexpr bool intersects(const Line& line, Vec2* out_intersection_point = nullptr) const; constexpr void project(const Vec2& axis, T* min, T* max) const; constexpr Line operator +(const Vec2& rhs) const; constexpr Line operator -(const Vec2& rhs) const; }; template struct Mat3x2 { T m11; T m12; T m21; T m22; T m31; T m32; constexpr Mat3x2(); constexpr Mat3x2(T m11, T m12, T m21, T m22, T m31, T m32); template constexpr Mat3x2(const Mat3x2& matrix); static const Mat3x2 identity; constexpr Mat3x2 invert() const; T scaling_factor() const; static constexpr Mat3x2 create_translation(const Vec2& position); static constexpr Mat3x2 create_translation(T x, T y); static constexpr Mat3x2 create_scale(T scale); static constexpr Mat3x2 create_scale(T x, T y); static constexpr Mat3x2 create_scale(const Vec2& scale); static constexpr Mat3x2 create_scale(T scale, const Vec2& center_point); static constexpr Mat3x2 create_scale(const Vec2& scale, const Vec2& center_point); static constexpr Mat3x2 create_scale(T scale_x, T scale_y, const Vec2& center_point); static Mat3x2 create_rotation(T radians); static Mat3x2 create_transform(const Vec2& position, const Vec2& origin, const Vec2& scale, T rotation); static constexpr Mat3x2 add(const Mat3x2& a, const Mat3x2& b); static constexpr Mat3x2 subtract(const Mat3x2& a, const Mat3x2& b); static constexpr Mat3x2 multiply(const Mat3x2& a, const Mat3x2& b); constexpr Mat3x2 operator *(const Mat3x2& rhs) const; constexpr Mat3x2 operator +(const Mat3x2& rhs) const; constexpr Mat3x2 operator -(const Mat3x2& rhs) const; constexpr Mat3x2& operator *=(const Mat3x2& rhs); constexpr bool operator==(const Mat3x2& rhs); constexpr bool operator!=(const Mat3x2& rhs); }; template const Mat3x2 Mat3x2::identity = Mat3x2(1, 0, 0, 1, 0, 0); template struct Mat4x4 { T m11; T m12; T m13; T m14; T m21; T m22; T m23; T m24; T m31; T m32; T m33; T m34; T m41; T m42; T m43; T m44; Mat4x4(); Mat4x4( T m11, T m12, T m13, T m14, T m21, T m22, T m23, T m24, T m31, T m32, T m33, T m34, T m41, T m42, T m43, T m44); static const Mat4x4 identity; static constexpr Mat4x4 create_ortho(T width, T height, T z_near_plane, T z_far_plane); static constexpr Mat4x4 create_ortho_offcenter(T left, T right, T bottom, T top, T z_near_plane, T z_far_plane); static Mat4x4 create_perspective(T field_of_view, T ratio, T z_near_plane, T z_far_plane); static constexpr Mat4x4 create_translation(T x, T y, T z); static constexpr Mat4x4 create_scale(T x, T y, T z); static Mat4x4 create_lookat(const Vec3& position, const Vec3& target, const Vec3& up); constexpr Mat4x4 operator* (const Mat4x4& rhs); }; template const Mat4x4 Mat4x4::identity = Mat4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); template constexpr Vec2::Vec2() : x(0), y(0) {} template template constexpr Vec2::Vec2(X x, Y y) : x(static_cast(x)), y(static_cast(y)) {} template template constexpr Vec2::Vec2(const Vec2& vector) : x(static_cast(vector.x)), y(static_cast(vector.y)) {} template constexpr Vec2 Vec2::operator+(const Vec2& rhs) const { return Vec2(x + rhs.x, y + rhs.y); } template constexpr Vec2 Vec2::operator-(const Vec2& rhs) const { return Vec2(x - rhs.x, y - rhs.y); } template constexpr Vec2 Vec2::operator-() const { return Vec2(-x, -y); } template constexpr Vec2 Vec2::operator/(const T rhs) const { return Vec2(x / rhs, y / rhs); } template constexpr Vec2 Vec2::operator* (const T rhs) const { return Vec2(x * rhs, y * rhs); } template constexpr Vec2 Vec2::operator *(const Vec2& rhs) { return Vec2(x * rhs.x, y * rhs.y); } template constexpr Vec2& Vec2::operator += (const Vec2& rhs) { x += rhs.x; y += rhs.y; return *this; } template constexpr Vec2& Vec2::operator -= (const Vec2& rhs) { x -= rhs.x; y -= rhs.y; return *this; } template constexpr Vec2& Vec2::operator /= (T rhs) { x /= rhs; y /= rhs; return *this; } template constexpr Vec2& Vec2::operator *= (const Vec2 & rhs) { x *= rhs.x; y *= rhs.y; return this; } template constexpr Vec2& Vec2::operator *=(T rhs) { x *= rhs; y *= rhs; return *this; } template constexpr bool Vec2::operator ==(const Vec2& rhs) const { return Calc::abs(x - rhs.x) < epsilon && Calc::abs(y - rhs.y) < epsilon; } template constexpr bool Vec2::operator !=(const Vec2& rhs) const { return !(*this == rhs); } template constexpr Vec2 Vec2::abs() const { return Vec2(Calc::abs(x), Calc::abs(y)); } template Vec2 Vec2::normal() const { auto len = Calc::sqrt(x * x + y * y); if (len <= 0) return Vec2(0, 0); return Vec2(x / len, y / len); } template constexpr Vec2 Vec2::turn_right() const { return Vec2(-y, x); } template constexpr Vec2 Vec2::turn_left() const { return Vec2(y, -x); } template T Vec2::length() const { return static_cast(Calc::sqrt(static_cast(x * x + y * y))); } template constexpr T Vec2::length_squared() const { return x * x + y * y; } template T Vec2::angle() const { return Calc::atan2(y, x); } template constexpr T Vec2::dot(const Vec2& a, const Vec2& b) { return a.x * b.x + a.y * b.y; } template constexpr Vec2 Vec2::transform(const Vec2& vec, const Mat3x2& matrix) { return Vec2( (vec.x * matrix.m11) + (vec.y * matrix.m21) + matrix.m31, (vec.x * matrix.m12) + (vec.y * matrix.m22) + matrix.m32); } template constexpr Vec2 Vec2::transform_normal(const Vec2& vec, const Mat3x2& matrix) { return Vec2( vec.x * matrix.m11 + vec.y * matrix.m21, vec.x * matrix.m12 + vec.y * matrix.m22); } template Vec2 Vec2::from_angle(T radians, T length) { return Vec2( Calc::cos(radians) * length, Calc::sin(radians) * length); } template constexpr Vec2 Vec2::approach(const Vec2& value, const Vec2& target, T delta) { if ((value - target).length_squared() <= delta * delta) return target; return value + (target - value).normal() * delta; } template constexpr Vec2 Vec2::lerp(const Vec2& a, const Vec2& b, T t) { if (t == 0) return a; else if (t == 1) return b; else return a + (b - a) * t; } template constexpr Vec2 Vec2::lerp_bezier(const Vec2& a, const Vec2& b, const Vec2& end, T t) { return lerp(lerp(a, b, t), lerp(b, end, t), t); } template constexpr Vec2 Vec2::lerp_bezier(const Vec2& a, const Vec2& b, const Vec2& c, const Vec2& end, T t) { return lerp_bezier(lerp(a, b, t), lerp(b, c, t), lerp(c, end, t), t); } template constexpr Vec2 Vec2::reflect(const Vec2& vector, const Vec2& normal) { auto dot = vector.x * normal.x + vector.y * normal.y; return Vec2( vector.x - 2 * dot * normal.x, vector.y - 2 * dot * normal.y); } template constexpr Vec2 Vec2::min(const Vec2& a, const Vec2& b) { return Vec2(Calc::min(a.x, b.x), Calc::min(a.y, b.y)); } template constexpr Vec2 Vec2::max(const Vec2& a, const Vec2& b) { return Vec2(Calc::max(a.x, b.x), Calc::max(a.y, b.y)); } template constexpr Vec3::Vec3() : x(0), y(0), z(0) {} template template constexpr Vec3::Vec3(X x, Y y, Z z) : x(static_cast(x)), y(static_cast(y)), z(static_cast(z)) {} template template constexpr Vec3::Vec3(const Vec3& vector) : x(static_cast(vector.x)), y(static_cast(vector.y)), z(static_cast(vector.z)) {} template constexpr Vec3 Vec3::operator+(const Vec3& rhs) const { return Vec3(x + rhs.x, y + rhs.y, z + rhs.z); } template constexpr Vec3 Vec3::operator-(const Vec3& rhs) const { return Vec3(x - rhs.x, y - rhs.y, z - rhs.z); } template T Vec3::length() const { return Calc::sqrt(x * x + y * y + z * z); } template Vec3 Vec3::normal() const { T len = length(); return Vec3(x / len, y / len, z / len); } template constexpr T Vec3::dot(const Vec3& a, const Vec3& b) { return a.x * b.x + a.y * b.y + a.z * b.z; } template constexpr Vec3 Vec3::cross(const Vec3& a, const Vec3& b) { return Vec3( a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); } template constexpr Vec4::Vec4() : x(0), y(0), z(0), w(0) {} template template constexpr Vec4::Vec4(X x, Y y, Z z, W w) : x(static_cast(x)), y(static_cast(y)), z(static_cast(z)), w(static_cast(w)) {} template template constexpr Vec4::Vec4(const Vec4& vector) : x(static_cast(vector.x)), y(static_cast(vector.y)), z(static_cast(vector.z)), w(static_cast(vector.w)) {} template constexpr Rect::Rect() : x(0), y(0), w(0), h(0) {} template constexpr Rect::Rect(T x, T y, T w, T h) : x(x), y(y), w(w), h(h) {} template template constexpr Rect::Rect(X x, Y y, W w, H h) : x(static_cast(x)), y(static_cast(y)), w(static_cast(w)), h(static_cast(h)) {} template template constexpr Rect::Rect(const Rect& rect) : x(static_cast(rect.x)), y(static_cast(rect.y)), w(static_cast(rect.w)), h(static_cast(rect.h)) {} template constexpr Rect Rect::operator+(const Vec2& rhs) const { return Rect(x + rhs.x, y + rhs.y, w, h); } template constexpr Rect Rect::operator-(const Vec2& rhs) const { return Rect(x - rhs.x, y - rhs.y, w, h); } template constexpr Rect& Rect::operator+=(const Vec2& rhs) { x += rhs.x; y += rhs.y; return *this; } template constexpr Rect& Rect::operator-=(const Vec2& rhs) { x -= rhs.x; y -= rhs.y; return *this; } template constexpr bool Rect::operator==(const Rect& rhs) const { return Calc::abs(x - rhs.x) < epsilon && Calc::abs(y - rhs.y) < epsilon && Calc::abs(w - rhs.w) < epsilon && Calc::abs(h - rhs.h) < epsilon; } template constexpr bool Rect::operator!=(const Rect& rhs) const { return !(*this == rhs); } template constexpr T Rect::left() const { return x; } template constexpr T Rect::right() const { return x + w; } template constexpr T Rect::top() const { return y; } template constexpr T Rect::bottom() const { return y + h; } template constexpr Vec2 Rect::center() const { return Vec2(x + w / 2, y + h / 2); } template constexpr T Rect::center_x() const { return x + w / 2; } template constexpr T Rect::center_y() const { return y + h / 2; } template constexpr Vec2 Rect::top_left() const { return Vec2(x, y); } template constexpr Vec2 Rect::top_right() const { return Vec2(x + w, y); } template constexpr Vec2 Rect::bottom_right() const { return Vec2(x + w, y + h); } template constexpr Vec2 Rect::bottom_left() const { return Vec2(x, y + h); } template constexpr Vec2 Rect::center_left() const { return Vec2(x, y + h / 2); } template constexpr Vec2 Rect::center_right() const { return Vec2(x + w, y + h / 2); } template constexpr Vec2 Rect::middle_top() const { return Vec2(x + w / 2, y); } template constexpr Vec2 Rect::middle_bottom() const { return Vec2(x + w / 2, y + h); } template constexpr Line Rect::left_line() const { return Line(left(), top(), left(), bottom()); } template constexpr Line Rect::right_line() const { return Line(right(), top(), right(), bottom()); } template constexpr Line Rect::top_line() const { return Line(left(), top(), right(), top()); } template constexpr Line Rect::bottom_line() const { return Line(left(), bottom(), right(), bottom()); } template constexpr bool Rect::contains(const Vec2& pt) const { return pt.x >= x && pt.x < x + w && pt.y >= y && pt.y < y + h; } template constexpr bool Rect::contains(const Rect& rect) const { return rect.x >= x && rect.x + rect.w < x + w && rect.y >= y && rect.y + rect.h < y + h; } template constexpr bool Rect::overlaps(const Rect& rect) const { return x + w >= rect.x && y + h >= rect.y && x < rect.x + rect.w && y < rect.y + rect.h; } template constexpr Rect Rect::overlap_rect(const Rect& against) const { Rect result; if (x + w >= against.x && x < against.x + against.w) { result.x = Calc::max(x, against.x); result.w = Calc::min(x + w, against.x + against.w) - result.x; } if (y + h >= against.y && y < against.y + against.h) { result.y = Calc::max(y, against.y); result.h = Calc::min(y + h, against.y + against.h) - result.y; } return result; } template constexpr bool Rect::intersects(const Line& line) const { return line.intersects(*this); } template constexpr bool Rect::intersects(const Line& line, Vec2* out_intersection_point) const { return line.intersects(*this, out_intersection_point); } template constexpr bool Rect::intersects(const Vec2& line_from, const Vec2& line_to) const { return intersects(Line(line_from, line_to)); } template constexpr bool Rect::intersects(const Vec2& line_from, const Vec2& line_to, Vec2* out_intersection_point) const { return intersects(Line(line_from, line_to), out_intersection_point); } template constexpr Vec2 Rect::intersection_point(const Line& line) const { Vec2 ret; if (line.intersects(*this, &ret)) return ret; return Vec2::zero; } template constexpr Vec2 Rect::intersection_point(const Vec2& line_from, const Vec2& line_to) const { Vec2 ret; if (Line(line_from, line_to).intersects(*this, &ret)) return ret; return Vec2::zero; } template constexpr Rect Rect::scale(T s) const { return Rect(x * s, y * s, w * s, h * s); } template constexpr Rect Rect::scale(T sx, T sy) const { return Rect(x * sx, y * sy, w * sx, h * sy); } template constexpr Rect Rect::inflate(T amount) const { return Rect(x - amount, y - amount, w + amount * 2, h + amount * 2); } template constexpr Rect Rect::inflate(T amount_x, T amount_y) const { return Rect(x - amount_x, y - amount_y, w + amount_x * 2, h + amount_y * 2); } template constexpr u8 Rect::get_sector(const Vec2& pt) const { u8 result = 0; if (pt.x < left()) result |= 0b0001; else if (pt.x >= right()) result |= 0b0010; if (pt.y < top()) result |= 0b0100; else if (pt.y >= bottom()) result |= 0b1000; return result; } template constexpr Rect Rect::transform(const Rect& rect, const Mat3x2& matrix) { return Rect( (rect.x * matrix.m11) + (rect.y * matrix.m21) + matrix.m31, (rect.x * matrix.m12) + (rect.y * matrix.m22) + matrix.m32, (rect.w * matrix.m11) + (rect.h * matrix.m21), (rect.w * matrix.m12) + (rect.h * matrix.m22)); } template constexpr Rect Rect::from_points(const Vec2& from, const Vec2& to) { auto min = Vec2::min(from, to); auto max = Vec2::max(from, to); return Rect(min.x, min.y, max.x - min.x, max.y - min.y); } template constexpr Quad::Quad() : a(), b(), c(), d() {} template constexpr Quad::Quad(const Vec2& a, const Vec2& b, const Vec2& c, const Vec2& d) : a(a), b(b), c(c), d(d) {} template constexpr void Quad::project(const Vec2& axis, T* min, T* max) const { T dot = Vec2::dot(a, axis); *min = dot; *max = dot; dot = Vec2::dot(b, axis); *min = dot < *min ? dot : *min; *max = dot > *max ? dot : *max; dot = Vec2::dot(c, axis); *min = dot < *min ? dot : *min; *max = dot > *max ? dot : *max; dot = Vec2::dot(d, axis); *min = dot < *min ? dot : *min; *max = dot > *max ? dot : *max; } template constexpr Circle::Circle() : center(0, 0), radius(0) {} template constexpr Circle::Circle(T x, T y, T radius) : center(x, y), radius(radius) {} template constexpr Circle::Circle(const Vec2& center, T radius) : center(center), radius(radius) {} template template constexpr Circle::Circle(const Circle& circle) : center(Vec2(static_cast(circle.center.x), static_cast(circle.center.y))), radius(static_cast(circle.radius)) {} template constexpr void Circle::project(const Vec2& axis, T* min, T* max) const { *min = Vec2::dot(center - axis * radius, axis); *max = Vec2::dot(center + axis * radius, axis); } template constexpr Line::Line() : a(0, 0), b(0, 0) {} template constexpr Line::Line(T x0, T y0, T x1, T y1) : a(x0, y0), b(x1, y1) {} template constexpr Line::Line(const Vec2& a, const Vec2& b) : a(a), b(b) {} template constexpr Rect Line::bounds() const { return Rect::from_points(a, b); } template constexpr Vec2 Line::closest_point(const Vec2& pt) const { auto v = b - a; auto w = pt - a; auto t = Vec2::dot(w, v) / (v.x * v.x + v.y * v.y); if (t < 0) t = 0; else if (t > 1) t = 1; return v * t + a; } template constexpr bool Line::intersects(const Rect& rect, Vec2* out_intersection_point) const { u8 ca = rect.get_sector(a); u8 cb = rect.get_sector(b); if (ca == cb || (ca & cb) != 0) return false; u8 both = ca | cb; // top if ((both & 0b0100) != 0 && intersects(rect.top_line(), out_intersection_point)) return true; // bottom if ((both & 0b1000) != 0 && intersects(rect.bottom_line(), out_intersection_point)) return true; // left if ((both & 0b0001) != 0 && intersects(rect.left_line(), out_intersection_point)) return true; // right if ((both & 0b0010) != 0 && intersects(rect.right_line(), out_intersection_point)) return true; return false; } template constexpr bool Line::intersects(const Line& line, Vec2* out_intersection_point) const { Vec2 e = b - a; Vec2 d = line.b - line.a; T e_dot_d_perp = e.x * d.y - e.y * d.x; // if e dot d == 0, it means the lines are parallel // so have infinite intersection points if (e_dot_d_perp > -epsilon && e_dot_d_perp < epsilon) return false; Vec2 c = line.a - a; T t = (c.x * d.y - c.y * d.x) / e_dot_d_perp; if (t < 0 || t > 1) return false; T u = (c.x * e.y - c.y * e.x) / e_dot_d_perp; if (u < 0 || u > 1) return false; if (out_intersection_point) *out_intersection_point = (e * t) + a; return true; } template constexpr void Line::project(const Vec2& axis, T* min, T* max) const { T dot = a.x * axis.x + a.y * axis.y; *min = dot; *max = dot; dot = b.x * axis.x + b.y * axis.y; *min = dot < *min ? dot : *min; *max = dot > *max ? dot : *max; } template constexpr Line Line::operator+(const Vec2& rhs) const { return Line(a + rhs, b + rhs); } template constexpr Line Line::operator-(const Vec2& rhs) const { return Line(a - rhs, b - rhs); } template constexpr Mat3x2::Mat3x2() : m11(0), m12(0), m21(0), m22(0), m31(0), m32(0) {} template constexpr Mat3x2::Mat3x2(T m11, T m12, T m21, T m22, T m31, T m32) : m11(m11), m12(m12), m21(m21), m22(m22), m31(m31), m32(m32) {} template template constexpr Mat3x2::Mat3x2(const Mat3x2& m) : m11(static_cast(m.m11)), m12(static_cast(m.m12)) , m21(static_cast(m.m21)), m22(static_cast(m.m22)) , m31(static_cast(m.m31)), m32(static_cast(m.m32)) {} template constexpr Mat3x2 Mat3x2::invert() const { auto det = (m11 * m22) - (m21 * m12); auto inv_det = 1 / det; return Mat3x2 ( m22 * inv_det, -m12 * inv_det, -m21 * inv_det, m11 * inv_det, (m21 * m32 - m31 * m22) * inv_det, (m31 * m12 - m11 * m32) * inv_det ); } template T Mat3x2::scaling_factor() const { return Calc::sqrt(m11 * m11 + m12 * m12); } template constexpr Mat3x2 Mat3x2::create_translation(const Vec2& position) { return Mat3x2(1, 0, 0, 1, position.x, position.y); } template constexpr Mat3x2 Mat3x2::create_translation(T x, T y) { return Mat3x2(1, 0, 0, 1, x, y); } template constexpr Mat3x2 Mat3x2::create_scale(T scale) { return Mat3x2(scale, 0, 0, scale, 0, 0); } template constexpr Mat3x2 Mat3x2::create_scale(T x, T y) { return Mat3x2(x, 0, 0, y, 0, 0); } template constexpr Mat3x2 Mat3x2::create_scale(const Vec2& scale) { return Mat3x2(scale.x, 0, 0, scale.y, 0, 0); } template constexpr Mat3x2 Mat3x2::create_scale(T scale, const Vec2& center_point) { auto tx = center_point.x * (1 - scale); auto ty = center_point.y * (1 - scale); Mat3x2 result; result.m11 = scale; result.m12 = 0; result.m21 = 0; result.m22 = scale; result.m31 = tx; result.m32 = ty; return result; } template constexpr Mat3x2 Mat3x2::create_scale(const Vec2& scale, const Vec2& center_point) { auto tx = center_point.x * (1 - scale.x); auto ty = center_point.y * (1 - scale.y); Mat3x2 result; result.m11 = scale.x; result.m12 = 0; result.m21 = 0; result.m22 = scale.y; result.m31 = tx; result.m32 = ty; return result; } template constexpr Mat3x2 Mat3x2::create_scale(T scale_x, T scale_y, const Vec2& center_point) { auto tx = center_point.x * (1 - scale_x); auto ty = center_point.y * (1 - scale_y); Mat3x2 result; result.m11 = scale_x; result.m12 = 0; result.m21 = 0; result.m22 = scale_y; result.m31 = tx; result.m32 = ty; return result; } template Mat3x2 Mat3x2::create_rotation(T radians) { auto c = Calc::cos(radians); auto s = Calc::sin(radians); return Mat3x2(c, s, -s, c, 0, 0); } template Mat3x2 Mat3x2::create_transform(const Vec2& position, const Vec2& origin, const Vec2& scale, T rotation) { Mat3x2 matrix = identity; if (origin.x != 0 || origin.y != 0) matrix = create_translation(-origin.x, -origin.y); if (scale.x != 1 || scale.y != 1) matrix = matrix * create_scale(scale); if (rotation != 0) matrix = matrix * create_rotation(rotation); if (position.x != 0 || position.y != 0) matrix = matrix * create_translation(position); return matrix; } template constexpr Mat3x2 Mat3x2::add(const Mat3x2& a, const Mat3x2& b) { return Mat3x2( a.m11 + b.m11, a.m12 + b.m12, a.m21 + b.m21, a.m22 + b.m22, a.m31 + b.m31, a.m32 + b.m32); } template constexpr Mat3x2 Mat3x2::subtract(const Mat3x2& a, const Mat3x2& b) { return Mat3x2( a.m11 - b.m11, a.m12 - b.m12, a.m21 - b.m21, a.m22 - b.m22, a.m31 - b.m31, a.m32 - b.m32); } template constexpr Mat3x2 Mat3x2::multiply(const Mat3x2& a, const Mat3x2& b) { return Mat3x2(a.m11 * b.m11 + a.m12 * b.m21, a.m11 * b.m12 + a.m12 * b.m22, a.m21 * b.m11 + a.m22 * b.m21, a.m21 * b.m12 + a.m22 * b.m22, a.m31 * b.m11 + a.m32 * b.m21 + b.m31, a.m31 * b.m12 + a.m32 * b.m22 + b.m32); } template constexpr Mat3x2 Mat3x2::operator *(const Mat3x2& rhs) const { return multiply(*this, rhs); } template constexpr Mat3x2 Mat3x2::operator +(const Mat3x2& rhs) const { return add(*this, rhs); } template constexpr Mat3x2 Mat3x2::operator -(const Mat3x2& rhs) const { return subtract(*this, rhs); } template constexpr Mat3x2& Mat3x2::operator *=(const Mat3x2& rhs) { *this = multiply(*this, rhs); return *this; } template constexpr bool Mat3x2::operator==(const Mat3x2& rhs) { return Calc::abs(m11 - rhs.m11) < epsilon && Calc::abs(m12 - rhs.m12) < epsilon && Calc::abs(m21 - rhs.m21) < epsilon && Calc::abs(m22 - rhs.m22) < epsilon && Calc::abs(m31 - rhs.m31) < epsilon && Calc::abs(m32 - rhs.m32) < epsilon; } template constexpr bool Mat3x2::operator!=(const Mat3x2& rhs) { return !(*this == rhs); } template Mat4x4::Mat4x4() : m11(0.0f), m12(0.0f), m13(0.0f), m14(0.0f), m21(0.0f), m22(0.0f), m23(0.0f), m24(0.0f), m31(0.0f), m32(0.0f), m33(0.0f), m34(0.0f), m41(0.0f), m42(0.0f), m43(0.0f), m44(0.0f) {} template Mat4x4::Mat4x4( T m11, T m12, T m13, T m14, T m21, T m22, T m23, T m24, T m31, T m32, T m33, T m34, T m41, T m42, T m43, T m44) : m11(m11), m12(m12), m13(m13), m14(m14), m21(m21), m22(m22), m23(m23), m24(m24), m31(m31), m32(m32), m33(m33), m34(m34), m41(m41), m42(m42), m43(m43), m44(m44) {} template constexpr Mat4x4 Mat4x4::create_ortho(T width, T height, T z_near_plane, T z_far_plane) { Mat4x4 result = identity; result.m11 = 2 / width; result.m12 = result.m13 = result.m14 = 0; result.m22 = -2 / height; result.m21 = result.m23 = result.m24 = 0; result.m33 = 1 / (z_near_plane - z_far_plane); result.m31 = result.m32 = result.m34 = 0; result.m41 = result.m42 = 0; result.m43 = z_near_plane / (z_near_plane - z_far_plane); result.m44 = 1; return result; } template constexpr Mat4x4 Mat4x4::create_ortho_offcenter(T left, T right, T bottom, T top, T z_near_plane, T z_far_plane) { Mat4x4 result = identity; result.m11 = 2 / (right - left); result.m12 = result.m13 = result.m14 = 0; result.m22 = 2 / (top - bottom); result.m21 = result.m23 = result.m24 = 0; result.m33 = 1 / (z_near_plane - z_far_plane); result.m31 = result.m32 = result.m34 = 0; result.m41 = (left + right) / (left - right); result.m42 = (top + bottom) / (bottom - top); result.m43 = z_near_plane / (z_near_plane - z_far_plane); result.m44 = 1; return result; } template Mat4x4 Mat4x4::create_perspective(T field_of_view, T ratio, T z_near_plane, T z_far_plane) { auto scale_x = 1 / Calc::tan(field_of_view * 0.5); auto scale_y = scale_x / ratio; Mat4x4 result; result.m11 = scale_y; result.m12 = result.m13 = result.m14 = 0; result.m22 = scale_x; result.m21 = result.m23 = result.m24 = 0; result.m31 = result.m32 = 0; result.m33 = z_far_plane / (z_near_plane - z_far_plane); result.m34 = -1; result.m41 = result.m42 = result.m44 = 0; result.m43 = z_near_plane * z_far_plane / (z_near_plane - z_far_plane); return result; } template constexpr Mat4x4 Mat4x4::create_translation(T x, T y, T z) { Mat4x4 result = identity; result.m41 = x; result.m42 = y; result.m43 = z; return result; } template constexpr Mat4x4 Mat4x4::create_scale(T x, T y, T z) { Mat4x4 result = identity; result.m11 = x; result.m22 = y; result.m33 = z; return result; } template Mat4x4 Mat4x4::create_lookat(const Vec3& position, const Vec3& target, const Vec3& up) { auto zaxis = (position - target).normal(); auto xaxis = Vec3::cross(up, zaxis).normal(); auto yaxis = Vec3::cross(zaxis, xaxis); Mat4x4 result; result.m11 = xaxis.x; result.m12 = yaxis.x; result.m13 = zaxis.x; result.m14 = 0.0f; result.m21 = xaxis.y; result.m22 = yaxis.y; result.m23 = zaxis.y; result.m24 = 0.0f; result.m31 = xaxis.z; result.m32 = yaxis.z; result.m33 = zaxis.z; result.m34 = 0.0f; result.m41 = -Vec3::dot(xaxis, position); result.m42 = -Vec3::dot(yaxis, position); result.m43 = -Vec3::dot(zaxis, position); result.m44 = 1.0f; return result; } template constexpr Mat4x4 Mat4x4::operator*(const Mat4x4& rhs) { Mat4x4 m; m.m11 = m11 * rhs.m11 + m12 * rhs.m21 + m13 * rhs.m31 + m14 * rhs.m41; m.m12 = m11 * rhs.m12 + m12 * rhs.m22 + m13 * rhs.m32 + m14 * rhs.m42; m.m13 = m11 * rhs.m13 + m12 * rhs.m23 + m13 * rhs.m33 + m14 * rhs.m43; m.m14 = m11 * rhs.m14 + m12 * rhs.m24 + m13 * rhs.m34 + m14 * rhs.m44; m.m21 = m21 * rhs.m11 + m22 * rhs.m21 + m23 * rhs.m31 + m24 * rhs.m41; m.m22 = m21 * rhs.m12 + m22 * rhs.m22 + m23 * rhs.m32 + m24 * rhs.m42; m.m23 = m21 * rhs.m13 + m22 * rhs.m23 + m23 * rhs.m33 + m24 * rhs.m43; m.m24 = m21 * rhs.m14 + m22 * rhs.m24 + m23 * rhs.m34 + m24 * rhs.m44; m.m31 = m31 * rhs.m11 + m32 * rhs.m21 + m33 * rhs.m31 + m34 * rhs.m41; m.m32 = m31 * rhs.m12 + m32 * rhs.m22 + m33 * rhs.m32 + m34 * rhs.m42; m.m33 = m31 * rhs.m13 + m32 * rhs.m23 + m33 * rhs.m33 + m34 * rhs.m43; m.m34 = m31 * rhs.m14 + m32 * rhs.m24 + m33 * rhs.m34 + m34 * rhs.m44; m.m41 = m41 * rhs.m11 + m42 * rhs.m21 + m43 * rhs.m31 + m44 * rhs.m41; m.m42 = m41 * rhs.m12 + m42 * rhs.m22 + m43 * rhs.m32 + m44 * rhs.m42; m.m43 = m41 * rhs.m13 + m42 * rhs.m23 + m43 * rhs.m33 + m44 * rhs.m43; m.m44 = m41 * rhs.m14 + m42 * rhs.m24 + m43 * rhs.m34 + m44 * rhs.m44; return m; } }