194 lines
4.4 KiB
C++
194 lines
4.4 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))
|
|
|
|
struct Color {
|
|
uint8_t r, g, b, a;
|
|
};
|
|
|
|
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(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(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<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>
|
|
struct Pool {
|
|
T &operator[](int index) {
|
|
return items[index];
|
|
}
|
|
|
|
const std::vector<T> &all() {
|
|
return items;
|
|
}
|
|
|
|
int acquire(const T &item) {
|
|
if (!free_indices.empty()) {
|
|
int index = free_indices.back();
|
|
free_indices.pop_back();
|
|
items[index] = std::move(item);
|
|
return index;
|
|
} else {
|
|
items.push_back(std::move(item));
|
|
return items.size() - 1;
|
|
}
|
|
}
|
|
|
|
void release(int index) {
|
|
free_indices.push_back(index);
|
|
}
|
|
|
|
bool is_valid(size_t index) const {
|
|
return index >= 0 && index < items.size() && std::find(free_indices.begin(), free_indices.end(), index) == free_indices.end();
|
|
}
|
|
|
|
private:
|
|
std::vector<T> items;
|
|
std::vector<int> free_indices;
|
|
};
|
|
|
|
#endif |