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