summaryrefslogtreecommitdiff
path: root/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp')
-rw-r--r--thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp1666
1 files changed, 1666 insertions, 0 deletions
diff --git a/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
new file mode 100644
index 0000000000..c3e912fdca
--- /dev/null
+++ b/thirdparty/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
@@ -0,0 +1,1666 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
+
+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.
+*/
+
+#include "btCollisionWorld.h"
+#include "btCollisionDispatcher.h"
+#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
+#include "BulletCollision/CollisionShapes/btCollisionShape.h"
+#include "BulletCollision/CollisionShapes/btConvexShape.h"
+#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h"
+#include "BulletCollision/CollisionShapes/btSphereShape.h" //for raycasting
+#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" //for raycasting
+#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" //for raycasting
+#include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h"
+#include "BulletCollision/CollisionShapes/btCompoundShape.h"
+#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h"
+#include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h"
+#include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h"
+#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
+#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
+#include "BulletCollision/BroadphaseCollision/btDbvt.h"
+#include "LinearMath/btAabbUtil2.h"
+#include "LinearMath/btQuickprof.h"
+#include "LinearMath/btSerializer.h"
+#include "BulletCollision/CollisionShapes/btConvexPolyhedron.h"
+#include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h"
+
+//#define DISABLE_DBVT_COMPOUNDSHAPE_RAYCAST_ACCELERATION
+
+
+//#define USE_BRUTEFORCE_RAYBROADPHASE 1
+//RECALCULATE_AABB is slower, but benefit is that you don't need to call 'stepSimulation' or 'updateAabbs' before using a rayTest
+//#define RECALCULATE_AABB_RAYCAST 1
+
+//When the user doesn't provide dispatcher or broadphase, create basic versions (and delete them in destructor)
+#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
+#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h"
+#include "BulletCollision/CollisionDispatch/btCollisionConfiguration.h"
+
+
+///for debug drawing
+
+//for debug rendering
+#include "BulletCollision/CollisionShapes/btBoxShape.h"
+#include "BulletCollision/CollisionShapes/btCapsuleShape.h"
+#include "BulletCollision/CollisionShapes/btCompoundShape.h"
+#include "BulletCollision/CollisionShapes/btConeShape.h"
+#include "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h"
+#include "BulletCollision/CollisionShapes/btCylinderShape.h"
+#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
+#include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h"
+#include "BulletCollision/CollisionShapes/btSphereShape.h"
+#include "BulletCollision/CollisionShapes/btTriangleCallback.h"
+#include "BulletCollision/CollisionShapes/btTriangleMeshShape.h"
+#include "BulletCollision/CollisionShapes/btStaticPlaneShape.h"
+
+
+
+btCollisionWorld::btCollisionWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache, btCollisionConfiguration* collisionConfiguration)
+:m_dispatcher1(dispatcher),
+m_broadphasePairCache(pairCache),
+m_debugDrawer(0),
+m_forceUpdateAllAabbs(true)
+{
+}
+
+
+btCollisionWorld::~btCollisionWorld()
+{
+
+ //clean up remaining objects
+ int i;
+ for (i=0;i<m_collisionObjects.size();i++)
+ {
+ btCollisionObject* collisionObject= m_collisionObjects[i];
+
+ btBroadphaseProxy* bp = collisionObject->getBroadphaseHandle();
+ if (bp)
+ {
+ //
+ // only clear the cached algorithms
+ //
+ getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bp,m_dispatcher1);
+ getBroadphase()->destroyProxy(bp,m_dispatcher1);
+ collisionObject->setBroadphaseHandle(0);
+ }
+ }
+
+
+}
+
+
+
+
+
+
+
+
+
+
+void btCollisionWorld::addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup, int collisionFilterMask)
+{
+
+ btAssert(collisionObject);
+
+ //check that the object isn't already added
+ btAssert( m_collisionObjects.findLinearSearch(collisionObject) == m_collisionObjects.size());
+ btAssert(collisionObject->getWorldArrayIndex() == -1); // do not add the same object to more than one collision world
+
+ collisionObject->setWorldArrayIndex(m_collisionObjects.size());
+ m_collisionObjects.push_back(collisionObject);
+
+ //calculate new AABB
+ btTransform trans = collisionObject->getWorldTransform();
+
+ btVector3 minAabb;
+ btVector3 maxAabb;
+ collisionObject->getCollisionShape()->getAabb(trans,minAabb,maxAabb);
+
+ int type = collisionObject->getCollisionShape()->getShapeType();
+ collisionObject->setBroadphaseHandle( getBroadphase()->createProxy(
+ minAabb,
+ maxAabb,
+ type,
+ collisionObject,
+ collisionFilterGroup,
+ collisionFilterMask,
+ m_dispatcher1)) ;
+
+
+
+
+
+}
+
+
+
+void btCollisionWorld::updateSingleAabb(btCollisionObject* colObj)
+{
+ btVector3 minAabb,maxAabb;
+ colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb);
+ //need to increase the aabb for contact thresholds
+ btVector3 contactThreshold(gContactBreakingThreshold,gContactBreakingThreshold,gContactBreakingThreshold);
+ minAabb -= contactThreshold;
+ maxAabb += contactThreshold;
+
+ if(getDispatchInfo().m_useContinuous && colObj->getInternalType()==btCollisionObject::CO_RIGID_BODY && !colObj->isStaticOrKinematicObject())
+ {
+ btVector3 minAabb2,maxAabb2;
+ colObj->getCollisionShape()->getAabb(colObj->getInterpolationWorldTransform(),minAabb2,maxAabb2);
+ minAabb2 -= contactThreshold;
+ maxAabb2 += contactThreshold;
+ minAabb.setMin(minAabb2);
+ maxAabb.setMax(maxAabb2);
+ }
+
+ btBroadphaseInterface* bp = (btBroadphaseInterface*)m_broadphasePairCache;
+
+ //moving objects should be moderately sized, probably something wrong if not
+ if ( colObj->isStaticObject() || ((maxAabb-minAabb).length2() < btScalar(1e12)))
+ {
+ bp->setAabb(colObj->getBroadphaseHandle(),minAabb,maxAabb, m_dispatcher1);
+ } else
+ {
+ //something went wrong, investigate
+ //this assert is unwanted in 3D modelers (danger of loosing work)
+ colObj->setActivationState(DISABLE_SIMULATION);
+
+ static bool reportMe = true;
+ if (reportMe && m_debugDrawer)
+ {
+ reportMe = false;
+ m_debugDrawer->reportErrorWarning("Overflow in AABB, object removed from simulation");
+ m_debugDrawer->reportErrorWarning("If you can reproduce this, please email bugs@continuousphysics.com\n");
+ m_debugDrawer->reportErrorWarning("Please include above information, your Platform, version of OS.\n");
+ m_debugDrawer->reportErrorWarning("Thanks.\n");
+ }
+ }
+}
+
+void btCollisionWorld::updateAabbs()
+{
+ BT_PROFILE("updateAabbs");
+
+ btTransform predictedTrans;
+ for ( int i=0;i<m_collisionObjects.size();i++)
+ {
+ btCollisionObject* colObj = m_collisionObjects[i];
+ btAssert(colObj->getWorldArrayIndex() == i);
+
+ //only update aabb of active objects
+ if (m_forceUpdateAllAabbs || colObj->isActive())
+ {
+ updateSingleAabb(colObj);
+ }
+ }
+}
+
+
+void btCollisionWorld::computeOverlappingPairs()
+{
+ BT_PROFILE("calculateOverlappingPairs");
+ m_broadphasePairCache->calculateOverlappingPairs(m_dispatcher1);
+}
+
+void btCollisionWorld::performDiscreteCollisionDetection()
+{
+ BT_PROFILE("performDiscreteCollisionDetection");
+
+ btDispatcherInfo& dispatchInfo = getDispatchInfo();
+
+ updateAabbs();
+
+ computeOverlappingPairs();
+
+ btDispatcher* dispatcher = getDispatcher();
+ {
+ BT_PROFILE("dispatchAllCollisionPairs");
+ if (dispatcher)
+ dispatcher->dispatchAllCollisionPairs(m_broadphasePairCache->getOverlappingPairCache(),dispatchInfo,m_dispatcher1);
+ }
+
+}
+
+
+
+void btCollisionWorld::removeCollisionObject(btCollisionObject* collisionObject)
+{
+
+
+ //bool removeFromBroadphase = false;
+
+ {
+
+ btBroadphaseProxy* bp = collisionObject->getBroadphaseHandle();
+ if (bp)
+ {
+ //
+ // only clear the cached algorithms
+ //
+ getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bp,m_dispatcher1);
+ getBroadphase()->destroyProxy(bp,m_dispatcher1);
+ collisionObject->setBroadphaseHandle(0);
+ }
+ }
+
+
+ int iObj = collisionObject->getWorldArrayIndex();
+// btAssert(iObj >= 0 && iObj < m_collisionObjects.size()); // trying to remove an object that was never added or already removed previously?
+ if (iObj >= 0 && iObj < m_collisionObjects.size())
+ {
+ btAssert(collisionObject == m_collisionObjects[iObj]);
+ m_collisionObjects.swap(iObj, m_collisionObjects.size()-1);
+ m_collisionObjects.pop_back();
+ if (iObj < m_collisionObjects.size())
+ {
+ m_collisionObjects[iObj]->setWorldArrayIndex(iObj);
+ }
+ }
+ else
+ {
+ // slow linear search
+ //swapremove
+ m_collisionObjects.remove(collisionObject);
+ }
+ collisionObject->setWorldArrayIndex(-1);
+}
+
+
+void btCollisionWorld::rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans,
+ btCollisionObject* collisionObject,
+ const btCollisionShape* collisionShape,
+ const btTransform& colObjWorldTransform,
+ RayResultCallback& resultCallback)
+{
+ btCollisionObjectWrapper colObWrap(0,collisionShape,collisionObject,colObjWorldTransform,-1,-1);
+ btCollisionWorld::rayTestSingleInternal(rayFromTrans,rayToTrans,&colObWrap,resultCallback);
+}
+
+void btCollisionWorld::rayTestSingleInternal(const btTransform& rayFromTrans,const btTransform& rayToTrans,
+ const btCollisionObjectWrapper* collisionObjectWrap,
+ RayResultCallback& resultCallback)
+{
+ btSphereShape pointShape(btScalar(0.0));
+ pointShape.setMargin(0.f);
+ const btConvexShape* castShape = &pointShape;
+ const btCollisionShape* collisionShape = collisionObjectWrap->getCollisionShape();
+ const btTransform& colObjWorldTransform = collisionObjectWrap->getWorldTransform();
+
+ if (collisionShape->isConvex())
+ {
+ // BT_PROFILE("rayTestConvex");
+ btConvexCast::CastResult castResult;
+ castResult.m_fraction = resultCallback.m_closestHitFraction;
+
+ btConvexShape* convexShape = (btConvexShape*) collisionShape;
+ btVoronoiSimplexSolver simplexSolver;
+ btSubsimplexConvexCast subSimplexConvexCaster(castShape,convexShape,&simplexSolver);
+
+ btGjkConvexCast gjkConvexCaster(castShape,convexShape,&simplexSolver);
+
+ //btContinuousConvexCollision convexCaster(castShape,convexShape,&simplexSolver,0);
+
+ btConvexCast* convexCasterPtr = 0;
+ //use kF_UseSubSimplexConvexCastRaytest by default
+ if (resultCallback.m_flags & btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest)
+ convexCasterPtr = &gjkConvexCaster;
+ else
+ convexCasterPtr = &subSimplexConvexCaster;
+
+ btConvexCast& convexCaster = *convexCasterPtr;
+
+ if (convexCaster.calcTimeOfImpact(rayFromTrans,rayToTrans,colObjWorldTransform,colObjWorldTransform,castResult))
+ {
+ //add hit
+ if (castResult.m_normal.length2() > btScalar(0.0001))
+ {
+ if (castResult.m_fraction < resultCallback.m_closestHitFraction)
+ {
+ //todo: figure out what this is about. When is rayFromTest.getBasis() not identity?
+#ifdef USE_SUBSIMPLEX_CONVEX_CAST
+ //rotate normal into worldspace
+ castResult.m_normal = rayFromTrans.getBasis() * castResult.m_normal;
+#endif //USE_SUBSIMPLEX_CONVEX_CAST
+
+ castResult.m_normal.normalize();
+ btCollisionWorld::LocalRayResult localRayResult
+ (
+ collisionObjectWrap->getCollisionObject(),
+ 0,
+ castResult.m_normal,
+ castResult.m_fraction
+ );
+
+ bool normalInWorldSpace = true;
+ resultCallback.addSingleResult(localRayResult, normalInWorldSpace);
+
+ }
+ }
+ }
+ } else {
+ if (collisionShape->isConcave())
+ {
+
+ //ConvexCast::CastResult
+ struct BridgeTriangleRaycastCallback : public btTriangleRaycastCallback
+ {
+ btCollisionWorld::RayResultCallback* m_resultCallback;
+ const btCollisionObject* m_collisionObject;
+ const btConcaveShape* m_triangleMesh;
+
+ btTransform m_colObjWorldTransform;
+
+ BridgeTriangleRaycastCallback( const btVector3& from,const btVector3& to,
+ btCollisionWorld::RayResultCallback* resultCallback, const btCollisionObject* collisionObject,const btConcaveShape* triangleMesh,const btTransform& colObjWorldTransform):
+ //@BP Mod
+ btTriangleRaycastCallback(from,to, resultCallback->m_flags),
+ m_resultCallback(resultCallback),
+ m_collisionObject(collisionObject),
+ m_triangleMesh(triangleMesh),
+ m_colObjWorldTransform(colObjWorldTransform)
+ {
+ }
+
+
+ virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex )
+ {
+ btCollisionWorld::LocalShapeInfo shapeInfo;
+ shapeInfo.m_shapePart = partId;
+ shapeInfo.m_triangleIndex = triangleIndex;
+
+ btVector3 hitNormalWorld = m_colObjWorldTransform.getBasis() * hitNormalLocal;
+
+ btCollisionWorld::LocalRayResult rayResult
+ (m_collisionObject,
+ &shapeInfo,
+ hitNormalWorld,
+ hitFraction);
+
+ bool normalInWorldSpace = true;
+ return m_resultCallback->addSingleResult(rayResult,normalInWorldSpace);
+ }
+
+ };
+
+ btTransform worldTocollisionObject = colObjWorldTransform.inverse();
+ btVector3 rayFromLocal = worldTocollisionObject * rayFromTrans.getOrigin();
+ btVector3 rayToLocal = worldTocollisionObject * rayToTrans.getOrigin();
+
+ // BT_PROFILE("rayTestConcave");
+ if (collisionShape->getShapeType()==TRIANGLE_MESH_SHAPE_PROXYTYPE)
+ {
+ ///optimized version for btBvhTriangleMeshShape
+ btBvhTriangleMeshShape* triangleMesh = (btBvhTriangleMeshShape*)collisionShape;
+
+ BridgeTriangleRaycastCallback rcb(rayFromLocal,rayToLocal,&resultCallback,collisionObjectWrap->getCollisionObject(),triangleMesh,colObjWorldTransform);
+ rcb.m_hitFraction = resultCallback.m_closestHitFraction;
+ triangleMesh->performRaycast(&rcb,rayFromLocal,rayToLocal);
+ }
+ else if (collisionShape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE)
+ {
+ ///optimized version for btScaledBvhTriangleMeshShape
+ btScaledBvhTriangleMeshShape* scaledTriangleMesh = (btScaledBvhTriangleMeshShape*)collisionShape;
+ btBvhTriangleMeshShape* triangleMesh = (btBvhTriangleMeshShape*)scaledTriangleMesh->getChildShape();
+
+ //scale the ray positions
+ btVector3 scale = scaledTriangleMesh->getLocalScaling();
+ btVector3 rayFromLocalScaled = rayFromLocal / scale;
+ btVector3 rayToLocalScaled = rayToLocal / scale;
+
+ //perform raycast in the underlying btBvhTriangleMeshShape
+ BridgeTriangleRaycastCallback rcb(rayFromLocalScaled, rayToLocalScaled, &resultCallback, collisionObjectWrap->getCollisionObject(), triangleMesh, colObjWorldTransform);
+ rcb.m_hitFraction = resultCallback.m_closestHitFraction;
+ triangleMesh->performRaycast(&rcb, rayFromLocalScaled, rayToLocalScaled);
+ }
+ else
+ {
+ //generic (slower) case
+ btConcaveShape* concaveShape = (btConcaveShape*)collisionShape;
+
+ btTransform worldTocollisionObject = colObjWorldTransform.inverse();
+
+ btVector3 rayFromLocal = worldTocollisionObject * rayFromTrans.getOrigin();
+ btVector3 rayToLocal = worldTocollisionObject * rayToTrans.getOrigin();
+
+ //ConvexCast::CastResult
+
+ struct BridgeTriangleRaycastCallback : public btTriangleRaycastCallback
+ {
+ btCollisionWorld::RayResultCallback* m_resultCallback;
+ const btCollisionObject* m_collisionObject;
+ btConcaveShape* m_triangleMesh;
+
+ btTransform m_colObjWorldTransform;
+
+ BridgeTriangleRaycastCallback( const btVector3& from,const btVector3& to,
+ btCollisionWorld::RayResultCallback* resultCallback, const btCollisionObject* collisionObject,btConcaveShape* triangleMesh, const btTransform& colObjWorldTransform):
+ //@BP Mod
+ btTriangleRaycastCallback(from,to, resultCallback->m_flags),
+ m_resultCallback(resultCallback),
+ m_collisionObject(collisionObject),
+ m_triangleMesh(triangleMesh),
+ m_colObjWorldTransform(colObjWorldTransform)
+ {
+ }
+
+
+ virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex )
+ {
+ btCollisionWorld::LocalShapeInfo shapeInfo;
+ shapeInfo.m_shapePart = partId;
+ shapeInfo.m_triangleIndex = triangleIndex;
+
+ btVector3 hitNormalWorld = m_colObjWorldTransform.getBasis() * hitNormalLocal;
+
+ btCollisionWorld::LocalRayResult rayResult
+ (m_collisionObject,
+ &shapeInfo,
+ hitNormalWorld,
+ hitFraction);
+
+ bool normalInWorldSpace = true;
+ return m_resultCallback->addSingleResult(rayResult,normalInWorldSpace);
+ }
+
+ };
+
+
+ BridgeTriangleRaycastCallback rcb(rayFromLocal,rayToLocal,&resultCallback,collisionObjectWrap->getCollisionObject(),concaveShape, colObjWorldTransform);
+ rcb.m_hitFraction = resultCallback.m_closestHitFraction;
+
+ btVector3 rayAabbMinLocal = rayFromLocal;
+ rayAabbMinLocal.setMin(rayToLocal);
+ btVector3 rayAabbMaxLocal = rayFromLocal;
+ rayAabbMaxLocal.setMax(rayToLocal);
+
+ concaveShape->processAllTriangles(&rcb,rayAabbMinLocal,rayAabbMaxLocal);
+ }
+ } else {
+ // BT_PROFILE("rayTestCompound");
+ if (collisionShape->isCompound())
+ {
+ struct LocalInfoAdder2 : public RayResultCallback
+ {
+ RayResultCallback* m_userCallback;
+ int m_i;
+
+ LocalInfoAdder2 (int i, RayResultCallback *user)
+ : m_userCallback(user), m_i(i)
+ {
+ m_closestHitFraction = m_userCallback->m_closestHitFraction;
+ m_flags = m_userCallback->m_flags;
+ }
+ virtual bool needsCollision(btBroadphaseProxy* p) const
+ {
+ return m_userCallback->needsCollision(p);
+ }
+
+ virtual btScalar addSingleResult (btCollisionWorld::LocalRayResult &r, bool b)
+ {
+ btCollisionWorld::LocalShapeInfo shapeInfo;
+ shapeInfo.m_shapePart = -1;
+ shapeInfo.m_triangleIndex = m_i;
+ if (r.m_localShapeInfo == NULL)
+ r.m_localShapeInfo = &shapeInfo;
+
+ const btScalar result = m_userCallback->addSingleResult(r, b);
+ m_closestHitFraction = m_userCallback->m_closestHitFraction;
+ return result;
+ }
+ };
+
+ struct RayTester : btDbvt::ICollide
+ {
+ const btCollisionObject* m_collisionObject;
+ const btCompoundShape* m_compoundShape;
+ const btTransform& m_colObjWorldTransform;
+ const btTransform& m_rayFromTrans;
+ const btTransform& m_rayToTrans;
+ RayResultCallback& m_resultCallback;
+
+ RayTester(const btCollisionObject* collisionObject,
+ const btCompoundShape* compoundShape,
+ const btTransform& colObjWorldTransform,
+ const btTransform& rayFromTrans,
+ const btTransform& rayToTrans,
+ RayResultCallback& resultCallback):
+ m_collisionObject(collisionObject),
+ m_compoundShape(compoundShape),
+ m_colObjWorldTransform(colObjWorldTransform),
+ m_rayFromTrans(rayFromTrans),
+ m_rayToTrans(rayToTrans),
+ m_resultCallback(resultCallback)
+ {
+
+ }
+
+ void ProcessLeaf(int i)
+ {
+ const btCollisionShape* childCollisionShape = m_compoundShape->getChildShape(i);
+ const btTransform& childTrans = m_compoundShape->getChildTransform(i);
+ btTransform childWorldTrans = m_colObjWorldTransform * childTrans;
+
+ btCollisionObjectWrapper tmpOb(0,childCollisionShape,m_collisionObject,childWorldTrans,-1,i);
+ // replace collision shape so that callback can determine the triangle
+
+
+
+ LocalInfoAdder2 my_cb(i, &m_resultCallback);
+
+ rayTestSingleInternal(
+ m_rayFromTrans,
+ m_rayToTrans,
+ &tmpOb,
+ my_cb);
+
+ }
+
+ void Process(const btDbvtNode* leaf)
+ {
+ ProcessLeaf(leaf->dataAsInt);
+ }
+ };
+
+ const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(collisionShape);
+ const btDbvt* dbvt = compoundShape->getDynamicAabbTree();
+
+
+ RayTester rayCB(
+ collisionObjectWrap->getCollisionObject(),
+ compoundShape,
+ colObjWorldTransform,
+ rayFromTrans,
+ rayToTrans,
+ resultCallback);
+#ifndef DISABLE_DBVT_COMPOUNDSHAPE_RAYCAST_ACCELERATION
+ if (dbvt)
+ {
+ btVector3 localRayFrom = colObjWorldTransform.inverseTimes(rayFromTrans).getOrigin();
+ btVector3 localRayTo = colObjWorldTransform.inverseTimes(rayToTrans).getOrigin();
+ btDbvt::rayTest(dbvt->m_root, localRayFrom , localRayTo, rayCB);
+ }
+ else
+#endif //DISABLE_DBVT_COMPOUNDSHAPE_RAYCAST_ACCELERATION
+ {
+ for (int i = 0, n = compoundShape->getNumChildShapes(); i < n; ++i)
+ {
+ rayCB.ProcessLeaf(i);
+ }
+ }
+ }
+ }
+ }
+}
+
+void btCollisionWorld::objectQuerySingle(const btConvexShape* castShape,const btTransform& convexFromTrans,const btTransform& convexToTrans,
+ btCollisionObject* collisionObject,
+ const btCollisionShape* collisionShape,
+ const btTransform& colObjWorldTransform,
+ ConvexResultCallback& resultCallback, btScalar allowedPenetration)
+{
+ btCollisionObjectWrapper tmpOb(0,collisionShape,collisionObject,colObjWorldTransform,-1,-1);
+ btCollisionWorld::objectQuerySingleInternal(castShape,convexFromTrans,convexToTrans,&tmpOb,resultCallback,allowedPenetration);
+}
+
+void btCollisionWorld::objectQuerySingleInternal(const btConvexShape* castShape,const btTransform& convexFromTrans,const btTransform& convexToTrans,
+ const btCollisionObjectWrapper* colObjWrap,
+ ConvexResultCallback& resultCallback, btScalar allowedPenetration)
+{
+ const btCollisionShape* collisionShape = colObjWrap->getCollisionShape();
+ const btTransform& colObjWorldTransform = colObjWrap->getWorldTransform();
+
+ if (collisionShape->isConvex())
+ {
+ //BT_PROFILE("convexSweepConvex");
+ btConvexCast::CastResult castResult;
+ castResult.m_allowedPenetration = allowedPenetration;
+ castResult.m_fraction = resultCallback.m_closestHitFraction;//btScalar(1.);//??
+
+ btConvexShape* convexShape = (btConvexShape*) collisionShape;
+ btVoronoiSimplexSolver simplexSolver;
+ btGjkEpaPenetrationDepthSolver gjkEpaPenetrationSolver;
+
+ btContinuousConvexCollision convexCaster1(castShape,convexShape,&simplexSolver,&gjkEpaPenetrationSolver);
+ //btGjkConvexCast convexCaster2(castShape,convexShape,&simplexSolver);
+ //btSubsimplexConvexCast convexCaster3(castShape,convexShape,&simplexSolver);
+
+ btConvexCast* castPtr = &convexCaster1;
+
+
+
+ if (castPtr->calcTimeOfImpact(convexFromTrans,convexToTrans,colObjWorldTransform,colObjWorldTransform,castResult))
+ {
+ //add hit
+ if (castResult.m_normal.length2() > btScalar(0.0001))
+ {
+ if (castResult.m_fraction < resultCallback.m_closestHitFraction)
+ {
+ castResult.m_normal.normalize();
+ btCollisionWorld::LocalConvexResult localConvexResult
+ (
+ colObjWrap->getCollisionObject(),
+ 0,
+ castResult.m_normal,
+ castResult.m_hitPoint,
+ castResult.m_fraction
+ );
+
+ bool normalInWorldSpace = true;
+ resultCallback.addSingleResult(localConvexResult, normalInWorldSpace);
+
+ }
+ }
+ }
+ } else {
+ if (collisionShape->isConcave())
+ {
+ if (collisionShape->getShapeType()==TRIANGLE_MESH_SHAPE_PROXYTYPE)
+ {
+ //BT_PROFILE("convexSweepbtBvhTriangleMesh");
+ btBvhTriangleMeshShape* triangleMesh = (btBvhTriangleMeshShape*)collisionShape;
+ btTransform worldTocollisionObject = colObjWorldTransform.inverse();
+ btVector3 convexFromLocal = worldTocollisionObject * convexFromTrans.getOrigin();
+ btVector3 convexToLocal = worldTocollisionObject * convexToTrans.getOrigin();
+ // rotation of box in local mesh space = MeshRotation^-1 * ConvexToRotation
+ btTransform rotationXform = btTransform(worldTocollisionObject.getBasis() * convexToTrans.getBasis());
+
+ //ConvexCast::CastResult
+ struct BridgeTriangleConvexcastCallback : public btTriangleConvexcastCallback
+ {
+ btCollisionWorld::ConvexResultCallback* m_resultCallback;
+ const btCollisionObject* m_collisionObject;
+ btTriangleMeshShape* m_triangleMesh;
+
+ BridgeTriangleConvexcastCallback(const btConvexShape* castShape, const btTransform& from,const btTransform& to,
+ btCollisionWorld::ConvexResultCallback* resultCallback, const btCollisionObject* collisionObject,btTriangleMeshShape* triangleMesh, const btTransform& triangleToWorld):
+ btTriangleConvexcastCallback(castShape, from,to, triangleToWorld, triangleMesh->getMargin()),
+ m_resultCallback(resultCallback),
+ m_collisionObject(collisionObject),
+ m_triangleMesh(triangleMesh)
+ {
+ }
+
+
+ virtual btScalar reportHit(const btVector3& hitNormalLocal, const btVector3& hitPointLocal, btScalar hitFraction, int partId, int triangleIndex )
+ {
+ btCollisionWorld::LocalShapeInfo shapeInfo;
+ shapeInfo.m_shapePart = partId;
+ shapeInfo.m_triangleIndex = triangleIndex;
+ if (hitFraction <= m_resultCallback->m_closestHitFraction)
+ {
+
+ btCollisionWorld::LocalConvexResult convexResult
+ (m_collisionObject,
+ &shapeInfo,
+ hitNormalLocal,
+ hitPointLocal,
+ hitFraction);
+
+ bool normalInWorldSpace = true;
+
+
+ return m_resultCallback->addSingleResult(convexResult,normalInWorldSpace);
+ }
+ return hitFraction;
+ }
+
+ };
+
+ BridgeTriangleConvexcastCallback tccb(castShape, convexFromTrans,convexToTrans,&resultCallback,colObjWrap->getCollisionObject(),triangleMesh, colObjWorldTransform);
+ tccb.m_hitFraction = resultCallback.m_closestHitFraction;
+ tccb.m_allowedPenetration = allowedPenetration;
+ btVector3 boxMinLocal, boxMaxLocal;
+ castShape->getAabb(rotationXform, boxMinLocal, boxMaxLocal);
+ triangleMesh->performConvexcast(&tccb,convexFromLocal,convexToLocal,boxMinLocal, boxMaxLocal);
+ } else
+ {
+ if (collisionShape->getShapeType()==STATIC_PLANE_PROXYTYPE)
+ {
+ btConvexCast::CastResult castResult;
+ castResult.m_allowedPenetration = allowedPenetration;
+ castResult.m_fraction = resultCallback.m_closestHitFraction;
+ btStaticPlaneShape* planeShape = (btStaticPlaneShape*) collisionShape;
+ btContinuousConvexCollision convexCaster1(castShape,planeShape);
+ btConvexCast* castPtr = &convexCaster1;
+
+ if (castPtr->calcTimeOfImpact(convexFromTrans,convexToTrans,colObjWorldTransform,colObjWorldTransform,castResult))
+ {
+ //add hit
+ if (castResult.m_normal.length2() > btScalar(0.0001))
+ {
+ if (castResult.m_fraction < resultCallback.m_closestHitFraction)
+ {
+ castResult.m_normal.normalize();
+ btCollisionWorld::LocalConvexResult localConvexResult
+ (
+ colObjWrap->getCollisionObject(),
+ 0,
+ castResult.m_normal,
+ castResult.m_hitPoint,
+ castResult.m_fraction
+ );
+
+ bool normalInWorldSpace = true;
+ resultCallback.addSingleResult(localConvexResult, normalInWorldSpace);
+ }
+ }
+ }
+
+ } else
+ {
+ //BT_PROFILE("convexSweepConcave");
+ btConcaveShape* concaveShape = (btConcaveShape*)collisionShape;
+ btTransform worldTocollisionObject = colObjWorldTransform.inverse();
+ btVector3 convexFromLocal = worldTocollisionObject * convexFromTrans.getOrigin();
+ btVector3 convexToLocal = worldTocollisionObject * convexToTrans.getOrigin();
+ // rotation of box in local mesh space = MeshRotation^-1 * ConvexToRotation
+ btTransform rotationXform = btTransform(worldTocollisionObject.getBasis() * convexToTrans.getBasis());
+
+ //ConvexCast::CastResult
+ struct BridgeTriangleConvexcastCallback : public btTriangleConvexcastCallback
+ {
+ btCollisionWorld::ConvexResultCallback* m_resultCallback;
+ const btCollisionObject* m_collisionObject;
+ btConcaveShape* m_triangleMesh;
+
+ BridgeTriangleConvexcastCallback(const btConvexShape* castShape, const btTransform& from,const btTransform& to,
+ btCollisionWorld::ConvexResultCallback* resultCallback, const btCollisionObject* collisionObject,btConcaveShape* triangleMesh, const btTransform& triangleToWorld):
+ btTriangleConvexcastCallback(castShape, from,to, triangleToWorld, triangleMesh->getMargin()),
+ m_resultCallback(resultCallback),
+ m_collisionObject(collisionObject),
+ m_triangleMesh(triangleMesh)
+ {
+ }
+
+
+ virtual btScalar reportHit(const btVector3& hitNormalLocal, const btVector3& hitPointLocal, btScalar hitFraction, int partId, int triangleIndex )
+ {
+ btCollisionWorld::LocalShapeInfo shapeInfo;
+ shapeInfo.m_shapePart = partId;
+ shapeInfo.m_triangleIndex = triangleIndex;
+ if (hitFraction <= m_resultCallback->m_closestHitFraction)
+ {
+
+ btCollisionWorld::LocalConvexResult convexResult
+ (m_collisionObject,
+ &shapeInfo,
+ hitNormalLocal,
+ hitPointLocal,
+ hitFraction);
+
+ bool normalInWorldSpace = true;
+
+ return m_resultCallback->addSingleResult(convexResult,normalInWorldSpace);
+ }
+ return hitFraction;
+ }
+
+ };
+
+ BridgeTriangleConvexcastCallback tccb(castShape, convexFromTrans,convexToTrans,&resultCallback,colObjWrap->getCollisionObject(),concaveShape, colObjWorldTransform);
+ tccb.m_hitFraction = resultCallback.m_closestHitFraction;
+ tccb.m_allowedPenetration = allowedPenetration;
+ btVector3 boxMinLocal, boxMaxLocal;
+ castShape->getAabb(rotationXform, boxMinLocal, boxMaxLocal);
+
+ btVector3 rayAabbMinLocal = convexFromLocal;
+ rayAabbMinLocal.setMin(convexToLocal);
+ btVector3 rayAabbMaxLocal = convexFromLocal;
+ rayAabbMaxLocal.setMax(convexToLocal);
+ rayAabbMinLocal += boxMinLocal;
+ rayAabbMaxLocal += boxMaxLocal;
+ concaveShape->processAllTriangles(&tccb,rayAabbMinLocal,rayAabbMaxLocal);
+ }
+ }
+ } else {
+ if (collisionShape->isCompound())
+ {
+ struct btCompoundLeafCallback : btDbvt::ICollide
+ {
+ btCompoundLeafCallback(
+ const btCollisionObjectWrapper* colObjWrap,
+ const btConvexShape* castShape,
+ const btTransform& convexFromTrans,
+ const btTransform& convexToTrans,
+ btScalar allowedPenetration,
+ const btCompoundShape* compoundShape,
+ const btTransform& colObjWorldTransform,
+ ConvexResultCallback& resultCallback)
+ :
+ m_colObjWrap(colObjWrap),
+ m_castShape(castShape),
+ m_convexFromTrans(convexFromTrans),
+ m_convexToTrans(convexToTrans),
+ m_allowedPenetration(allowedPenetration),
+ m_compoundShape(compoundShape),
+ m_colObjWorldTransform(colObjWorldTransform),
+ m_resultCallback(resultCallback) {
+ }
+
+ const btCollisionObjectWrapper* m_colObjWrap;
+ const btConvexShape* m_castShape;
+ const btTransform& m_convexFromTrans;
+ const btTransform& m_convexToTrans;
+ btScalar m_allowedPenetration;
+ const btCompoundShape* m_compoundShape;
+ const btTransform& m_colObjWorldTransform;
+ ConvexResultCallback& m_resultCallback;
+
+ public:
+
+ void ProcessChild(int index, const btTransform& childTrans, const btCollisionShape* childCollisionShape)
+ {
+ btTransform childWorldTrans = m_colObjWorldTransform * childTrans;
+
+ struct LocalInfoAdder : public ConvexResultCallback {
+ ConvexResultCallback* m_userCallback;
+ int m_i;
+
+ LocalInfoAdder(int i, ConvexResultCallback *user)
+ : m_userCallback(user), m_i(i)
+ {
+ m_closestHitFraction = m_userCallback->m_closestHitFraction;
+ }
+ virtual bool needsCollision(btBroadphaseProxy* p) const
+ {
+ return m_userCallback->needsCollision(p);
+ }
+ virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& r, bool b)
+ {
+ btCollisionWorld::LocalShapeInfo shapeInfo;
+ shapeInfo.m_shapePart = -1;
+ shapeInfo.m_triangleIndex = m_i;
+ if (r.m_localShapeInfo == NULL)
+ r.m_localShapeInfo = &shapeInfo;
+ const btScalar result = m_userCallback->addSingleResult(r, b);
+ m_closestHitFraction = m_userCallback->m_closestHitFraction;
+ return result;
+
+ }
+ };
+
+ LocalInfoAdder my_cb(index, &m_resultCallback);
+
+ btCollisionObjectWrapper tmpObj(m_colObjWrap, childCollisionShape, m_colObjWrap->getCollisionObject(), childWorldTrans, -1, index);
+
+ objectQuerySingleInternal(m_castShape, m_convexFromTrans, m_convexToTrans, &tmpObj, my_cb, m_allowedPenetration);
+ }
+
+ void Process(const btDbvtNode* leaf)
+ {
+ // Processing leaf node
+ int index = leaf->dataAsInt;
+
+ btTransform childTrans = m_compoundShape->getChildTransform(index);
+ const btCollisionShape* childCollisionShape = m_compoundShape->getChildShape(index);
+
+ ProcessChild(index, childTrans, childCollisionShape);
+ }
+ };
+
+ BT_PROFILE("convexSweepCompound");
+ const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(collisionShape);
+
+ btVector3 fromLocalAabbMin, fromLocalAabbMax;
+ btVector3 toLocalAabbMin, toLocalAabbMax;
+
+ castShape->getAabb(colObjWorldTransform.inverse() * convexFromTrans, fromLocalAabbMin, fromLocalAabbMax);
+ castShape->getAabb(colObjWorldTransform.inverse() * convexToTrans, toLocalAabbMin, toLocalAabbMax);
+
+ fromLocalAabbMin.setMin(toLocalAabbMin);
+ fromLocalAabbMax.setMax(toLocalAabbMax);
+
+ btCompoundLeafCallback callback(colObjWrap, castShape, convexFromTrans, convexToTrans,
+ allowedPenetration, compoundShape, colObjWorldTransform, resultCallback);
+
+ const btDbvt* tree = compoundShape->getDynamicAabbTree();
+ if (tree) {
+ const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds = btDbvtVolume::FromMM(fromLocalAabbMin, fromLocalAabbMax);
+ tree->collideTV(tree->m_root, bounds, callback);
+ } else {
+ int i;
+ for (i=0;i<compoundShape->getNumChildShapes();i++)
+ {
+ const btCollisionShape* childCollisionShape = compoundShape->getChildShape(i);
+ btTransform childTrans = compoundShape->getChildTransform(i);
+ callback.ProcessChild(i, childTrans, childCollisionShape);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+struct btSingleRayCallback : public btBroadphaseRayCallback
+{
+
+ btVector3 m_rayFromWorld;
+ btVector3 m_rayToWorld;
+ btTransform m_rayFromTrans;
+ btTransform m_rayToTrans;
+ btVector3 m_hitNormal;
+
+ const btCollisionWorld* m_world;
+ btCollisionWorld::RayResultCallback& m_resultCallback;
+
+ btSingleRayCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld,const btCollisionWorld* world,btCollisionWorld::RayResultCallback& resultCallback)
+ :m_rayFromWorld(rayFromWorld),
+ m_rayToWorld(rayToWorld),
+ m_world(world),
+ m_resultCallback(resultCallback)
+ {
+ m_rayFromTrans.setIdentity();
+ m_rayFromTrans.setOrigin(m_rayFromWorld);
+ m_rayToTrans.setIdentity();
+ m_rayToTrans.setOrigin(m_rayToWorld);
+
+ btVector3 rayDir = (rayToWorld-rayFromWorld);
+
+ rayDir.normalize ();
+ ///what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT
+ m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[0];
+ m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[1];
+ m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[2];
+ m_signs[0] = m_rayDirectionInverse[0] < 0.0;
+ m_signs[1] = m_rayDirectionInverse[1] < 0.0;
+ m_signs[2] = m_rayDirectionInverse[2] < 0.0;
+
+ m_lambda_max = rayDir.dot(m_rayToWorld-m_rayFromWorld);
+
+ }
+
+
+
+ virtual bool process(const btBroadphaseProxy* proxy)
+ {
+ ///terminate further ray tests, once the closestHitFraction reached zero
+ if (m_resultCallback.m_closestHitFraction == btScalar(0.f))
+ return false;
+
+ btCollisionObject* collisionObject = (btCollisionObject*)proxy->m_clientObject;
+
+ //only perform raycast if filterMask matches
+ if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle()))
+ {
+ //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
+ //btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
+#if 0
+#ifdef RECALCULATE_AABB
+ btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
+ collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax);
+#else
+ //getBroadphase()->getAabb(collisionObject->getBroadphaseHandle(),collisionObjectAabbMin,collisionObjectAabbMax);
+ const btVector3& collisionObjectAabbMin = collisionObject->getBroadphaseHandle()->m_aabbMin;
+ const btVector3& collisionObjectAabbMax = collisionObject->getBroadphaseHandle()->m_aabbMax;
+#endif
+#endif
+ //btScalar hitLambda = m_resultCallback.m_closestHitFraction;
+ //culling already done by broadphase
+ //if (btRayAabb(m_rayFromWorld,m_rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,m_hitNormal))
+ {
+ m_world->rayTestSingle(m_rayFromTrans,m_rayToTrans,
+ collisionObject,
+ collisionObject->getCollisionShape(),
+ collisionObject->getWorldTransform(),
+ m_resultCallback);
+ }
+ }
+ return true;
+ }
+};
+
+void btCollisionWorld::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const
+{
+ //BT_PROFILE("rayTest");
+ /// use the broadphase to accelerate the search for objects, based on their aabb
+ /// and for each object with ray-aabb overlap, perform an exact ray test
+ btSingleRayCallback rayCB(rayFromWorld,rayToWorld,this,resultCallback);
+
+#ifndef USE_BRUTEFORCE_RAYBROADPHASE
+ m_broadphasePairCache->rayTest(rayFromWorld,rayToWorld,rayCB);
+#else
+ for (int i=0;i<this->getNumCollisionObjects();i++)
+ {
+ rayCB.process(m_collisionObjects[i]->getBroadphaseHandle());
+ }
+#endif //USE_BRUTEFORCE_RAYBROADPHASE
+
+}
+
+
+struct btSingleSweepCallback : public btBroadphaseRayCallback
+{
+
+ btTransform m_convexFromTrans;
+ btTransform m_convexToTrans;
+ btVector3 m_hitNormal;
+ const btCollisionWorld* m_world;
+ btCollisionWorld::ConvexResultCallback& m_resultCallback;
+ btScalar m_allowedCcdPenetration;
+ const btConvexShape* m_castShape;
+
+
+ btSingleSweepCallback(const btConvexShape* castShape, const btTransform& convexFromTrans,const btTransform& convexToTrans,const btCollisionWorld* world,btCollisionWorld::ConvexResultCallback& resultCallback,btScalar allowedPenetration)
+ :m_convexFromTrans(convexFromTrans),
+ m_convexToTrans(convexToTrans),
+ m_world(world),
+ m_resultCallback(resultCallback),
+ m_allowedCcdPenetration(allowedPenetration),
+ m_castShape(castShape)
+ {
+ btVector3 unnormalizedRayDir = (m_convexToTrans.getOrigin()-m_convexFromTrans.getOrigin());
+ btVector3 rayDir = unnormalizedRayDir.normalized();
+ ///what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT
+ m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[0];
+ m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[1];
+ m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[2];
+ m_signs[0] = m_rayDirectionInverse[0] < 0.0;
+ m_signs[1] = m_rayDirectionInverse[1] < 0.0;
+ m_signs[2] = m_rayDirectionInverse[2] < 0.0;
+
+ m_lambda_max = rayDir.dot(unnormalizedRayDir);
+
+ }
+
+ virtual bool process(const btBroadphaseProxy* proxy)
+ {
+ ///terminate further convex sweep tests, once the closestHitFraction reached zero
+ if (m_resultCallback.m_closestHitFraction == btScalar(0.f))
+ return false;
+
+ btCollisionObject* collisionObject = (btCollisionObject*)proxy->m_clientObject;
+
+ //only perform raycast if filterMask matches
+ if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) {
+ //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
+ m_world->objectQuerySingle(m_castShape, m_convexFromTrans,m_convexToTrans,
+ collisionObject,
+ collisionObject->getCollisionShape(),
+ collisionObject->getWorldTransform(),
+ m_resultCallback,
+ m_allowedCcdPenetration);
+ }
+
+ return true;
+ }
+};
+
+
+
+void btCollisionWorld::convexSweepTest(const btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration) const
+{
+
+ BT_PROFILE("convexSweepTest");
+ /// use the broadphase to accelerate the search for objects, based on their aabb
+ /// and for each object with ray-aabb overlap, perform an exact ray test
+ /// unfortunately the implementation for rayTest and convexSweepTest duplicated, albeit practically identical
+
+
+
+ btTransform convexFromTrans,convexToTrans;
+ convexFromTrans = convexFromWorld;
+ convexToTrans = convexToWorld;
+ btVector3 castShapeAabbMin, castShapeAabbMax;
+ /* Compute AABB that encompasses angular movement */
+ {
+ btVector3 linVel, angVel;
+ btTransformUtil::calculateVelocity (convexFromTrans, convexToTrans, 1.0f, linVel, angVel);
+ btVector3 zeroLinVel;
+ zeroLinVel.setValue(0,0,0);
+ btTransform R;
+ R.setIdentity ();
+ R.setRotation (convexFromTrans.getRotation());
+ castShape->calculateTemporalAabb (R, zeroLinVel, angVel, 1.0f, castShapeAabbMin, castShapeAabbMax);
+ }
+
+#ifndef USE_BRUTEFORCE_RAYBROADPHASE
+
+ btSingleSweepCallback convexCB(castShape,convexFromWorld,convexToWorld,this,resultCallback,allowedCcdPenetration);
+
+ m_broadphasePairCache->rayTest(convexFromTrans.getOrigin(),convexToTrans.getOrigin(),convexCB,castShapeAabbMin,castShapeAabbMax);
+
+#else
+ /// go over all objects, and if the ray intersects their aabb + cast shape aabb,
+ // do a ray-shape query using convexCaster (CCD)
+ int i;
+ for (i=0;i<m_collisionObjects.size();i++)
+ {
+ btCollisionObject* collisionObject= m_collisionObjects[i];
+ //only perform raycast if filterMask matches
+ if(resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) {
+ //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
+ btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
+ collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax);
+ AabbExpand (collisionObjectAabbMin, collisionObjectAabbMax, castShapeAabbMin, castShapeAabbMax);
+ btScalar hitLambda = btScalar(1.); //could use resultCallback.m_closestHitFraction, but needs testing
+ btVector3 hitNormal;
+ if (btRayAabb(convexFromWorld.getOrigin(),convexToWorld.getOrigin(),collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,hitNormal))
+ {
+ objectQuerySingle(castShape, convexFromTrans,convexToTrans,
+ collisionObject,
+ collisionObject->getCollisionShape(),
+ collisionObject->getWorldTransform(),
+ resultCallback,
+ allowedCcdPenetration);
+ }
+ }
+ }
+#endif //USE_BRUTEFORCE_RAYBROADPHASE
+}
+
+
+
+struct btBridgedManifoldResult : public btManifoldResult
+{
+
+ btCollisionWorld::ContactResultCallback& m_resultCallback;
+
+ btBridgedManifoldResult( const btCollisionObjectWrapper* obj0Wrap,const btCollisionObjectWrapper* obj1Wrap,btCollisionWorld::ContactResultCallback& resultCallback )
+ :btManifoldResult(obj0Wrap,obj1Wrap),
+ m_resultCallback(resultCallback)
+ {
+ }
+
+ virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth)
+ {
+ bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject();
+ btVector3 pointA = pointInWorld + normalOnBInWorld * depth;
+ btVector3 localA;
+ btVector3 localB;
+ if (isSwapped)
+ {
+ localA = m_body1Wrap->getCollisionObject()->getWorldTransform().invXform(pointA );
+ localB = m_body0Wrap->getCollisionObject()->getWorldTransform().invXform(pointInWorld);
+ } else
+ {
+ localA = m_body0Wrap->getCollisionObject()->getWorldTransform().invXform(pointA );
+ localB = m_body1Wrap->getCollisionObject()->getWorldTransform().invXform(pointInWorld);
+ }
+
+ btManifoldPoint newPt(localA,localB,normalOnBInWorld,depth);
+ newPt.m_positionWorldOnA = pointA;
+ newPt.m_positionWorldOnB = pointInWorld;
+
+ //BP mod, store contact triangles.
+ if (isSwapped)
+ {
+ newPt.m_partId0 = m_partId1;
+ newPt.m_partId1 = m_partId0;
+ newPt.m_index0 = m_index1;
+ newPt.m_index1 = m_index0;
+ } else
+ {
+ newPt.m_partId0 = m_partId0;
+ newPt.m_partId1 = m_partId1;
+ newPt.m_index0 = m_index0;
+ newPt.m_index1 = m_index1;
+ }
+
+ //experimental feature info, for per-triangle material etc.
+ const btCollisionObjectWrapper* obj0Wrap = isSwapped? m_body1Wrap : m_body0Wrap;
+ const btCollisionObjectWrapper* obj1Wrap = isSwapped? m_body0Wrap : m_body1Wrap;
+ m_resultCallback.addSingleResult(newPt,obj0Wrap,newPt.m_partId0,newPt.m_index0,obj1Wrap,newPt.m_partId1,newPt.m_index1);
+
+ }
+
+};
+
+
+
+struct btSingleContactCallback : public btBroadphaseAabbCallback
+{
+
+ btCollisionObject* m_collisionObject;
+ btCollisionWorld* m_world;
+ btCollisionWorld::ContactResultCallback& m_resultCallback;
+
+
+ btSingleContactCallback(btCollisionObject* collisionObject, btCollisionWorld* world,btCollisionWorld::ContactResultCallback& resultCallback)
+ :m_collisionObject(collisionObject),
+ m_world(world),
+ m_resultCallback(resultCallback)
+ {
+ }
+
+ virtual bool process(const btBroadphaseProxy* proxy)
+ {
+ btCollisionObject* collisionObject = (btCollisionObject*)proxy->m_clientObject;
+ if (collisionObject == m_collisionObject)
+ return true;
+
+ //only perform raycast if filterMask matches
+ if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle()))
+ {
+ btCollisionObjectWrapper ob0(0,m_collisionObject->getCollisionShape(),m_collisionObject,m_collisionObject->getWorldTransform(),-1,-1);
+ btCollisionObjectWrapper ob1(0,collisionObject->getCollisionShape(),collisionObject,collisionObject->getWorldTransform(),-1,-1);
+
+ btCollisionAlgorithm* algorithm = m_world->getDispatcher()->findAlgorithm(&ob0,&ob1,0, BT_CLOSEST_POINT_ALGORITHMS);
+ if (algorithm)
+ {
+ btBridgedManifoldResult contactPointResult(&ob0,&ob1, m_resultCallback);
+ //discrete collision detection query
+
+ algorithm->processCollision(&ob0,&ob1, m_world->getDispatchInfo(),&contactPointResult);
+
+ algorithm->~btCollisionAlgorithm();
+ m_world->getDispatcher()->freeCollisionAlgorithm(algorithm);
+ }
+ }
+ return true;
+ }
+};
+
+
+///contactTest performs a discrete collision test against all objects in the btCollisionWorld, and calls the resultCallback.
+///it reports one or more contact points for every overlapping object (including the one with deepest penetration)
+void btCollisionWorld::contactTest( btCollisionObject* colObj, ContactResultCallback& resultCallback)
+{
+ btVector3 aabbMin,aabbMax;
+ colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(),aabbMin,aabbMax);
+ btSingleContactCallback contactCB(colObj,this,resultCallback);
+
+ m_broadphasePairCache->aabbTest(aabbMin,aabbMax,contactCB);
+}
+
+
+///contactTest performs a discrete collision test between two collision objects and calls the resultCallback if overlap if detected.
+///it reports one or more contact points (including the one with deepest penetration)
+void btCollisionWorld::contactPairTest(btCollisionObject* colObjA, btCollisionObject* colObjB, ContactResultCallback& resultCallback)
+{
+ btCollisionObjectWrapper obA(0,colObjA->getCollisionShape(),colObjA,colObjA->getWorldTransform(),-1,-1);
+ btCollisionObjectWrapper obB(0,colObjB->getCollisionShape(),colObjB,colObjB->getWorldTransform(),-1,-1);
+
+ btCollisionAlgorithm* algorithm = getDispatcher()->findAlgorithm(&obA,&obB, 0, BT_CLOSEST_POINT_ALGORITHMS);
+ if (algorithm)
+ {
+ btBridgedManifoldResult contactPointResult(&obA,&obB, resultCallback);
+ contactPointResult.m_closestPointDistanceThreshold = resultCallback.m_closestDistanceThreshold;
+ //discrete collision detection query
+ algorithm->processCollision(&obA,&obB, getDispatchInfo(),&contactPointResult);
+
+ algorithm->~btCollisionAlgorithm();
+ getDispatcher()->freeCollisionAlgorithm(algorithm);
+ }
+
+}
+
+
+
+
+class DebugDrawcallback : public btTriangleCallback, public btInternalTriangleIndexCallback
+{
+ btIDebugDraw* m_debugDrawer;
+ btVector3 m_color;
+ btTransform m_worldTrans;
+
+public:
+
+ DebugDrawcallback(btIDebugDraw* debugDrawer,const btTransform& worldTrans,const btVector3& color) :
+ m_debugDrawer(debugDrawer),
+ m_color(color),
+ m_worldTrans(worldTrans)
+ {
+ }
+
+ virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex)
+ {
+ processTriangle(triangle,partId,triangleIndex);
+ }
+
+ virtual void processTriangle(btVector3* triangle,int partId, int triangleIndex)
+ {
+ (void)partId;
+ (void)triangleIndex;
+
+ btVector3 wv0,wv1,wv2;
+ wv0 = m_worldTrans*triangle[0];
+ wv1 = m_worldTrans*triangle[1];
+ wv2 = m_worldTrans*triangle[2];
+ btVector3 center = (wv0+wv1+wv2)*btScalar(1./3.);
+
+ if (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawNormals )
+ {
+ btVector3 normal = (wv1-wv0).cross(wv2-wv0);
+ normal.normalize();
+ btVector3 normalColor(1,1,0);
+ m_debugDrawer->drawLine(center,center+normal,normalColor);
+ }
+ m_debugDrawer->drawLine(wv0,wv1,m_color);
+ m_debugDrawer->drawLine(wv1,wv2,m_color);
+ m_debugDrawer->drawLine(wv2,wv0,m_color);
+ }
+};
+
+
+void btCollisionWorld::debugDrawObject(const btTransform& worldTransform, const btCollisionShape* shape, const btVector3& color)
+{
+ // Draw a small simplex at the center of the object
+ if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawFrames)
+ {
+ getDebugDrawer()->drawTransform(worldTransform,.1);
+ }
+
+ if (shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE)
+ {
+ const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shape);
+ for (int i=compoundShape->getNumChildShapes()-1;i>=0;i--)
+ {
+ btTransform childTrans = compoundShape->getChildTransform(i);
+ const btCollisionShape* colShape = compoundShape->getChildShape(i);
+ debugDrawObject(worldTransform*childTrans,colShape,color);
+ }
+
+ } else
+ {
+
+ switch (shape->getShapeType())
+ {
+
+ case BOX_SHAPE_PROXYTYPE:
+ {
+ const btBoxShape* boxShape = static_cast<const btBoxShape*>(shape);
+ btVector3 halfExtents = boxShape->getHalfExtentsWithMargin();
+ getDebugDrawer()->drawBox(-halfExtents,halfExtents,worldTransform,color);
+ break;
+ }
+
+ case SPHERE_SHAPE_PROXYTYPE:
+ {
+ const btSphereShape* sphereShape = static_cast<const btSphereShape*>(shape);
+ btScalar radius = sphereShape->getMargin();//radius doesn't include the margin, so draw with margin
+
+ getDebugDrawer()->drawSphere(radius, worldTransform, color);
+ break;
+ }
+ case MULTI_SPHERE_SHAPE_PROXYTYPE:
+ {
+ const btMultiSphereShape* multiSphereShape = static_cast<const btMultiSphereShape*>(shape);
+
+ btTransform childTransform;
+ childTransform.setIdentity();
+
+ for (int i = multiSphereShape->getSphereCount()-1; i>=0;i--)
+ {
+ childTransform.setOrigin(multiSphereShape->getSpherePosition(i));
+ getDebugDrawer()->drawSphere(multiSphereShape->getSphereRadius(i), worldTransform*childTransform, color);
+ }
+
+ break;
+ }
+ case CAPSULE_SHAPE_PROXYTYPE:
+ {
+ const btCapsuleShape* capsuleShape = static_cast<const btCapsuleShape*>(shape);
+
+ btScalar radius = capsuleShape->getRadius();
+ btScalar halfHeight = capsuleShape->getHalfHeight();
+
+ int upAxis = capsuleShape->getUpAxis();
+ getDebugDrawer()->drawCapsule(radius, halfHeight, upAxis, worldTransform, color);
+ break;
+ }
+ case CONE_SHAPE_PROXYTYPE:
+ {
+ const btConeShape* coneShape = static_cast<const btConeShape*>(shape);
+ btScalar radius = coneShape->getRadius();//+coneShape->getMargin();
+ btScalar height = coneShape->getHeight();//+coneShape->getMargin();
+
+ int upAxis= coneShape->getConeUpIndex();
+ getDebugDrawer()->drawCone(radius, height, upAxis, worldTransform, color);
+ break;
+
+ }
+ case CYLINDER_SHAPE_PROXYTYPE:
+ {
+ const btCylinderShape* cylinder = static_cast<const btCylinderShape*>(shape);
+ int upAxis = cylinder->getUpAxis();
+ btScalar radius = cylinder->getRadius();
+ btScalar halfHeight = cylinder->getHalfExtentsWithMargin()[upAxis];
+ getDebugDrawer()->drawCylinder(radius, halfHeight, upAxis, worldTransform, color);
+ break;
+ }
+
+ case STATIC_PLANE_PROXYTYPE:
+ {
+ const btStaticPlaneShape* staticPlaneShape = static_cast<const btStaticPlaneShape*>(shape);
+ btScalar planeConst = staticPlaneShape->getPlaneConstant();
+ const btVector3& planeNormal = staticPlaneShape->getPlaneNormal();
+ getDebugDrawer()->drawPlane(planeNormal, planeConst,worldTransform, color);
+ break;
+
+ }
+ default:
+ {
+
+ /// for polyhedral shapes
+ if (shape->isPolyhedral())
+ {
+ btPolyhedralConvexShape* polyshape = (btPolyhedralConvexShape*) shape;
+
+ int i;
+ if (polyshape->getConvexPolyhedron())
+ {
+ const btConvexPolyhedron* poly = polyshape->getConvexPolyhedron();
+ for (i=0;i<poly->m_faces.size();i++)
+ {
+ btVector3 centroid(0,0,0);
+ int numVerts = poly->m_faces[i].m_indices.size();
+ if (numVerts)
+ {
+ int lastV = poly->m_faces[i].m_indices[numVerts-1];
+ for (int v=0;v<poly->m_faces[i].m_indices.size();v++)
+ {
+ int curVert = poly->m_faces[i].m_indices[v];
+ centroid+=poly->m_vertices[curVert];
+ getDebugDrawer()->drawLine(worldTransform*poly->m_vertices[lastV],worldTransform*poly->m_vertices[curVert],color);
+ lastV = curVert;
+ }
+ }
+ centroid*= btScalar(1.f)/btScalar(numVerts);
+ if (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawNormals)
+ {
+ btVector3 normalColor(1,1,0);
+ btVector3 faceNormal(poly->m_faces[i].m_plane[0],poly->m_faces[i].m_plane[1],poly->m_faces[i].m_plane[2]);
+ getDebugDrawer()->drawLine(worldTransform*centroid,worldTransform*(centroid+faceNormal),normalColor);
+ }
+
+ }
+
+
+ } else
+ {
+ for (i=0;i<polyshape->getNumEdges();i++)
+ {
+ btVector3 a,b;
+ polyshape->getEdge(i,a,b);
+ btVector3 wa = worldTransform * a;
+ btVector3 wb = worldTransform * b;
+ getDebugDrawer()->drawLine(wa,wb,color);
+ }
+ }
+
+
+ }
+
+ if (shape->isConcave())
+ {
+ btConcaveShape* concaveMesh = (btConcaveShape*) shape;
+
+ ///@todo pass camera, for some culling? no -> we are not a graphics lib
+ btVector3 aabbMax(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT));
+ btVector3 aabbMin(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT));
+
+ DebugDrawcallback drawCallback(getDebugDrawer(),worldTransform,color);
+ concaveMesh->processAllTriangles(&drawCallback,aabbMin,aabbMax);
+
+ }
+
+ if (shape->getShapeType() == CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE)
+ {
+ btConvexTriangleMeshShape* convexMesh = (btConvexTriangleMeshShape*) shape;
+ //todo: pass camera for some culling
+ btVector3 aabbMax(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT));
+ btVector3 aabbMin(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT));
+ //DebugDrawcallback drawCallback;
+ DebugDrawcallback drawCallback(getDebugDrawer(),worldTransform,color);
+ convexMesh->getMeshInterface()->InternalProcessAllTriangles(&drawCallback,aabbMin,aabbMax);
+ }
+
+
+
+ }
+
+ }
+ }
+}
+
+
+void btCollisionWorld::debugDrawWorld()
+{
+ if (getDebugDrawer())
+ {
+ getDebugDrawer()->clearLines();
+
+ btIDebugDraw::DefaultColors defaultColors = getDebugDrawer()->getDefaultColors();
+
+ if ( getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints)
+ {
+
+
+ if (getDispatcher())
+ {
+ int numManifolds = getDispatcher()->getNumManifolds();
+
+ for (int i=0;i<numManifolds;i++)
+ {
+ btPersistentManifold* contactManifold = getDispatcher()->getManifoldByIndexInternal(i);
+ //btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
+ //btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());
+
+ int numContacts = contactManifold->getNumContacts();
+ for (int j=0;j<numContacts;j++)
+ {
+ btManifoldPoint& cp = contactManifold->getContactPoint(j);
+ getDebugDrawer()->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),defaultColors.m_contactPoint);
+ }
+ }
+ }
+ }
+
+ if ((getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb)))
+ {
+ int i;
+
+ for ( i=0;i<m_collisionObjects.size();i++)
+ {
+ btCollisionObject* colObj = m_collisionObjects[i];
+ if ((colObj->getCollisionFlags() & btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT)==0)
+ {
+ if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawWireframe))
+ {
+ btVector3 color(btScalar(0.4),btScalar(0.4),btScalar(0.4));
+
+ switch(colObj->getActivationState())
+ {
+ case ACTIVE_TAG:
+ color = defaultColors.m_activeObject; break;
+ case ISLAND_SLEEPING:
+ color = defaultColors.m_deactivatedObject;break;
+ case WANTS_DEACTIVATION:
+ color = defaultColors.m_wantsDeactivationObject;break;
+ case DISABLE_DEACTIVATION:
+ color = defaultColors.m_disabledDeactivationObject;break;
+ case DISABLE_SIMULATION:
+ color = defaultColors.m_disabledSimulationObject;break;
+ default:
+ {
+ color = btVector3(btScalar(.3),btScalar(0.3),btScalar(0.3));
+ }
+ };
+
+ colObj->getCustomDebugColor(color);
+
+ debugDrawObject(colObj->getWorldTransform(),colObj->getCollisionShape(),color);
+ }
+ if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb))
+ {
+ btVector3 minAabb,maxAabb;
+ btVector3 colorvec = defaultColors.m_aabb;
+ colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb);
+ btVector3 contactThreshold(gContactBreakingThreshold,gContactBreakingThreshold,gContactBreakingThreshold);
+ minAabb -= contactThreshold;
+ maxAabb += contactThreshold;
+
+ btVector3 minAabb2,maxAabb2;
+
+ if(getDispatchInfo().m_useContinuous && colObj->getInternalType()==btCollisionObject::CO_RIGID_BODY && !colObj->isStaticOrKinematicObject())
+ {
+ colObj->getCollisionShape()->getAabb(colObj->getInterpolationWorldTransform(),minAabb2,maxAabb2);
+ minAabb2 -= contactThreshold;
+ maxAabb2 += contactThreshold;
+ minAabb.setMin(minAabb2);
+ maxAabb.setMax(maxAabb2);
+ }
+
+ m_debugDrawer->drawAabb(minAabb,maxAabb,colorvec);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void btCollisionWorld::serializeCollisionObjects(btSerializer* serializer)
+{
+ int i;
+
+ ///keep track of shapes already serialized
+ btHashMap<btHashPtr,btCollisionShape*> serializedShapes;
+
+ for (i=0;i<m_collisionObjects.size();i++)
+ {
+ btCollisionObject* colObj = m_collisionObjects[i];
+ btCollisionShape* shape = colObj->getCollisionShape();
+
+ if (!serializedShapes.find(shape))
+ {
+ serializedShapes.insert(shape,shape);
+ shape->serializeSingleShape(serializer);
+ }
+ }
+
+ //serialize all collision objects
+ for (i=0;i<m_collisionObjects.size();i++)
+ {
+ btCollisionObject* colObj = m_collisionObjects[i];
+ if ((colObj->getInternalType() == btCollisionObject::CO_COLLISION_OBJECT) || (colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK))
+ {
+ colObj->serializeSingleObject(serializer);
+ }
+ }
+}
+
+
+void btCollisionWorld::serialize(btSerializer* serializer)
+{
+
+ serializer->startSerialization();
+
+ serializeCollisionObjects(serializer);
+
+ serializer->finishSerialization();
+}
+