#ifndef UTILS_H #define UTILS_H #include "pch.h" #define MIN(x, y) ((x) < (y) ? (x) : (y)) #define MAX(x, y) ((x) > (y) ? (x) : (y)) #define UNUSED(x) (void)(x) struct Color { uint8_t r, g, b = 0, a = 255; }; template struct Vec2 { T x, y; template Vec2 operator*(Vec2 s) { return {x * s.x, y * s.y}; } template Vec2 operator/(Vec2 s) { return {x / s.x, y / s.y}; } template Vec2 operator*(U s) const { return {x * s, y * s}; } template Vec2 operator/(U s) const { return {x / s, y / s}; } Vec2 operator+(const Vec2 &other) const { return {x + other.x, y + other.y}; } Vec2 operator-(const Vec2 &other) const { return {x - other.x, y - other.y}; } Vec2 operator-() const { return {-x, -y}; } T dot(const Vec2 &o) const { return x * o.x + y * o.y; } float dist(const Vec2 &other) const { float dx = other.x - x; float dy = other.y - y; return std::sqrt(dx * dx + dy * dy); } Vec2 normalized() const { float length = std::sqrt(x * x + y * y); if (length == 0) return {0, 0}; return {x / length, y / length}; } float angle_to(const Vec2 &other) const { float dx = other.x - x; float dy = other.y - y; return std::atan2(dy, dx); } }; struct Line { Vec2 start; Vec2 end; Line(Vec2 start, Vec2 end) : start(start), end(end) {} bool intersects(const Line &other) const { float denom = (other.end.y - other.start.y) * (end.x - start.x) - (other.end.x - other.start.x) * (end.y - start.y); if (std::abs(denom) < 1e-6f) // Lines are parallel (or very close to it) return false; float ua = ((other.end.x - other.start.x) * (start.y - other.start.y) - (other.end.y - other.start.y) * (start.x - other.start.x)) / denom; float ub = ((end.x - start.x) * (start.y - other.start.y) - (end.y - start.y) * (start.x - other.start.x)) / denom; return ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1; } }; struct Rect { Line diagonal; // from top-left to bottom-right Rect(Vec2 a, Vec2 b) : diagonal(a, b) { diagonal.start = { MIN(a.x, b.x), MIN(a.y, b.y) }; diagonal.end = { MAX(a.x, b.x), MAX(a.y, b.y) }; } static Rect from_size(Vec2 position, Vec2 size) { return Rect(position, position + size); } bool contains(const Vec2 &point) const { return point.x >= diagonal.start.x && point.x <= diagonal.end.x && point.y >= diagonal.start.y && point.y <= diagonal.end.y; } bool intersects(const Rect &other) const { return !(diagonal.start.x > other.diagonal.end.x || diagonal.end.x < other.diagonal.start.x || diagonal.start.y > other.diagonal.end.y || diagonal.end.y < other.diagonal.start.y); } bool intersects(const Line &line) const { if (contains(line.start) || contains(line.end)) return true; Vec2 rect_points[4] = { diagonal.start, {diagonal.end.x, diagonal.start.y}, {diagonal.start.x, diagonal.end.y}, diagonal.end }; for (int i = 0; i < 4; i++) { Vec2 edge_start = rect_points[i]; Vec2 edge_end = rect_points[(i + 1) % 4]; if (Line{edge_start, edge_end}.intersects(line)) return true; } return false; } float x() const { return diagonal.start.x; } float y() const { return diagonal.start.y; } float w() const { return diagonal.end.x - diagonal.start.x; } float h() const { return diagonal.end.y - diagonal.start.y; } }; template struct Pool { T *operator[](uint64_t index) { if (!is_valid(index)) { fprintf(stderr, "Invalid pool index: %llu\n", (unsigned long long)index); return nullptr; } uint32_t id = (uint32_t)(index & 0xFFFFFFFFULL); return slots[id].ptr; } const std::vector &all() { static std::vector all_items; all_items.clear(); for (const auto &slot : slots) if (slot.alive) all_items.push_back(slot.ptr); return all_items; } uint64_t acquire(T *item) { uint32_t id; if (!free_indices.empty()) { id = free_indices.back(); free_indices.pop_back(); } else { id = slots.size(); slots.push_back({}); } slots[id].ptr = item; slots[id].refcount = 1; slots[id].alive = true; slots[id].generation++; uint64_t index = ((uint64_t)slots[id].generation << 32) | id; return index; } void use(uint64_t index) { if (is_valid(index)) { uint64_t id = (uint32_t)(index & 0xFFFFFFFFULL); slots[id].refcount++; } } void release(uint64_t index) { if (!is_valid(index)) return; uint32_t id = (uint32_t)(index & 0xFFFFFFFFULL); auto &slot = slots[id]; slot.refcount--; if (slot.refcount <= 0) { delete slot.ptr; slot.ptr = nullptr; slot.alive = false; free_indices.push_back(id); } } bool is_valid(uint64_t index) const { uint32_t id = (uint32_t)(index & 0xFFFFFFFFULL); uint32_t gen = (uint32_t)(index >> 32); return id >= 0 && id < slots.size() && slots[id].alive && slots[id].generation == gen; } private: struct Slot { T *ptr = nullptr; int refcount = 0; bool alive = false; uint32_t generation = 0; }; std::vector slots; std::vector free_indices; }; #endif