Files
project_misth/include/utils.h
T
2026-05-21 21:56:36 +01:00

246 lines
5.6 KiB
C++

#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;
bool operator!=(const Color &other) const {
return r != other.r || g != other.g || b != other.b;
}
};
template <typename T>
struct Vec2 {
T x, y;
template <typename U>
Vec2<float> operator*(Vec2<U> s) {
return {x * s.x, y * s.y};
}
template <typename U>
Vec2<float> operator/(Vec2<U> s) {
return {x / s.x, y / s.y};
}
template <typename U>
Vec2 operator*(U s) const {
return {x * s, y * s};
}
template <typename U>
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<float> 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<float> start;
Vec2<float> end;
Line() = default;
Line(Vec2<float> start, Vec2<float> 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<float> a, Vec2<float> 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(Vec2<float> size) {
return Rect({0, 0}, size);
}
static Rect from(Vec2<float> position, Vec2<float> size) {
return Rect(position, position + size);
}
bool contains(const Vec2<float> &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<float> 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<float> edge_start = rect_points[i];
Vec2<float> 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 <typename T = void *>
struct Pool {
uint32_t size() const {
return slots.size() - free_indices.size();
}
T *operator[](uint64_t index) {
if (!is_valid(index)) {
fprintf(stderr, "Invalid pool index: %lu\n", (uint64_t)index);
return nullptr;
}
uint32_t id = (uint32_t)(index & 0xFFFFFFFFULL);
return slots[id].ptr;
}
const std::vector<T *> &all() {
static std::vector<T *> 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 = 0;
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<Slot> slots;
std::vector<uint32_t> free_indices;
};
#endif