diff --git a/cpp/src/entities.cpp b/cpp/src/entities.cpp index e3e0f50..b8f78b8 100644 --- a/cpp/src/entities.cpp +++ b/cpp/src/entities.cpp @@ -5,6 +5,7 @@ #include "log.hpp" #include "math.hpp" #include "sprite.hpp" +#include "coorginates.hpp" Entity::Entity(WorldPos position) : m_Position(position) { LOG_DEBUG("spawning entity at position ", position); @@ -25,13 +26,13 @@ void Entity::ZeroActualVelocityInDirection(WorldPos direction) { // where e1 is formed by the direction where we want to zero-out // the velocity, and e2 is the orthogonal vector. // Scalars q1, q2 are coordinates for e1, e2 basis. - WorldPos e1 = direction.normalized(); - WorldPos e2 = e1.orthogonal(); + WorldPos e1 = direction.GetNormalized(); + WorldPos e2 = e1.GetOrthogonal(); // q1 * e1 + q2 * e2 = v, from this follows: auto &v = GetActualVelocity(); - float q2 = (v.y * e1.x - v.x * e1.y) / (e2.y * e1.x - e2.x * e1.y); - float q1 = (v.x - q2 * e2.x) / e1.x; + float q2 = (v.y() * e1.x() - v.x() * e1.y()) / (e2.y() * e1.x() - e2.x() * e1.y()); + float q1 = (v.x() - q2 * e2.x()) / e1.x(); // We then zero-out the q1, but only if it's positive - meaning // it is aiming in the direction of "direction", not out. diff --git a/cpp/src/math.hpp b/cpp/src/math.hpp index 4f148c5..01e900e 100644 --- a/cpp/src/math.hpp +++ b/cpp/src/math.hpp @@ -1,21 +1,19 @@ #pragma once +#include #include #include #include #include #include -#include -#include -#include #include - +#include +#include template -requires std::floating_point -static inline bool equalEpsilon(const T& a, const T& b) -{ - constexpr auto epsilon = [](){ + requires std::floating_point +static inline bool equalEpsilon(const T &a, const T &b) { + constexpr auto epsilon = []() { if constexpr (std::is_same_v) { return T{1e-5}; } else { @@ -29,46 +27,41 @@ static inline bool equalEpsilon(const T& a, const T& b) return std::abs(a - b) < epsilon; } +struct Any {}; -template -class vec { +template class vec { public: vec() : m_Array{} {} template - requires (std::same_as && ...) && (sizeof...(ArgsT) == N) + requires(std::same_as && ...) && (sizeof...(ArgsT) == N) vec(ArgsT... args) : m_Array{args...} {} - const T& operator[](size_t index) const - { + const T &operator[](size_t index) const { // we leave run-time checks to the underlying std::array return m_Array[index]; } - T& operator[](size_t index) - { + T &operator[](size_t index) { // we leave run-time checks to the underlying std::array return m_Array[index]; } - friend std::ostream &operator<<(std::ostream &os, const vec &obj) - { + friend std::ostream &operator<<(std::ostream &os, const vec &obj) { os << "( "; - for (const auto& element : obj.m_Array) { + for (const auto &element : obj.m_Array) { os << element << " "; } os << ")"; return os; } - // // binary operators // - friend bool operator==(const vec& a, const vec& b) - { - for (const auto& [u, v] : std::views::zip(a.m_Array,b.m_Array)) { + friend bool operator==(const vec &a, const vec &b) { + for (const auto &[u, v] : std::views::zip(a.m_Array, b.m_Array)) { if (!equalEpsilon(u, v)) { return false; } @@ -76,113 +69,96 @@ public: return true; } - friend bool operator!=(const vec& a, const vec& b) - { - return !(a == b); - } + friend bool operator!=(const vec &a, const vec &b) { return !(a == b); } - friend vec operator+(const vec& a, const vec& b) - { - vec c; - std::ranges::transform(a.m_Array, b.m_Array, c.m_Array.begin(), std::plus{}); + friend vec operator+(const vec &a, const vec &b) { + vec c; + std::ranges::transform(a.m_Array, b.m_Array, c.m_Array.begin(), + std::plus{}); return c; } - friend vec operator-(const vec& a, const vec& b) - { - vec c; - std::ranges::transform(a.m_Array, b.m_Array, c.m_Array.begin(), std::minus{}); + friend vec operator-(const vec &a, const vec &b) { + vec c; + std::ranges::transform(a.m_Array, b.m_Array, c.m_Array.begin(), + std::minus{}); return c; } - friend vec operator*(const vec& a, const T& scalar) - { - vec c; - std::ranges::transform(a.m_Array, std::views::repeat(scalar), c.m_Array.begin(), std::multiplies{}); + friend vec operator*(const vec &a, const T &scalar) { + vec c; + std::ranges::transform(a.m_Array, std::views::repeat(scalar), + c.m_Array.begin(), std::multiplies{}); return c; } - friend vec operator*(const T& scalar, const vec& a) { - return a * scalar; - } + friend vec operator*(const T &scalar, const vec &a) { return a * scalar; } - friend vec operator/(const vec& a, const T& scalar) - { - vec c; - std::ranges::transform(a.m_Array, std::views::repeat(scalar), c.m_Array.begin(), std::divides{}); + friend vec operator/(const vec &a, const T &scalar) { + vec c; + std::ranges::transform(a.m_Array, std::views::repeat(scalar), + c.m_Array.begin(), std::divides{}); return c; } // // compound-assignment operators // - - vec& operator+=(const vec& b) - { - vec& a = *this; - std::ranges::transform(a.m_Array, b.m_Array, a.m_Array.begin(), std::plus{}); + + vec &operator+=(const vec &b) { + vec &a = *this; + std::ranges::transform(a.m_Array, b.m_Array, a.m_Array.begin(), + std::plus{}); return a; } - vec& operator-=(const vec& b) - { - vec& a = *this; - std::ranges::transform(a.m_Array, b.m_Array, a.m_Array.begin(), std::minus{}); + vec &operator-=(const vec &b) { + vec &a = *this; + std::ranges::transform(a.m_Array, b.m_Array, a.m_Array.begin(), + std::minus{}); return a; } - // // Utility functions // - T LengthSquared() const - { - return std::transform_reduce( - m_Array.begin(), m_Array.end(), - T{0.0}, - std::plus{}, - [](T x){ - return x*x; - } - ); + T LengthSquared() const { + return std::transform_reduce(m_Array.begin(), m_Array.end(), T{0.0}, + std::plus{}, [](T x) { return x * x; }); } - T Length() const - { - return std::sqrt(LengthSquared()); - } + T Length() const { return std::sqrt(LengthSquared()); } - T DistanceTo(const vec& b) const { - const vec& a = *this; + T DistanceTo(const vec &b) const { + const vec &a = *this; return (a - b).Length(); - } + } // // In-place vector operations // - void Normalize() - { + void Normalize() { T length = Length(); if (equalEpsilon(length, T{0})) - return; - std::ranges::transform(m_Array, std::views::repeat(length), m_Array.begin(), std::divides{}); + return; + std::ranges::transform(m_Array, std::views::repeat(length), m_Array.begin(), + std::divides{}); } - // // Methods returning new object // - - vec GetNormalized() const - { + + vec GetNormalized() const { vec tmp = *this; tmp.Normalize(); return tmp; } - vec GetOrthogonal() const requires (N == 2) + vec GetOrthogonal() const + requires(N == 2) { vec tmp = *this; @@ -192,15 +168,53 @@ public: return tmp; } -// const T& x = m_Array[0]; -// const T& y = m_Array[1]; -// const T& z = m_Array[2]; + // + // Helpers + // + const T &x() const + requires(N >= 1) + { + return m_Array[0]; + } + + T &x() + requires(N >= 1) + { + return m_Array[0]; + } + + const T &y() const + requires(N >= 2) + { + return m_Array[1]; + } + + T &y() + requires(N >= 2) + { + return m_Array[1]; + } + + const T &z() const + requires(N >= 3) + { + return m_Array[2]; + } + + T &z() + requires(N >= 3) + { + return m_Array[2]; + } private: - std::array m_Array; + std::array m_Array; }; +// +// Aliases +// using vec2 = vec; using vec3 = vec; @@ -215,138 +229,143 @@ using uvec2 = vec; using uvec3 = vec; using uvec4 = vec; -constexpr double EQUALITY_LIMIT = 1e-6; +// tags for differentiating between domains +struct WorldTag {}; +struct WindowTag {}; +struct TileTag {}; -#ifdef _WIN32 -#include -#define M_PI std::numbers::pi -#endif +// types for each domain +using WorldPos = vec; +using WindowPos = vec; +using TilePos = vec; -template struct Vec2D { -public: - Vec2D() = default; - ~Vec2D() = default; - - template - Vec2D(Vec2D other) { - this->x = static_cast(other.x); - this->y = static_cast(other.y); - } - - Vec2D& operator+=(const Vec2D &other) { - x += other.x; - y += other.y; - return *this; - } - - template - requires std::is_arithmetic_v - Vec2D& operator/=(U k) { - this->x /= static_cast(k); - this->y /= static_cast(k); - return *this; - } - - friend Vec2D operator+(const Vec2D &a, const Vec2D &b) { - return Vec2D{a.x + b.x, a.y + b.y}; - } - - friend Vec2D operator-(const Vec2D &a, const Vec2D &b) { - return Vec2D{a.x - b.x, a.y - b.y}; - } - - template - requires std::is_arithmetic_v - friend Vec2D operator*(U k, const Vec2D &v) - { - return Vec2D{k * v.x, k * v.y}; - } - - template - requires std::is_arithmetic_v - friend Vec2D operator/(const Vec2D &v, U k) - { - return Vec2D{v.x / k, v.y / k}; - } - - friend bool operator==(const Vec2D &a, const Vec2D &b) { - if constexpr (std::is_integral_v) { - return a.x == b.x && a.y == b.y; - } else if constexpr (std::is_floating_point_v) { - return a.distance(b) < EQUALITY_LIMIT; - } else { - static_assert("Unhandled comparison"); - } - } - - Vec2D operator*(float b) const { return Vec2D{b * x, b * y}; } - - T distance_squared(const Vec2D &other) const { - T dx = x - other.x; - T dy = y - other.y; - return dx * dx + dy * dy; - } - - T distance(const Vec2D &other) const - requires std::floating_point - { - return sqrt(distance_squared(other)); - } - - void normalize() - requires std::floating_point - { - auto length = sqrt(x * x + y * y); - if (length < EQUALITY_LIMIT) { - x = y = 0; - } else { - x /= length; - y /= length; - } - } - - Vec2D normalized() - requires std::floating_point - { - Vec2D v(*this); - v.normalize(); - return v; - } - - Vec2D orthogonal() const - { - Vec2D v(*this); - - std::swap(v.x, v.y); - v.x = -v.x; - return v; - } - - template Vec2D(std::initializer_list list) { - assert(list.size() == 2); - auto first_element = *list.begin(); - auto second_element = *(list.begin() + 1); - x = static_cast(first_element); - y = static_cast(second_element); - } - - T x, y; - - friend std::ostream &operator<<(std::ostream &os, const Vec2D &obj) { - os << "( " << obj.x << ", " << obj.y << ")"; - return os; - } -}; - -using TilePos = Vec2D; -using WorldPos = Vec2D; -using WindowPos = Vec2D; +// +// Utils +// struct TilePosHash { - std::size_t operator()(const TilePos& p) const noexcept { - std::size_t h1 = std::hash{}(p.x); - std::size_t h2 = std::hash{}(p.y); - return h1 ^ (h2 + 0x9e3779b9 + (h1<<6) + (h1>>2)); - } + std::size_t operator()(const TilePos &p) const noexcept { + std::size_t h1 = std::hash{}(p.x()); + std::size_t h2 = std::hash{}(p.y()); + return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2)); + } }; +// old stuff - TODO delete + +// constexpr double EQUALITY_LIMIT = 1e-6; +// template struct Vec2D { +// public: +// Vec2D() = default; +// ~Vec2D() = default; +// +// template +// Vec2D(Vec2D other) { +// this->x = static_cast(other.x); +// this->y = static_cast(other.y); +// } +// +// Vec2D& operator+=(const Vec2D &other) { +// x += other.x; +// y += other.y; +// return *this; +// } +// +// template +// requires std::is_arithmetic_v +// Vec2D& operator/=(U k) { +// this->x /= static_cast(k); +// this->y /= static_cast(k); +// return *this; +// } +// +// friend Vec2D operator+(const Vec2D &a, const Vec2D &b) { +// return Vec2D{a.x + b.x, a.y + b.y}; +// } +// +// friend Vec2D operator-(const Vec2D &a, const Vec2D &b) { +// return Vec2D{a.x - b.x, a.y - b.y}; +// } +// +// template +// requires std::is_arithmetic_v +// friend Vec2D operator*(U k, const Vec2D &v) +// { +// return Vec2D{k * v.x, k * v.y}; +// } +// +// template +// requires std::is_arithmetic_v +// friend Vec2D operator/(const Vec2D &v, U k) +// { +// return Vec2D{v.x / k, v.y / k}; +// } +// +// friend bool operator==(const Vec2D &a, const Vec2D &b) { +// if constexpr (std::is_integral_v) { +// return a.x == b.x && a.y == b.y; +// } else if constexpr (std::is_floating_point_v) { +// return a.distance(b) < EQUALITY_LIMIT; +// } else { +// static_assert("Unhandled comparison"); +// } +// } +// +// Vec2D operator*(float b) const { return Vec2D{b * x, b * y}; } +// +// T distance_squared(const Vec2D &other) const { +// T dx = x - other.x; +// T dy = y - other.y; +// return dx * dx + dy * dy; +// } +// +// T distance(const Vec2D &other) const +// requires std::floating_point +// { +// return sqrt(distance_squared(other)); +// } +// +// void normalize() +// requires std::floating_point +// { +// auto length = sqrt(x * x + y * y); +// if (length < EQUALITY_LIMIT) { +// x = y = 0; +// } else { +// x /= length; +// y /= length; +// } +// } +// +// Vec2D normalized() +// requires std::floating_point +// { +// Vec2D v(*this); +// v.normalize(); +// return v; +// } +// +// Vec2D orthogonal() const +// { +// Vec2D v(*this); +// +// std::swap(v.x, v.y); +// v.x = -v.x; +// return v; +// } +// +// template Vec2D(std::initializer_list list) { +// assert(list.size() == 2); +// auto first_element = *list.begin(); +// auto second_element = *(list.begin() + 1); +// x = static_cast(first_element); +// y = static_cast(second_element); +// } +// +// T x, y; +// +// friend std::ostream &operator<<(std::ostream &os, const Vec2D &obj) { +// os << "( " << obj.x << ", " << obj.y << ")"; +// return os; +// } +// };