194 lines
7.8 KiB
C++
194 lines
7.8 KiB
C++
/**
|
|
This file is a part of our_dick
|
|
Copyright (C) 2020 rexy712
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef OUR_DICK_ENGINE_COLLISION_HPP
|
|
#define OUR_DICK_ENGINE_COLLISION_HPP
|
|
|
|
#include "base_types.hpp"
|
|
|
|
namespace egn{
|
|
|
|
//How far away before a collision is considered to have occurred
|
|
static constexpr float default_collision_epsilon = 1.0e-10f;
|
|
|
|
class collidable_visitor;
|
|
|
|
//Anything which derives from this is considered collidable and must be comparible to any other collidable
|
|
class collidable_iface
|
|
{
|
|
public:
|
|
//Check if this and the other collidable have collided
|
|
virtual bool check_collision(const collidable_iface& c, float epsilon)const = 0;
|
|
virtual void accept_visitor(collidable_visitor& v)const = 0;
|
|
};
|
|
|
|
//CRTP collidable to allow the collision checks to determine the concrete type of the collidable
|
|
template<typename Derived>
|
|
class collidable : public collidable_iface
|
|
{
|
|
public:
|
|
bool check_collision(const collidable_iface& c, float epsilon = default_collision_epsilon)const override final;
|
|
private:
|
|
void accept_visitor(collidable_visitor& v)const override final;
|
|
};
|
|
|
|
|
|
namespace collision{
|
|
|
|
//Basic collidable objects
|
|
|
|
//A 1D point
|
|
class point : public egn::point, public collidable<point>
|
|
{
|
|
public:
|
|
using egn::point::point;
|
|
using egn::point::operator=;
|
|
};
|
|
|
|
//A 2D line
|
|
class line_segment : public egn::line_segment, public collidable<line_segment>{};
|
|
|
|
//A 2D rectangle
|
|
class rectangle : public egn::rectangle, public collidable<rectangle>{};
|
|
|
|
//A 3D bounding box
|
|
class aabb : public egn::aabb, public collidable<aabb>
|
|
{
|
|
public:
|
|
using egn::aabb::aabb;
|
|
using egn::aabb::operator=;
|
|
aabb(const egn::aabb& b);
|
|
aabb& operator=(const egn::aabb& b);
|
|
};
|
|
|
|
//A 3D sphere
|
|
class sphere : public egn::sphere, public collidable<sphere>
|
|
{
|
|
public:
|
|
using egn::sphere::sphere;
|
|
using egn::sphere::operator=;
|
|
sphere(const egn::sphere& b);
|
|
sphere& operator=(const egn::sphere& b);
|
|
};
|
|
|
|
}
|
|
|
|
//base class for collision visitor to provide polymorphic access to visitation functions
|
|
class collidable_visitor
|
|
{
|
|
public:
|
|
virtual void visit(const collision::aabb& a) = 0;
|
|
virtual void visit(const collision::sphere& a) = 0;
|
|
virtual void visit(const collision::line_segment& a) = 0;
|
|
virtual void visit(const collision::rectangle& a) = 0;
|
|
virtual void visit(const collision::point& p) = 0;
|
|
};
|
|
|
|
//Templated visitor to allow checking collision from polymorphic types
|
|
template<typename T>
|
|
class collision_visitor : public collidable_visitor
|
|
{
|
|
private:
|
|
const T& m_l;
|
|
float m_epsilon;
|
|
bool m_result = false;
|
|
public:
|
|
constexpr explicit collision_visitor(const T& l, float epsilon);
|
|
void visit(const collision::aabb& a)override;
|
|
void visit(const collision::sphere& a)override;
|
|
void visit(const collision::line_segment& a)override;
|
|
void visit(const collision::rectangle& a)override;
|
|
void visit(const collision::point& p)override;
|
|
constexpr bool result()const;
|
|
};
|
|
|
|
//Concrete collision detection that is eventually called
|
|
//bool check_collision(const collidable_iface& l, const collidable_iface& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const aabb& l, const aabb& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const aabb& l, const sphere& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const aabb& l, const line_segment& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const aabb& l, const rectangle& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const aabb& l, const point& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const sphere& l, const sphere& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const sphere& l, const aabb& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const sphere& l, const line_segment& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const sphere& l, const rectangle& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const sphere& l, const point& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const line_segment& l, const line_segment& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const line_segment& l, const aabb& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const line_segment& l, const sphere& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const line_segment& l, const rectangle& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const line_segment& l, const point& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const rectangle& l, const rectangle& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const rectangle& l, const aabb& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const rectangle& l, const sphere& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const rectangle& l, const line_segment& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const rectangle& l, const point& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const point& l, const point& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const point& l, const aabb& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const point& l, const sphere& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const point& l, const line_segment& r, float epsilon = default_collision_epsilon);
|
|
bool check_collision(const point& l, const rectangle& r, float epsilon = default_collision_epsilon);
|
|
|
|
|
|
//Check collision between this and c via a visitor
|
|
template<typename Derived>
|
|
bool collidable<Derived>::check_collision(const collidable_iface& c, float epsilon)const{
|
|
collision_visitor<Derived> vis(static_cast<const Derived&>(*this), epsilon); //Determine our true type for visitor
|
|
c.accept_visitor(vis); //have c give its true type to our visitor and check for collision
|
|
return vis.result();
|
|
}
|
|
template<typename Derived>
|
|
void collidable<Derived>::accept_visitor(collidable_visitor& v)const{
|
|
v.visit(static_cast<const Derived&>(*this)); //Give the visitor our true type to allow calling correct collision check function
|
|
}
|
|
|
|
template<typename T>
|
|
constexpr collision_visitor<T>::collision_visitor(const T& l, float epsilon):
|
|
m_l(l),
|
|
m_epsilon(epsilon){}
|
|
//Call correct concrete function for given collision
|
|
template<typename T>
|
|
void collision_visitor<T>::visit(const collision::aabb& a){
|
|
m_result = check_collision(m_l, a, m_epsilon);
|
|
}
|
|
template<typename T>
|
|
void collision_visitor<T>::visit(const collision::sphere& a){
|
|
m_result = check_collision(m_l, a, m_epsilon);
|
|
}
|
|
template<typename T>
|
|
void collision_visitor<T>::visit(const collision::line_segment& a){
|
|
m_result = check_collision(m_l, a, m_epsilon);
|
|
}
|
|
template<typename T>
|
|
void collision_visitor<T>::visit(const collision::rectangle& a){
|
|
m_result = check_collision(m_l, a, m_epsilon);
|
|
}
|
|
template<typename T>
|
|
void collision_visitor<T>::visit(const collision::point& a){
|
|
m_result = check_collision(m_l, a, m_epsilon);
|
|
}
|
|
template<typename T>
|
|
constexpr bool collision_visitor<T>::result()const{
|
|
return m_result;
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|