module; import std; export module LunarWM.Math; export namespace LunarWM { namespace Math { template requires std::is_arithmetic_v struct Vec2 { template requires std::is_arithmetic_v Vec2 operator+(Vec2 const &other) { return { x + other.x, y + other.y }; } template requires std::is_arithmetic_v Vec2 operator-(Vec2 const &other) { return { x - other.x, y - other.y }; } template requires std::is_arithmetic_v Vec2 operator*(Vec2 const &other) { return { x * other.x, y * other.x }; } template requires std::is_arithmetic_v Vec2 operator*(T scalar) { return { x * scalar, y * scalar }; } template requires std::is_arithmetic_v Vec2 operator/(T scalar) { return { x / scalar, y / scalar }; } template requires std::is_arithmetic_v Vec2 operator-() { return { -x, -y }; } T length() const { return std::sqrt(x * x + y * y); } T lengthSquared() const { return x * x + y * y; } Vec2 normalized() const { T len = length(); if (len == T(0)) return { T(0), T(0) }; return *this / len; } T x, y; }; template requires std::is_arithmetic_v Vec2 operator*(T scalar, Vec2 const &v) { return { v.x * scalar, v.y * scalar }; } template requires std::is_arithmetic_v struct Rect { Rect(Vec2 pos, Vec2 size) : pos(pos) , size(size) { } Rect(T x, T y, T w, T h) : pos({ x, y }) , size({ w, h }) { } T &x() { return pos.x; } T &y() { return pos.y; } T &w() { return size.x; } T &h() { return size.y; } T x() const { return pos.x; } T y() const { return pos.y; } T w() const { return size.x; } T h() const { return size.y; } T left() const { return x(); } T right() const { return x() + w(); } T top() const { return y(); } T bottom() const { return y() + h(); } T &left() { return x(); } T &top() { return y(); } Vec2 pos, size; }; template requires std::is_arithmetic_v struct Box { template requires std::is_arithmetic_v Vec2 &operator[](U const index) { if (index < 0 || index > 1) throw std::out_of_range("A box only has two points"); return m_data[index]; } Vec2 &first() { return m_data[0]; } Vec2 &second() { return m_data[1]; } T &x0() { return m_data[0].x; } T &y0() { return m_data[0].y; } T &x1() { return m_data[1].x; } T &y1() { return m_data[1].y; } T &left() { if (x0() < x1()) return x0(); return x1(); } T &right() { if (x0() > x1()) return x0(); return x1(); } T &top() { if (y0() < y1()) return y0(); return y1(); } T &bottom() { if (y0() > y1()) return y0(); return y1(); } Box() { } Box(Rect rect) { this->m_data[0] = rect.pos; this->m_data[1] = rect.pos + rect.size; } private: Vec2 m_data[2] = {}; }; template requires std::is_arithmetic_v std::vector> subtract_rect( Math::Rect const &src, Math::Rect const &clip) { std::vector> result; auto sx = src.x(); auto sy = src.y(); auto sw = src.w(); auto sh = src.h(); auto cx = clip.x(); auto cy = clip.y(); auto cw = clip.w(); auto ch = clip.h(); T s_right = sx + sw; T s_bottom = sy + sh; T c_right = cx + cw; T c_bottom = cy + ch; // No overlap → keep src if (c_right <= sx || cx >= s_right || c_bottom <= sy || cy >= s_bottom) { result.push_back(src); return result; } // Top piece if (cy > sy) { result.emplace_back(sx, sy, sw, cy - sy); } // Bottom piece if (c_bottom < s_bottom) { result.emplace_back(sx, c_bottom, sw, s_bottom - c_bottom); } // Middle pieces left and right of clip T middle_top = std::max(sy, cy); T middle_bottom = std::min(s_bottom, c_bottom); T middle_height = middle_bottom - middle_top; if (middle_height > 0) { // Left piece if (cx > sx) { result.emplace_back(sx, middle_top, cx - sx, middle_height); } // Right piece if (c_right < s_right) { result.emplace_back( c_right, middle_top, s_right - c_right, middle_height); } } return result; } template requires std::is_arithmetic_v struct Viewport { Rect rect; Vec2 depth_limits; }; } // namespace Math } // namespace LunarWM