246 lines
9.9 KiB
C++
246 lines
9.9 KiB
C++
/********************************************************************************
|
|
* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ *
|
|
* Copyright (c) 2010-2013 Daniel Chappuis *
|
|
*********************************************************************************
|
|
* *
|
|
* This software is provided 'as-is', without any express or implied warranty. *
|
|
* In no event will the authors be held liable for any damages arising from the *
|
|
* use of this software. *
|
|
* *
|
|
* Permission is granted to anyone to use this software for any purpose, *
|
|
* including commercial applications, and to alter it and redistribute it *
|
|
* freely, subject to the following restrictions: *
|
|
* *
|
|
* 1. The origin of this software must not be misrepresented; you must not claim *
|
|
* that you wrote the original software. If you use this software in a *
|
|
* product, an acknowledgment in the product documentation would be *
|
|
* appreciated but is not required. *
|
|
* *
|
|
* 2. Altered source versions must be plainly marked as such, and must not be *
|
|
* misrepresented as being the original software. *
|
|
* *
|
|
* 3. This notice may not be removed or altered from any source distribution. *
|
|
* *
|
|
********************************************************************************/
|
|
|
|
// Libraries
|
|
#include "CollisionBody.h"
|
|
#include "engine/CollisionWorld.h"
|
|
#include "engine/ContactManifold.h"
|
|
|
|
// We want to use the ReactPhysics3D namespace
|
|
using namespace reactphysics3d;
|
|
|
|
// Constructor
|
|
CollisionBody::CollisionBody(const Transform& transform, CollisionWorld& world, bodyindex id)
|
|
: Body(id), mType(DYNAMIC), mTransform(transform), mProxyCollisionShapes(NULL),
|
|
mNbCollisionShapes(0), mContactManifoldsList(NULL), mWorld(world) {
|
|
|
|
mIsCollisionEnabled = true;
|
|
mInterpolationFactor = 0.0;
|
|
|
|
// Initialize the old transform
|
|
mOldTransform = transform;
|
|
}
|
|
|
|
// Destructor
|
|
CollisionBody::~CollisionBody() {
|
|
assert(mContactManifoldsList == NULL);
|
|
|
|
// Remove all the proxy collision shapes of the body
|
|
removeAllCollisionShapes();
|
|
}
|
|
|
|
// Add a collision shape to the body.
|
|
/// This methods will create a copy of the collision shape you provided inside the world and
|
|
/// return a pointer to the actual collision shape in the world. You can use this pointer to
|
|
/// remove the collision from the body. Note that when the body is destroyed, all the collision
|
|
/// shapes will also be destroyed automatically. Because an internal copy of the collision shape
|
|
/// you provided is performed, you can delete it right after calling this method. The second
|
|
/// parameter is the transformation that transform the local-space of the collision shape into
|
|
/// the local-space of the body. By default, the second parameter is the identity transform.
|
|
/// This method will return a pointer to the proxy collision shape that links the body with
|
|
/// the collision shape you have added.
|
|
ProxyShape* CollisionBody::addCollisionShape(const CollisionShape& collisionShape,
|
|
const Transform& transform) {
|
|
|
|
// Create an internal copy of the collision shape into the world (if it does not exist yet)
|
|
CollisionShape* newCollisionShape = mWorld.createCollisionShape(collisionShape);
|
|
|
|
// Create a new proxy collision shape to attach the collision shape to the body
|
|
ProxyShape* proxyShape = new (mWorld.mMemoryAllocator.allocate(
|
|
sizeof(ProxyShape))) ProxyShape(this, newCollisionShape,
|
|
transform, decimal(1));
|
|
|
|
// Add it to the list of proxy collision shapes of the body
|
|
if (mProxyCollisionShapes == NULL) {
|
|
mProxyCollisionShapes = proxyShape;
|
|
}
|
|
else {
|
|
proxyShape->mNext = mProxyCollisionShapes;
|
|
mProxyCollisionShapes = proxyShape;
|
|
}
|
|
|
|
// Compute the world-space AABB of the new collision shape
|
|
AABB aabb;
|
|
newCollisionShape->computeAABB(aabb, mTransform * transform);
|
|
|
|
// Notify the collision detection about this new collision shape
|
|
mWorld.mCollisionDetection.addProxyCollisionShape(proxyShape, aabb);
|
|
|
|
mNbCollisionShapes++;
|
|
|
|
// Return a pointer to the collision shape
|
|
return proxyShape;
|
|
}
|
|
|
|
// Remove a collision shape from the body
|
|
void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) {
|
|
|
|
ProxyShape* current = mProxyCollisionShapes;
|
|
|
|
// If the the first proxy shape is the one to remove
|
|
if (current == proxyShape) {
|
|
mProxyCollisionShapes = current->mNext;
|
|
mWorld.mCollisionDetection.removeProxyCollisionShape(current);
|
|
mWorld.removeCollisionShape(proxyShape->mCollisionShape);
|
|
current->ProxyShape::~ProxyShape();
|
|
mWorld.mMemoryAllocator.release(current, sizeof(ProxyShape));
|
|
mNbCollisionShapes--;
|
|
return;
|
|
}
|
|
|
|
// Look for the proxy shape that contains the collision shape in parameter
|
|
while(current->mNext != NULL) {
|
|
|
|
// If we have found the collision shape to remove
|
|
if (current->mNext == proxyShape) {
|
|
|
|
// Remove the proxy collision shape
|
|
ProxyShape* elementToRemove = current->mNext;
|
|
current->mNext = elementToRemove->mNext;
|
|
mWorld.mCollisionDetection.removeProxyCollisionShape(elementToRemove);
|
|
mWorld.removeCollisionShape(proxyShape->mCollisionShape);
|
|
elementToRemove->ProxyShape::~ProxyShape();
|
|
mWorld.mMemoryAllocator.release(elementToRemove, sizeof(ProxyShape));
|
|
mNbCollisionShapes--;
|
|
return;
|
|
}
|
|
|
|
// Get the next element in the list
|
|
current = current->mNext;
|
|
}
|
|
|
|
assert(mNbCollisionShapes >= 0);
|
|
}
|
|
|
|
// Remove all the collision shapes
|
|
void CollisionBody::removeAllCollisionShapes() {
|
|
|
|
ProxyShape* current = mProxyCollisionShapes;
|
|
|
|
// Look for the proxy shape that contains the collision shape in parameter
|
|
while(current != NULL) {
|
|
|
|
// Remove the proxy collision shape
|
|
ProxyShape* nextElement = current->mNext;
|
|
mWorld.mCollisionDetection.removeProxyCollisionShape(current);
|
|
mWorld.removeCollisionShape(current->mCollisionShape);
|
|
current->ProxyShape::~ProxyShape();
|
|
mWorld.mMemoryAllocator.release(current, sizeof(ProxyShape));
|
|
|
|
// Get the next element in the list
|
|
current = nextElement;
|
|
}
|
|
|
|
mProxyCollisionShapes = NULL;
|
|
}
|
|
|
|
// Reset the contact manifold lists
|
|
void CollisionBody::resetContactManifoldsList() {
|
|
|
|
// Delete the linked list of contact manifolds of that body
|
|
ContactManifoldListElement* currentElement = mContactManifoldsList;
|
|
while (currentElement != NULL) {
|
|
ContactManifoldListElement* nextElement = currentElement->next;
|
|
|
|
// Delete the current element
|
|
currentElement->ContactManifoldListElement::~ContactManifoldListElement();
|
|
mWorld.mMemoryAllocator.release(currentElement, sizeof(ContactManifoldListElement));
|
|
|
|
currentElement = nextElement;
|
|
}
|
|
mContactManifoldsList = NULL;
|
|
}
|
|
|
|
// Update the broad-phase state for this body (because it has moved for instance)
|
|
void CollisionBody::updateBroadPhaseState() const {
|
|
|
|
// For all the proxy collision shapes of the body
|
|
for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) {
|
|
|
|
// Recompute the world-space AABB of the collision shape
|
|
AABB aabb;
|
|
shape->getCollisionShape()->computeAABB(aabb, mTransform *shape->getLocalToBodyTransform());
|
|
|
|
// Update the broad-phase state for the proxy collision shape
|
|
mWorld.mCollisionDetection.updateProxyCollisionShape(shape, aabb);
|
|
}
|
|
}
|
|
|
|
// Ask the broad-phase to test again the collision shapes of the body for collision
|
|
// (as if the body has moved).
|
|
void CollisionBody::askForBroadPhaseCollisionCheck() const {
|
|
|
|
// For all the proxy collision shapes of the body
|
|
for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) {
|
|
|
|
mWorld.mCollisionDetection.askForBroadPhaseCollisionCheck(shape);
|
|
}
|
|
}
|
|
|
|
// Return true if a point is inside the collision body
|
|
bool CollisionBody::testPointInside(const Vector3& worldPoint) const {
|
|
|
|
// For each collision shape of the body
|
|
for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) {
|
|
|
|
// Test if the point is inside the collision shape
|
|
if (shape->testPointInside(worldPoint)) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Raycast method
|
|
bool CollisionBody::raycast(const Ray& ray) {
|
|
|
|
// For each collision shape of the body
|
|
for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) {
|
|
|
|
// Test if the ray hits the collision shape
|
|
if (shape->raycast(ray)) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Raycast method with feedback information
|
|
/// The method returns the closest hit among all the collision shapes of the body
|
|
bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) {
|
|
|
|
bool isHit = false;
|
|
|
|
// For each collision shape of the body
|
|
for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) {
|
|
|
|
// Test if the ray hits the collision shape
|
|
if (shape->raycast(ray, raycastInfo, distance)) {
|
|
distance = raycastInfo.distance;
|
|
isHit = true;
|
|
}
|
|
}
|
|
|
|
return isHit;
|
|
}
|