Files
lunarwm/src/Math.cppm
Slendi 14f2e52722 Stuff
Signed-off-by: Slendi <slendi@socopon.com>
2025-07-23 15:57:12 +03:00

225 lines
4.7 KiB
C++

export module LunarWM.Math;
import std;
export namespace LunarWM::Math {
template<typename T = float>
requires std::is_arithmetic_v<T> struct Vec2 {
template<typename U = T>
requires std::is_arithmetic_v<U>
auto operator+(Vec2<U> const &other) -> Vec2<U>
{
return { x + other.x, y + other.y };
}
template<typename U = T>
requires std::is_arithmetic_v<U>
auto operator-(Vec2<U> const &other) -> Vec2<U>
{
return { x - other.x, y - other.y };
}
template<typename U = T>
requires std::is_arithmetic_v<U>
auto operator*(Vec2<U> const &other) -> Vec2<U>
{
return { x * other.x, y * other.x };
}
template<typename U = T>
requires std::is_arithmetic_v<U> auto operator*(T scalar) -> Vec2<U>
{
return { x * scalar, y * scalar };
}
template<typename U = T>
requires std::is_arithmetic_v<U> auto operator/(T scalar) -> Vec2<U>
{
return { x / scalar, y / scalar };
}
template<typename U = T>
requires std::is_arithmetic_v<U> auto operator-() -> Vec2
{
return { -x, -y };
}
auto length() const -> T { return std::sqrt(x * x + y * y); }
auto lengthSquared() const -> T { return x * x + y * y; }
auto normalized() const -> Vec2<T>
{
T len = length();
if (len == T(0)) {
return { T(0), T(0) };
}
return *this / len;
}
T x, y;
};
template<typename T>
requires std::is_arithmetic_v<T>
auto operator*(T scalar, Vec2<T> const &v) -> Vec2<T>
{
return { v.x * scalar, v.y * scalar };
}
template<typename T = float>
requires std::is_arithmetic_v<T> struct Rect {
Rect(Vec2<T> pos, Vec2<T> size)
: pos(pos)
, size(size)
{
}
Rect(T x, T y, T w, T h)
: pos({ x, y })
, size({ w, h })
{
}
auto x() -> T & { return pos.x; }
auto y() -> T & { return pos.y; }
auto w() -> T & { return size.x; }
auto h() -> T & { return size.y; }
auto x() const -> T { return pos.x; }
auto y() const -> T { return pos.y; }
auto w() const -> T { return size.x; }
auto h() const -> T { return size.y; }
auto left() const -> T { return x(); }
auto right() const -> T { return x() + w(); }
auto top() const -> T { return y(); }
auto bottom() const -> T { return y() + h(); }
auto left() -> T & { return x(); }
auto top() -> T & { return y(); }
Vec2<T> pos, size;
};
template<typename T = float>
requires std::is_arithmetic_v<T> struct Box {
template<typename U = int>
requires std::is_arithmetic_v<U> auto operator[](U const index) -> Vec2<T> &
{
if (index < 0 || index > 1) {
throw std::out_of_range("A box only has two points");
}
return m_data[index];
}
auto first() -> Vec2<T> & { return m_data[0]; }
auto second() -> Vec2<T> & { return m_data[1]; }
auto x0() -> T & { return m_data[0].x; }
auto y0() -> T & { return m_data[0].y; }
auto x1() -> T & { return m_data[1].x; }
auto y1() -> T & { return m_data[1].y; }
auto left() -> T &
{
if (x0() < x1()) {
return x0();
}
return x1();
}
auto right() -> T &
{
if (x0() > x1()) {
return x0();
}
return x1();
}
auto top() -> T &
{
if (y0() < y1()) {
return y0();
}
return y1();
}
auto bottom() -> T &
{
if (y0() > y1()) {
return y0();
}
return y1();
}
Box() = default;
explicit Box(Rect<T> rect)
{
this->m_data[0] = rect.pos;
this->m_data[1] = rect.pos + rect.size;
}
private:
std::array<Vec2<T>, 2> m_data = {};
};
template<typename T = int>
requires std::is_arithmetic_v<T>
auto subtract_rect(Math::Rect<T> const &src, Math::Rect<T> const &clip)
-> std::vector<Math::Rect<T>>
{
std::vector<Math::Rect<T>> 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<typename T = float>
requires std::is_arithmetic_v<T> struct Viewport {
Rect<T> rect;
Vec2<T> depth_limits;
};
template<typename T> constexpr auto deg2rad(T degrees) -> T
{
return degrees * (std::numbers::pi / 180.0);
}
} // namespace LunarWM::Math