/*
This file is part of Minitrem.
Minitrem is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Minitrem is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Minitrem. If not, see .
*/
template
class vec_t {
template
void load_from_args(void)
{
static_assert(index < N + 1, "too many elements in the initializer");
static_assert(index > N - 1, "too few elements in the initializer");
}
template
void load_from_args(T first, U... rest)
{
v[index] = first;
load_from_args(rest...);
}
public:
T v[N];
// Basic operations
vec_t() = default;
template
vec_t(T first, U... rest)
{
load_from_args<0>(first, rest...);
}
template
vec_t(vec_t b)
{
for (size_t i = 0; i < N; i++)
v[i] = (T)b[i];
}
T& operator[](size_t i)
{
return v[i];
}
const T& operator[](size_t i) const
{
return v[i];
}
void broadcast(T x)
{
for (size_t i = 0; i < N; i++)
v[i] = x;
}
// Comparison
friend bool operator==(const vec_t &a, const vec_t &b)
{
for (size_t i = 0; i < N; i++)
if (a[i] != b[i])
return false;
return true;
}
// Good enough for maps or sets.
friend bool operator<(const vec_t &a, const vec_t &b)
{
for (size_t i = 0; i < N; i++) {
if (a[i] < b[i])
return true;
else if (a[i] > b[i])
return false;
}
return false;
}
// Arithmetics
friend vec_t operator+(const vec_t &v)
{
return v;
}
friend vec_t operator+(const vec_t &a, const vec_t &b)
{
vec_t r;
for (size_t i = 0; i < N; i++)
r[i] = a[i] + b[i];
return r;
}
friend vec_t &operator+=(vec_t &v, const vec_t &b)
{
for (size_t i = 0; i < N; i++)
v[i] += b[i];
return v;
}
friend vec_t operator-(const vec_t &v)
{
return -1 * v;
}
friend vec_t operator-(const vec_t &a, const vec_t &b)
{
vec_t r;
for (size_t i = 0; i < N; i++)
r[i] = a[i] - b[i];
return r;
}
friend vec_t &operator-=(vec_t &v, const vec_t &b)
{
for (size_t i = 0; i < N; i++)
v[i] -= b[i];
return v;
}
friend vec_t operator^(const vec_t &a, const vec_t &b)
{
vec_t r;
for (size_t i = 0; i < N; i++)
r[i] = a[i] * b[i];
return r;
}
friend vec_t &operator^=(vec_t &v, const vec_t &b)
{
for (size_t i = 0; i < N; i++)
v[i] *= b[i];
return v;
}
friend T operator*(const vec_t &a, const vec_t &b)
{
T r = (T)0;
for (size_t i = 0; i < N; i++)
r += a[i] * b[i];
return r;
}
friend vec_t operator*(const vec_t &a, const T &b)
{
vec_t r;
for (size_t i = 0; i < N; i++)
r[i] = a[i] * b;
return r;
}
friend vec_t operator*(const T &b, const vec_t &a)
{
return a * b;
}
friend vec_t &operator*=(vec_t &v, const T &b)
{
for (size_t i = 0; i < N; i++)
v[i] *= b;
return v;
}
friend vec_t operator/(const vec_t &a, const T &b)
{
vec_t r;
for (size_t i = 0; i < N; i++)
r[i] = a[i] / b;
return r;
}
friend vec_t operator/(const T &b, const vec_t &a)
{
return a / b;
}
friend vec_t &operator/=(vec_t &v, const T &b)
{
for (size_t i = 0; i < N; i++)
v[i] /= b;
return v;
}
vec_t floor(void)
{
vec_t r;
for (size_t i = 0; i < N; i++)
r[i] = std::floor(v[i]);
return r;
}
vec_t ceil(void)
{
vec_t r;
for (size_t i = 0; i < N; i++)
r[i] = std::ceil(v[i]);
return r;
}
vec_t wrap(void)
{
return *this - this->floor();
}
T len(void)
{
return std::sqrt(*this * *this);
}
T angle(void)
{
static_assert(N == 2, "angle called for a vector that's not 2-dimensional");
return atan2(v[1], v[0]);
}
vec_t norm(void)
{
return *this / len();
}
static vec_t rad(float t)
{
return vec_t(cos(t), sin(t));
}
// Compatibility with SFML
template
operator sf::Vector2() const
{
static_assert(N == 2, "conversion of vec_t with N != 2 to sf::Vector2");
return sf::Vector2((U)v[0], (U)v[1]);
}
template
operator sf::Vector3() const
{
static_assert(N == 3, "conversion of vec_t with N != 3 to sf::Vector3");
return sf::Vector3((U)v[0], (U)v[1], (U)v[2]);
}
template
vec_t(sf::Vector2 b)
{
static_assert(N == 2, "conversion of sf::Vector2 to vec_t with N != 2");
v[0] = b.x;
v[1] = b.y;
}
template
vec_t(sf::Vector3 b)
{
static_assert(N == 3, "conversion of sf::Vector2 to vec_t with N != 3");
v[0] = b.x;
v[1] = b.y;
v[2] = b.z;
}
// Compatibility with iostream
friend std::ostream& operator<<(std::ostream& stream, vec_t v)
{
stream << "(";
for (size_t i = 0; i < N; i++) {
if (i)
stream << ", ";
stream << v.v[i];
}
stream << ")";
return stream;
}
};
template
class rect_t {
public:
vec_t v[2];
rect_t() = default;
rect_t(vec_t a, vec_t b)
{
v[0] = a;
v[1] = b;
}
vec_t& operator[](size_t i)
{
return v[i];
}
const vec_t& operator[](size_t i) const
{
return v[i];
}
vec_t dims(void) const
{
return v[1] - v[0];
}
T dim(size_t i) const
{
return v[1][i] - v[0][i];
}
T dim_min(void) const
{
T min = INFINITY;
for (size_t i = 0; i < N; i++)
if (dim(i) < min)
min = dim(i);
return min;
}
T area(void) const
{
T area = 1;
for (size_t i = 0; i < N; i++)
area *= dim(i);
return area;
}
rect_t norm(void) const
{
rect_t r;
for (size_t i = 0; i < N; i++) {
r[0][i] = std::min(v[0][i], v[1][i]);
r[1][i] = std::max(v[0][i], v[1][i]);
}
return r;
}
vec_t center(void) const
{
return v[0] / 2 + v[1] / 2;
}
bool contains(vec_t &u) const
{
for (size_t i = 0; i < N; i++)
if (u[i] < v[0][i] || u[i] > v[1][i])
return false;
return true;
}
static rect_t around(vec_t v, T r)
{
vec_t R(r, r);
return rect_t(v - R, v + R);
}
friend bool operator&&(const rect_t &a, const rect_t &b)
{
for (size_t i = 0; i < N; i++)
if (a[1][i] < b[0][i] || a[0][i] > b[1][i])
return false;
return true;
}
friend rect_t operator|(const rect_t &a, const rect_t &b)
{
rect_t r;
r[0][0] = std::min(a[0][0], b[0][0]);
r[0][1] = std::min(a[0][1], b[0][1]);
r[1][0] = std::max(a[1][0], b[1][0]);
r[1][1] = std::max(a[1][1], b[1][1]);
return r;
}
friend rect_t operator+(const rect_t &a, const vec_t &b)
{
rect_t r;
r[0] = a[0] + b;
r[1] = a[1] + b;
return r;
}
friend std::ostream& operator<<(std::ostream& stream, rect_t r)
{
stream << "(" << r[0] << " x " << r[1] << ")";
return stream;
}
// Compatibility with SFML
rect_t(sf::FloatRect b)
{
static_assert(N == 2, "conversion of sf::FloatRect to rect_t with N != 2");
v[0][0] = b.left;
v[0][1] = b.top;
v[1][0] = b.left + b.width;
v[1][1] = b.top + b.height;
}
};
// Shorthands
typedef vec_t v2f_t;
typedef vec_t v3f_t;
typedef rect_t rectf_t;