/* 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;