ephysics/ephysics/body/CollisionBody.cpp

221 lines
7.0 KiB
C++

/** @file
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
* @author Daniel CHAPPUIS
* @author Edouard DUPIN
* @copyright 2010-2016, Daniel Chappuis
* @copyright 2017, Edouard DUPIN
* @license MPL v2.0 (see license file)
*/
#include <ephysics/body/CollisionBody.hpp>
#include <ephysics/engine/CollisionWorld.hpp>
#include <ephysics/collision/ContactManifold.hpp>
// We want to use the ReactPhysics3D namespace
using namespace ephysics;
CollisionBody::CollisionBody(const etk::Transform3D& _transform, CollisionWorld& _world, bodyindex _id):
Body(_id),
m_type(DYNAMIC),
m_transform(_transform),
m_proxyCollisionShapes(null),
m_numberCollisionShapes(0),
m_contactManifoldsList(null),
m_world(_world) {
}
CollisionBody::~CollisionBody() {
assert(m_contactManifoldsList == null);
// Remove all the proxy collision shapes of the body
removeAllCollisionShapes();
}
inline void CollisionBody::setType(BodyType _type) {
m_type = _type;
if (m_type == STATIC) {
// Update the broad-phase state of the body
updateBroadPhaseState();
}
}
ProxyShape* CollisionBody::addCollisionShape(CollisionShape* _collisionShape,
const etk::Transform3D& _transform) {
// Create a proxy collision shape to attach the collision shape to the body
ProxyShape* proxyShape = ETK_NEW(ProxyShape, this, _collisionShape,_transform, float(1));
// Add it to the list of proxy collision shapes of the body
if (m_proxyCollisionShapes == null) {
m_proxyCollisionShapes = proxyShape;
} else {
proxyShape->m_next = m_proxyCollisionShapes;
m_proxyCollisionShapes = proxyShape;
}
AABB aabb;
_collisionShape->computeAABB(aabb, m_transform * _transform);
m_world.m_collisionDetection.addProxyCollisionShape(proxyShape, aabb);
m_numberCollisionShapes++;
return proxyShape;
}
void CollisionBody::removeCollisionShape(const ProxyShape* _proxyShape) {
ProxyShape* current = m_proxyCollisionShapes;
// If the the first proxy shape is the one to remove
if (current == _proxyShape) {
m_proxyCollisionShapes = current->m_next;
if (m_isActive) {
m_world.m_collisionDetection.removeProxyCollisionShape(current);
}
ETK_DELETE(ProxyShape, current);
current = null;
m_numberCollisionShapes--;
return;
}
// Look for the proxy shape that contains the collision shape in parameter
while(current->m_next != null) {
// If we have found the collision shape to remove
if (current->m_next == _proxyShape) {
// Remove the proxy collision shape
ProxyShape* elementToRemove = current->m_next;
current->m_next = elementToRemove->m_next;
if (m_isActive) {
m_world.m_collisionDetection.removeProxyCollisionShape(elementToRemove);
}
ETK_DELETE(ProxyShape, elementToRemove);
elementToRemove = null;
m_numberCollisionShapes--;
return;
}
// Get the next element in the list
current = current->m_next;
}
}
void CollisionBody::removeAllCollisionShapes() {
ProxyShape* current = m_proxyCollisionShapes;
// Look for the proxy shape that contains the collision shape in parameter
while(current != null) {
// Remove the proxy collision shape
ProxyShape* nextElement = current->m_next;
if (m_isActive) {
m_world.m_collisionDetection.removeProxyCollisionShape(current);
}
ETK_DELETE(ProxyShape, current);
// Get the next element in the list
current = nextElement;
}
m_proxyCollisionShapes = null;
}
void CollisionBody::resetContactManifoldsList() {
// Delete the linked list of contact manifolds of that body
ContactManifoldListElement* currentElement = m_contactManifoldsList;
while (currentElement != null) {
ContactManifoldListElement* nextElement = currentElement->next;
// Delete the current element
ETK_DELETE(ContactManifoldListElement, currentElement);
currentElement = nextElement;
}
m_contactManifoldsList = null;
}
void CollisionBody::updateBroadPhaseState() const {
// For all the proxy collision shapes of the body
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
// Update the proxy
updateProxyShapeInBroadPhase(shape);
}
}
void CollisionBody::updateProxyShapeInBroadPhase(ProxyShape* _proxyShape, bool _forceReinsert) const {
AABB aabb;
_proxyShape->getCollisionShape()->computeAABB(aabb, m_transform * _proxyShape->getLocalToBodyTransform());
m_world.m_collisionDetection.updateProxyCollisionShape(_proxyShape, aabb, vec3(0, 0, 0), _forceReinsert);
}
void CollisionBody::setIsActive(bool _isActive) {
// If the state does not change
if (m_isActive == _isActive) {
return;
}
Body::setIsActive(_isActive);
// If we have to activate the body
if (_isActive == true) {
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
AABB aabb;
shape->getCollisionShape()->computeAABB(aabb, m_transform * shape->m_localToBodyTransform);
m_world.m_collisionDetection.addProxyCollisionShape(shape, aabb);
}
} else {
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
m_world.m_collisionDetection.removeProxyCollisionShape(shape);
}
resetContactManifoldsList();
}
}
void CollisionBody::askForBroadPhaseCollisionCheck() const {
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
m_world.m_collisionDetection.askForBroadPhaseCollisionCheck(shape);
}
}
int32_t CollisionBody::resetIsAlreadyInIslandAndCountManifolds() {
m_isAlreadyInIsland = false;
int32_t nbManifolds = 0;
// Reset the m_isAlreadyInIsland variable of the contact manifolds for this body
ContactManifoldListElement* currentElement = m_contactManifoldsList;
while (currentElement != null) {
currentElement->contactManifold->m_isAlreadyInIsland = false;
currentElement = currentElement->next;
nbManifolds++;
}
return nbManifolds;
}
bool CollisionBody::testPointInside(const vec3& _worldPoint) const {
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
if (shape->testPointInside(_worldPoint)) return true;
}
return false;
}
bool CollisionBody::raycast(const Ray& _ray, RaycastInfo& _raycastInfo) {
if (m_isActive == false) {
return false;
}
bool isHit = false;
Ray rayTemp(_ray);
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
// Test if the ray hits the collision shape
if (shape->raycast(rayTemp, _raycastInfo)) {
rayTemp.maxFraction = _raycastInfo.hitFraction;
isHit = true;
}
}
return isHit;
}
AABB CollisionBody::getAABB() const {
AABB bodyAABB;
if (m_proxyCollisionShapes == null) {
return bodyAABB;
}
m_proxyCollisionShapes->getCollisionShape()->computeAABB(bodyAABB, m_transform * m_proxyCollisionShapes->getLocalToBodyTransform());
for (ProxyShape* shape = m_proxyCollisionShapes->m_next; shape != null; shape = shape->m_next) {
AABB aabb;
shape->getCollisionShape()->computeAABB(aabb, m_transform * shape->getLocalToBodyTransform());
bodyAABB.mergeWithAABB(aabb);
}
return bodyAABB;
}