#pragma once /* * Copyright (C) 2024 Brett Terpstra * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 this program. If not, see . */ #ifndef BLT_MATH_AABB_H #define BLT_MATH_AABB_H #include #include #include namespace blt { // yes I could use the vector (see tower defense game commit log for this) // this feels nicer template class axis_t { public: axis_t(const T min, const T max): m_min(min), m_max(max) {} [[nodiscard]] bool intersects(const T p) const { return p >= m_min && p <= m_max; } template [[nodiscard]] bool intersects(const axis_t& other) const { return static_cast(other.m_min) <= m_max && static_cast(other.m_max) >= m_min; } [[nodiscard]] T min() const { return m_min; } [[nodiscard]] T max() const { return m_max; } [[nodiscard]] T length() const { return m_max - m_min; } private: T m_min, m_max; }; namespace detail { template class axis_aligned_bounding_box_base_t { public: [[nodiscard]] vec get_center() const { vec min; for (u32 i = 0; i < Axis; i++) min[i] = m_axes[i].min(); const auto center = get_size() / 2.0f; return min + center; } [[nodiscard]] vec get_size() const { vec size; for (u32 i = 0; i < Axis; i++) size[i] = m_axes[i].length(); return size; } template [[nodiscard]] bool intersects(const axis_aligned_bounding_box_base_t& other) const { for (u32 i = 0; i < Axis; i++) if (!m_axes[i].intersects(other.m_axes[i])) return false; return true; } template [[nodiscard]] bool intersects(const vec& point) const { for (u32 i = 0; i < Axis; i++) if (!m_axes[i].intersects(point[i])) return false; return true; } axis_t& operator[](u32 i) { return m_axes[i]; } axis_t& axis(u32 i) { if (i >= Axis) throw std::out_of_range("Axis index out of range"); return m_axes[i]; } protected: std::array, Axis> m_axes; }; } template class axis_aligned_bounding_box_t : public detail::axis_aligned_bounding_box_base_t { public: using detail::axis_aligned_bounding_box_base_t::axis_aligned_bounding_box_base_t; }; template class axis_aligned_bounding_box_t<2, T> : public detail::axis_aligned_bounding_box_base_t<2, T> { public: using detail::axis_aligned_bounding_box_base_t<2, T>::axis_aligned_bounding_box_base_t; [[nodiscard]] vec2 min() const { return {this->m_axes[0].min(), this->m_axes[1].min()}; } [[nodiscard]] vec2 max() const { return {this->m_axes[0].max(), this->m_axes[1].max()}; } }; template class axis_aligned_bounding_box_t<3, T> : public detail::axis_aligned_bounding_box_base_t<3, T> { public: using detail::axis_aligned_bounding_box_base_t<2, T>::axis_aligned_bounding_box_base_t; [[nodiscard]] vec3 min() const { return {this->m_axes[0].min(), this->m_axes[1].min(), this->m_axes[2].min()}; } [[nodiscard]] vec3s max() const { return {this->m_axes[0].max(), this->m_axes[1].max(), this->m_axes[2].max()}; } }; using aabb_2d_t = axis_aligned_bounding_box_t<2, float>; using aabb_3d_t = axis_aligned_bounding_box_t<3, float>; } #endif //BLT_MATH_AABB_H