that’s precisely how they want us to use it.legacy
@@ -35,6 +35,7 @@ liblol_a_SOURCES = \ | |||
$(sdl_sources) \ | |||
$(d3d9_sources) \ | |||
$(android_sources) \ | |||
$(bullet_sources) \ | |||
\ | |||
thread/threadbase.h thread/thread.h \ | |||
\ | |||
@@ -60,7 +61,7 @@ liblol_a_SOURCES = \ | |||
debug/fps.cpp debug/fps.h debug/sphere.cpp debug/sphere.h \ | |||
debug/record.cpp debug/record.h debug/stats.cpp debug/stats.h \ | |||
debug/quad.cpp debug/quad.h | |||
liblol_a_CPPFLAGS = @LOL_CFLAGS@ | |||
liblol_a_CPPFLAGS = @LOL_CFLAGS@ -Ibullet | |||
SUFFIXES = .lolfx | |||
.lolfx.o: | |||
@@ -113,3 +114,545 @@ android_sources = \ | |||
image/codec/android-image.cpp \ | |||
platform/android/androidapp.cpp platform/android/androidapp.h | |||
bullet_sources = | |||
if FALSE #CONDITIONAL_BUILD_MULTITHREADED | |||
bullet_sources += \ | |||
bullet/BulletMultiThreaded/PosixThreadSupport.h \ | |||
bullet/BulletMultiThreaded/vectormath/scalar/cpp/mat_aos.h \ | |||
bullet/BulletMultiThreaded/vectormath/scalar/cpp/vec_aos.h \ | |||
bullet/BulletMultiThreaded/vectormath/scalar/cpp/quat_aos.h \ | |||
bullet/BulletMultiThreaded/vectormath/scalar/cpp/vectormath_aos.h \ | |||
bullet/BulletMultiThreaded/PpuAddressSpace.h \ | |||
bullet/BulletMultiThreaded/SpuCollisionTaskProcess.h \ | |||
bullet/BulletMultiThreaded/PlatformDefinitions.h \ | |||
bullet/BulletMultiThreaded/vectormath2bullet.h \ | |||
bullet/BulletMultiThreaded/SpuGatheringCollisionDispatcher.h \ | |||
bullet/BulletMultiThreaded/SpuCollisionObjectWrapper.h \ | |||
bullet/BulletMultiThreaded/SpuSampleTaskProcess.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/boxBoxDistance.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/Box.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPenetrationDepthSolver.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuLocalSupport.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuConvexPenetrationDepthSolver.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuContactResult.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuPreferredPenetrationDirections.h \ | |||
bullet/BulletMultiThreaded/SpuSync.h \ | |||
bullet/BulletMultiThreaded/btThreadSupportInterface.h \ | |||
bullet/BulletMultiThreaded/SpuLibspe2Support.h \ | |||
bullet/BulletMultiThreaded/SpuSampleTask/SpuSampleTask.h \ | |||
bullet/BulletMultiThreaded/SpuFakeDma.h \ | |||
bullet/BulletMultiThreaded/SpuContactManifoldCollisionAlgorithm.h \ | |||
bullet/BulletMultiThreaded/SpuDoubleBuffer.h \ | |||
bullet/BulletMultiThreaded/Win32ThreadSupport.h \ | |||
bullet/BulletMultiThreaded/SequentialThreadSupport.h | |||
libBulletMultiThreaded_la_CXXFLAGS = ${CXXFLAGS} -I./BulletMultiThreaded/vectormath/scalar/cpp | |||
bullet_sources += \ | |||
bullet/BulletMultiThreaded/SpuCollisionObjectWrapper.cpp \ | |||
bullet/BulletMultiThreaded/SpuSampleTask/SpuSampleTask.cpp \ | |||
bullet/BulletMultiThreaded/SpuLibspe2Support.cpp \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuContactResult.cpp \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.cpp \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPenetrationDepthSolver.cpp \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.cpp \ | |||
bullet/BulletMultiThreaded/btThreadSupportInterface.cpp \ | |||
bullet/BulletMultiThreaded/SequentialThreadSupport.cpp \ | |||
bullet/BulletMultiThreaded/SpuGatheringCollisionDispatcher.cpp \ | |||
bullet/BulletMultiThreaded/Win32ThreadSupport.cpp \ | |||
bullet/BulletMultiThreaded/SpuFakeDma.cpp \ | |||
bullet/BulletMultiThreaded/PosixThreadSupport.cpp \ | |||
bullet/BulletMultiThreaded/SpuCollisionTaskProcess.cpp \ | |||
bullet/BulletMultiThreaded/SpuContactManifoldCollisionAlgorithm.cpp \ | |||
bullet/BulletMultiThreaded/SpuSampleTaskProcess.cpp \ | |||
bullet/BulletMultiThreaded/SpuSampleTask/SpuSampleTask.h \ | |||
bullet/BulletMultiThreaded/PpuAddressSpace.h \ | |||
bullet/BulletMultiThreaded/SpuSampleTaskProcess.h \ | |||
bullet/BulletMultiThreaded/SequentialThreadSupport.h \ | |||
bullet/BulletMultiThreaded/PlatformDefinitions.h \ | |||
bullet/BulletMultiThreaded/Win32ThreadSupport.h \ | |||
bullet/BulletMultiThreaded/SpuContactManifoldCollisionAlgorithm.h \ | |||
bullet/BulletMultiThreaded/btThreadSupportInterface.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuConvexPenetrationDepthSolver.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuPreferredPenetrationDirections.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuLocalSupport.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPenetrationDepthSolver.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuContactResult.h \ | |||
bullet/BulletMultiThreaded/SpuGatheringCollisionDispatcher.h \ | |||
bullet/BulletMultiThreaded/SpuFakeDma.h \ | |||
bullet/BulletMultiThreaded/SpuSync.h \ | |||
bullet/BulletMultiThreaded/SpuCollisionObjectWrapper.h \ | |||
bullet/BulletMultiThreaded/SpuDoubleBuffer.h \ | |||
bullet/BulletMultiThreaded/SpuCollisionTaskProcess.h \ | |||
bullet/BulletMultiThreaded/PosixThreadSupport.h \ | |||
bullet/BulletMultiThreaded/SpuLibspe2Support.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/boxBoxDistance.cpp \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/boxBoxDistance.h \ | |||
bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/Box.h | |||
endif | |||
bullet_sources += \ | |||
bullet/LinearMath/btQuickprof.cpp \ | |||
bullet/LinearMath/btGeometryUtil.cpp \ | |||
bullet/LinearMath/btAlignedAllocator.cpp \ | |||
bullet/LinearMath/btSerializer.cpp \ | |||
bullet/LinearMath/btConvexHull.cpp \ | |||
bullet/LinearMath/btConvexHullComputer.cpp \ | |||
bullet/LinearMath/btHashMap.h \ | |||
bullet/LinearMath/btConvexHull.h \ | |||
bullet/LinearMath/btAabbUtil2.h \ | |||
bullet/LinearMath/btGeometryUtil.h \ | |||
bullet/LinearMath/btQuadWord.h \ | |||
bullet/LinearMath/btPoolAllocator.h \ | |||
bullet/LinearMath/btScalar.h \ | |||
bullet/LinearMath/btMinMax.h \ | |||
bullet/LinearMath/btVector3.h \ | |||
bullet/LinearMath/btList.h \ | |||
bullet/LinearMath/btStackAlloc.h \ | |||
bullet/LinearMath/btMatrix3x3.h \ | |||
bullet/LinearMath/btMotionState.h \ | |||
bullet/LinearMath/btAlignedAllocator.h \ | |||
bullet/LinearMath/btQuaternion.h \ | |||
bullet/LinearMath/btAlignedObjectArray.h \ | |||
bullet/LinearMath/btQuickprof.h \ | |||
bullet/LinearMath/btSerializer.h \ | |||
bullet/LinearMath/btTransformUtil.h \ | |||
bullet/LinearMath/btTransform.h \ | |||
bullet/LinearMath/btDefaultMotionState.h \ | |||
bullet/LinearMath/btIDebugDraw.h \ | |||
bullet/LinearMath/btRandom.h | |||
bullet_sources += \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btConvexCast.cpp \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionObject.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btGhostObject.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btManifoldResult.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btUnionFind.cpp \ | |||
bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btTetrahedronShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btShapeHull.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btCompoundShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btConeShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btMultiSphereShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btUniformScalingShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btSphereShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleBuffer.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btEmptyShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btCollisionShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btConvexShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btConvex2dShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btConvexInternalShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btConvexHullShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleCallback.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btCapsuleShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btConcaveShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btBoxShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btBox2dShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btOptimizedBvh.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btCylinderShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleMesh.cpp \ | |||
bullet/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp \ | |||
bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp \ | |||
bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp \ | |||
bullet/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp \ | |||
bullet/BulletCollision/BroadphaseCollision/btDispatcher.cpp \ | |||
bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp \ | |||
bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp \ | |||
bullet/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp \ | |||
bullet/BulletCollision/BroadphaseCollision/btDbvt.cpp \ | |||
bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btConvexCast.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btPointCollector.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionObject.h \ | |||
bullet/BulletCollision/CollisionDispatch/btGhostObject.h \ | |||
bullet/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h \ | |||
bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btBoxBoxDetector.h \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.h \ | |||
bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.h \ | |||
bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btUnionFind.h \ | |||
bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.h \ | |||
bullet/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionWorld.h \ | |||
bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h \ | |||
bullet/BulletCollision/CollisionDispatch/btManifoldResult.h \ | |||
bullet/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionConfiguration.h \ | |||
bullet/BulletCollision/CollisionShapes/btConvexShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btConvex2dShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleCallback.h \ | |||
bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btCompoundShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btBoxShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btBox2dShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btMultiSphereShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btCollisionMargin.h \ | |||
bullet/BulletCollision/CollisionShapes/btConcaveShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btEmptyShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btUniformScalingShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btMaterial.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleInfoMap.h \ | |||
bullet/BulletCollision/CollisionShapes/btSphereShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btConvexPointCloudShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btCapsuleShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btCollisionShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleMeshShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btStridingMeshInterface.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleMesh.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleBuffer.h \ | |||
bullet/BulletCollision/CollisionShapes/btShapeHull.h \ | |||
bullet/BulletCollision/CollisionShapes/btMinkowskiSumShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btOptimizedBvh.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h \ | |||
bullet/BulletCollision/CollisionShapes/btCylinderShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btTetrahedronShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btConvexInternalShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btConeShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btConvexHullShape.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btAxisSweep3.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btDbvt.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btDispatcher.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.h \ | |||
bullet/BulletCollision/Gimpact/btGImpactBvh.cpp\ | |||
bullet/BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp\ | |||
bullet/BulletCollision/Gimpact/btTriangleShapeEx.cpp\ | |||
bullet/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp\ | |||
bullet/BulletCollision/Gimpact/btGImpactShape.cpp\ | |||
bullet/BulletCollision/Gimpact/gim_box_set.cpp\ | |||
bullet/BulletCollision/Gimpact/gim_contact.cpp\ | |||
bullet/BulletCollision/Gimpact/gim_memory.cpp\ | |||
bullet/BulletCollision/Gimpact/gim_tri_collision.cpp | |||
bullet_sources += \ | |||
bullet/BulletDynamics/Dynamics/btRigidBody.cpp \ | |||
bullet/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp \ | |||
bullet/BulletDynamics/Dynamics/Bullet-C-API.cpp \ | |||
bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp \ | |||
bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp \ | |||
bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp \ | |||
bullet/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp \ | |||
bullet/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp \ | |||
bullet/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp \ | |||
bullet/BulletDynamics/ConstraintSolver/btContactConstraint.cpp \ | |||
bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp \ | |||
bullet/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp \ | |||
bullet/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp \ | |||
bullet/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp \ | |||
bullet/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp \ | |||
bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp \ | |||
bullet/BulletDynamics/Vehicle/btWheelInfo.cpp \ | |||
bullet/BulletDynamics/Vehicle/btRaycastVehicle.cpp \ | |||
bullet/BulletDynamics/Character/btKinematicCharacterController.cpp \ | |||
bullet/BulletDynamics/Character/btKinematicCharacterController.h \ | |||
bullet/BulletDynamics/Character/btCharacterControllerInterface.h \ | |||
bullet/BulletDynamics/Dynamics/btActionInterface.h \ | |||
bullet/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h \ | |||
bullet/BulletDynamics/Dynamics/btRigidBody.h \ | |||
bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h \ | |||
bullet/BulletDynamics/Dynamics/btDynamicsWorld.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btSolverBody.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btConstraintSolver.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btTypedConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btContactConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btJacobianEntry.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btSolverConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btHingeConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btHinge2Constraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btUniversalConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btSolve2bullet/LinearConstraint.h \ | |||
bullet/BulletDynamics/Vehicle/btVehicleRaycaster.h \ | |||
bullet/BulletDynamics/Vehicle/btRaycastVehicle.h \ | |||
bullet/BulletDynamics/Vehicle/btWheelInfo.h | |||
bullet_sources += \ | |||
bullet/BulletSoftBody/btDefaultSoftBodySolver.cpp \ | |||
bullet/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp \ | |||
bullet/BulletSoftBody/btSoftBody.cpp \ | |||
bullet/BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp \ | |||
bullet/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp \ | |||
bullet/BulletSoftBody/btSoftRigidDynamicsWorld.cpp \ | |||
bullet/BulletSoftBody/btSoftBodyHelpers.cpp \ | |||
bullet/BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp \ | |||
bullet/BulletSoftBody/btSparseSDF.h \ | |||
bullet/BulletSoftBody/btSoftRigidCollisionAlgorithm.h \ | |||
bullet/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h \ | |||
bullet/BulletSoftBody/btSoftBody.h \ | |||
bullet/BulletSoftBody/btSoftSoftCollisionAlgorithm.h \ | |||
bullet/BulletSoftBody/btSoftBodyInternals.h \ | |||
bullet/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h \ | |||
bullet/BulletSoftBody/btSoftRigidDynamicsWorld.h \ | |||
bullet/BulletSoftBody/btSoftBodyHelpers.h | |||
bullet_sources += \ | |||
bullet/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h \ | |||
bullet/BulletSoftBody/btSoftBodyInternals.h \ | |||
bullet/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h \ | |||
bullet/BulletSoftBody/btSoftSoftCollisionAlgorithm.h \ | |||
bullet/BulletSoftBody/btSoftBody.h \ | |||
bullet/BulletSoftBody/btSoftBodyHelpers.h \ | |||
bullet/BulletSoftBody/btSparseSDF.h \ | |||
bullet/BulletSoftBody/btSoftRigidCollisionAlgorithm.h \ | |||
bullet/BulletSoftBody/btSoftRigidDynamicsWorld.h \ | |||
bullet/BulletDynamics/Vehicle/btRaycastVehicle.h \ | |||
bullet/BulletDynamics/Vehicle/btWheelInfo.h \ | |||
bullet/BulletDynamics/Vehicle/btVehicleRaycaster.h \ | |||
bullet/BulletDynamics/Dynamics/btActionInterface.h \ | |||
bullet/BulletDynamics/Dynamics/btRigidBody.h \ | |||
bullet/BulletDynamics/Dynamics/btDynamicsWorld.h \ | |||
bullet/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h \ | |||
bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btSolverConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btTypedConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btConstraintSolver.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btContactConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btJacobianEntry.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btSolve2bullet/LinearConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btHingeConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btHinge2Constraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btUniversalConstraint.h \ | |||
bullet/BulletDynamics/ConstraintSolver/btSolverBody.h \ | |||
bullet/BulletDynamics/Character/btCharacterControllerInterface.h \ | |||
bullet/BulletDynamics/Character/btKinematicCharacterController.h \ | |||
bullet/BulletCollision/CollisionShapes/btShapeHull.h \ | |||
bullet/BulletCollision/CollisionShapes/btConcaveShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btCollisionMargin.h \ | |||
bullet/BulletCollision/CollisionShapes/btCompoundShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btConvexHullShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btCylinderShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleMesh.h \ | |||
bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btUniformScalingShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btConvexPointCloudShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btTetrahedronShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btCapsuleShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btSphereShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btMultiSphereShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btConvexInternalShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btStridingMeshInterface.h \ | |||
bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btEmptyShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btOptimizedBvh.h \ | |||
bullet/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleCallback.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleInfoMap.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleBuffer.h \ | |||
bullet/BulletCollision/CollisionShapes/btConvexShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btConvex2dShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btConeShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btCollisionShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btBoxShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btBox2dShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btMinkowskiSumShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btTriangleMeshShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btMaterial.h \ | |||
bullet/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h \ | |||
bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btConvexCast.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btPointCollector.h \ | |||
bullet/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btDbvt.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btDispatcher.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btAxisSweep3.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h \ | |||
bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h \ | |||
bullet/BulletCollision/CollisionDispatch/btUnionFind.h \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionConfiguration.h \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.h \ | |||
bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.h \ | |||
bullet/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionWorld.h \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h \ | |||
bullet/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btCollisionObject.h \ | |||
bullet/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h \ | |||
bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btGhostObject.h \ | |||
bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.h \ | |||
bullet/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btBoxBoxDetector.h \ | |||
bullet/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h \ | |||
bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h \ | |||
bullet/BulletCollision/CollisionDispatch/btManifoldResult.h \ | |||
bullet/BulletCollision/Gimpact/gim_memory.h \ | |||
bullet/BulletCollision/Gimpact/gim_clip_polygon.h \ | |||
bullet/BulletCollision/Gimpact/gim_bitset.h \ | |||
bullet/BulletCollision/Gimpact/gim_linear_math.h \ | |||
bullet/BulletCollision/Gimpact/btGeometryOperations.h \ | |||
bullet/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h \ | |||
bullet/BulletCollision/Gimpact/btGImpactBvh.h \ | |||
bullet/BulletCollision/Gimpact/gim_box_set.h \ | |||
bullet/BulletCollision/Gimpact/gim_array.h \ | |||
bullet/BulletCollision/Gimpact/btGImpactShape.h \ | |||
bullet/BulletCollision/Gimpact/btTriangleShapeEx.h \ | |||
bullet/BulletCollision/Gimpact/btClipPolygon.h \ | |||
bullet/BulletCollision/Gimpact/gim_box_collision.h \ | |||
bullet/BulletCollision/Gimpact/gim_tri_collision.h \ | |||
bullet/BulletCollision/Gimpact/gim_geometry.h \ | |||
bullet/BulletCollision/Gimpact/gim_math.h \ | |||
bullet/BulletCollision/Gimpact/btQuantization.h \ | |||
bullet/BulletCollision/Gimpact/btGImpactQuantizedBvh.h \ | |||
bullet/BulletCollision/Gimpact/gim_geom_types.h \ | |||
bullet/BulletCollision/Gimpact/gim_basic_geometry_operations.h \ | |||
bullet/BulletCollision/Gimpact/gim_contact.h \ | |||
bullet/BulletCollision/Gimpact/gim_hash_table.h \ | |||
bullet/BulletCollision/Gimpact/gim_radixsort.h \ | |||
bullet/BulletCollision/Gimpact/btGImpactMassUtil.h \ | |||
bullet/BulletCollision/Gimpact/btGenericPoolAllocator.h \ | |||
bullet/BulletCollision/Gimpact/btBoxCollision.h \ | |||
bullet/BulletCollision/Gimpact/btContactProcessing.h \ | |||
bullet/LinearMath/btGeometryUtil.h \ | |||
bullet/LinearMath/btConvexHull.h \ | |||
bullet/LinearMath/btList.h \ | |||
bullet/LinearMath/btMatrix3x3.h \ | |||
bullet/LinearMath/btVector3.h \ | |||
bullet/LinearMath/btPoolAllocator.h \ | |||
bullet/LinearMath/btScalar.h \ | |||
bullet/LinearMath/btDefaultMotionState.h \ | |||
bullet/LinearMath/btTransform.h \ | |||
bullet/LinearMath/btQuadWord.h \ | |||
bullet/LinearMath/btAabbUtil2.h \ | |||
bullet/LinearMath/btTransformUtil.h \ | |||
bullet/LinearMath/btRandom.h \ | |||
bullet/LinearMath/btQuaternion.h \ | |||
bullet/LinearMath/btMinMax.h \ | |||
bullet/LinearMath/btMotionState.h \ | |||
bullet/LinearMath/btIDebugDraw.h \ | |||
bullet/LinearMath/btAlignedAllocator.h \ | |||
bullet/LinearMath/btStackAlloc.h \ | |||
bullet/LinearMath/btAlignedObjectArray.h \ | |||
bullet/LinearMath/btHashMap.h \ | |||
bullet/LinearMath/btQuickprof.h\ | |||
bullet/LinearMath/btSerializer.h | |||
@@ -0,0 +1,176 @@ | |||
/* | |||
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. | |||
*/ | |||
/* | |||
Draft high-level generic physics C-API. For low-level access, use the physics SDK native API's. | |||
Work in progress, functionality will be added on demand. | |||
If possible, use the richer Bullet C++ API, by including "btBulletDynamicsCommon.h" | |||
*/ | |||
#ifndef BULLET_C_API_H | |||
#define BULLET_C_API_H | |||
#define PL_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name | |||
#ifdef BT_USE_DOUBLE_PRECISION | |||
typedef double plReal; | |||
#else | |||
typedef float plReal; | |||
#endif | |||
typedef plReal plVector3[3]; | |||
typedef plReal plQuaternion[4]; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** Particular physics SDK (C-API) */ | |||
PL_DECLARE_HANDLE(plPhysicsSdkHandle); | |||
/** Dynamics world, belonging to some physics SDK (C-API)*/ | |||
PL_DECLARE_HANDLE(plDynamicsWorldHandle); | |||
/** Rigid Body that can be part of a Dynamics World (C-API)*/ | |||
PL_DECLARE_HANDLE(plRigidBodyHandle); | |||
/** Collision Shape/Geometry, property of a Rigid Body (C-API)*/ | |||
PL_DECLARE_HANDLE(plCollisionShapeHandle); | |||
/** Constraint for Rigid Bodies (C-API)*/ | |||
PL_DECLARE_HANDLE(plConstraintHandle); | |||
/** Triangle Mesh interface (C-API)*/ | |||
PL_DECLARE_HANDLE(plMeshInterfaceHandle); | |||
/** Broadphase Scene/Proxy Handles (C-API)*/ | |||
PL_DECLARE_HANDLE(plCollisionBroadphaseHandle); | |||
PL_DECLARE_HANDLE(plBroadphaseProxyHandle); | |||
PL_DECLARE_HANDLE(plCollisionWorldHandle); | |||
/** | |||
Create and Delete a Physics SDK | |||
*/ | |||
extern plPhysicsSdkHandle plNewBulletSdk(void); //this could be also another sdk, like ODE, PhysX etc. | |||
extern void plDeletePhysicsSdk(plPhysicsSdkHandle physicsSdk); | |||
/** Collision World, not strictly necessary, you can also just create a Dynamics World with Rigid Bodies which internally manages the Collision World with Collision Objects */ | |||
typedef void(*btBroadphaseCallback)(void* clientData, void* object1,void* object2); | |||
extern plCollisionBroadphaseHandle plCreateSapBroadphase(btBroadphaseCallback beginCallback,btBroadphaseCallback endCallback); | |||
extern void plDestroyBroadphase(plCollisionBroadphaseHandle bp); | |||
extern plBroadphaseProxyHandle plCreateProxy(plCollisionBroadphaseHandle bp, void* clientData, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ); | |||
extern void plDestroyProxy(plCollisionBroadphaseHandle bp, plBroadphaseProxyHandle proxyHandle); | |||
extern void plSetBoundingBox(plBroadphaseProxyHandle proxyHandle, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ); | |||
/* todo: add pair cache support with queries like add/remove/find pair */ | |||
extern plCollisionWorldHandle plCreateCollisionWorld(plPhysicsSdkHandle physicsSdk); | |||
/* todo: add/remove objects */ | |||
/* Dynamics World */ | |||
extern plDynamicsWorldHandle plCreateDynamicsWorld(plPhysicsSdkHandle physicsSdk); | |||
extern void plDeleteDynamicsWorld(plDynamicsWorldHandle world); | |||
extern void plStepSimulation(plDynamicsWorldHandle, plReal timeStep); | |||
extern void plAddRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object); | |||
extern void plRemoveRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object); | |||
/* Rigid Body */ | |||
extern plRigidBodyHandle plCreateRigidBody( void* user_data, float mass, plCollisionShapeHandle cshape ); | |||
extern void plDeleteRigidBody(plRigidBodyHandle body); | |||
/* Collision Shape definition */ | |||
extern plCollisionShapeHandle plNewSphereShape(plReal radius); | |||
extern plCollisionShapeHandle plNewBoxShape(plReal x, plReal y, plReal z); | |||
extern plCollisionShapeHandle plNewCapsuleShape(plReal radius, plReal height); | |||
extern plCollisionShapeHandle plNewConeShape(plReal radius, plReal height); | |||
extern plCollisionShapeHandle plNewCylinderShape(plReal radius, plReal height); | |||
extern plCollisionShapeHandle plNewCompoundShape(void); | |||
extern void plAddChildShape(plCollisionShapeHandle compoundShape,plCollisionShapeHandle childShape, plVector3 childPos,plQuaternion childOrn); | |||
extern void plDeleteShape(plCollisionShapeHandle shape); | |||
/* Convex Meshes */ | |||
extern plCollisionShapeHandle plNewConvexHullShape(void); | |||
extern void plAddVertex(plCollisionShapeHandle convexHull, plReal x,plReal y,plReal z); | |||
/* Concave static triangle meshes */ | |||
extern plMeshInterfaceHandle plNewMeshInterface(void); | |||
extern void plAddTriangle(plMeshInterfaceHandle meshHandle, plVector3 v0,plVector3 v1,plVector3 v2); | |||
extern plCollisionShapeHandle plNewStaticTriangleMeshShape(plMeshInterfaceHandle); | |||
extern void plSetScaling(plCollisionShapeHandle shape, plVector3 scaling); | |||
/* SOLID has Response Callback/Table/Management */ | |||
/* PhysX has Triggers, User Callbacks and filtering */ | |||
/* ODE has the typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); */ | |||
/* typedef void plUpdatedPositionCallback(void* userData, plRigidBodyHandle rbHandle, plVector3 pos); */ | |||
/* typedef void plUpdatedOrientationCallback(void* userData, plRigidBodyHandle rbHandle, plQuaternion orientation); */ | |||
/* get world transform */ | |||
extern void plGetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix); | |||
extern void plGetPosition(plRigidBodyHandle object,plVector3 position); | |||
extern void plGetOrientation(plRigidBodyHandle object,plQuaternion orientation); | |||
/* set world transform (position/orientation) */ | |||
extern void plSetPosition(plRigidBodyHandle object, const plVector3 position); | |||
extern void plSetOrientation(plRigidBodyHandle object, const plQuaternion orientation); | |||
extern void plSetEuler(plReal yaw,plReal pitch,plReal roll, plQuaternion orient); | |||
extern void plSetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix); | |||
typedef struct plRayCastResult { | |||
plRigidBodyHandle m_body; | |||
plCollisionShapeHandle m_shape; | |||
plVector3 m_positionWorld; | |||
plVector3 m_normalWorld; | |||
} plRayCastResult; | |||
extern int plRayCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plRayCastResult res); | |||
/* Sweep API */ | |||
/* extern plRigidBodyHandle plObjectCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plVector3 hitpoint, plVector3 normal); */ | |||
/* Continuous Collision Detection API */ | |||
// needed for source/blender/blenkernel/intern/collision.c | |||
double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float q2[3], float q3[3], float *pa, float *pb, float normal[3]); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif //BULLET_C_API_H | |||
@@ -0,0 +1,37 @@ | |||
//Bullet Continuous Collision Detection and Physics Library | |||
//Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
// | |||
// btAxisSweep3 | |||
// | |||
// Copyright (c) 2006 Simon Hobbs | |||
// | |||
// 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 "btAxisSweep3.h" | |||
btAxisSweep3::btAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned short int maxHandles, btOverlappingPairCache* pairCache, bool disableRaycastAccelerator) | |||
:btAxisSweep3Internal<unsigned short int>(worldAabbMin,worldAabbMax,0xfffe,0xffff,maxHandles,pairCache,disableRaycastAccelerator) | |||
{ | |||
// 1 handle is reserved as sentinel | |||
btAssert(maxHandles > 1 && maxHandles < 32767); | |||
} | |||
bt32BitAxisSweep3::bt32BitAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned int maxHandles , btOverlappingPairCache* pairCache , bool disableRaycastAccelerator) | |||
:btAxisSweep3Internal<unsigned int>(worldAabbMin,worldAabbMax,0xfffffffe,0x7fffffff,maxHandles,pairCache,disableRaycastAccelerator) | |||
{ | |||
// 1 handle is reserved as sentinel | |||
btAssert(maxHandles > 1 && maxHandles < 2147483647); | |||
} |
@@ -0,0 +1,82 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_BROADPHASE_INTERFACE_H | |||
#define BT_BROADPHASE_INTERFACE_H | |||
struct btDispatcherInfo; | |||
class btDispatcher; | |||
#include "btBroadphaseProxy.h" | |||
class btOverlappingPairCache; | |||
struct btBroadphaseAabbCallback | |||
{ | |||
virtual ~btBroadphaseAabbCallback() {} | |||
virtual bool process(const btBroadphaseProxy* proxy) = 0; | |||
}; | |||
struct btBroadphaseRayCallback : public btBroadphaseAabbCallback | |||
{ | |||
///added some cached data to accelerate ray-AABB tests | |||
btVector3 m_rayDirectionInverse; | |||
unsigned int m_signs[3]; | |||
btScalar m_lambda_max; | |||
virtual ~btBroadphaseRayCallback() {} | |||
}; | |||
#include "LinearMath/btVector3.h" | |||
///The btBroadphaseInterface class provides an interface to detect aabb-overlapping object pairs. | |||
///Some implementations for this broadphase interface include btAxisSweep3, bt32BitAxisSweep3 and btDbvtBroadphase. | |||
///The actual overlapping pair management, storage, adding and removing of pairs is dealt by the btOverlappingPairCache class. | |||
class btBroadphaseInterface | |||
{ | |||
public: | |||
virtual ~btBroadphaseInterface() {} | |||
virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy) =0; | |||
virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher)=0; | |||
virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher)=0; | |||
virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const =0; | |||
virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0), const btVector3& aabbMax = btVector3(0,0,0)) = 0; | |||
virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) = 0; | |||
///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb | |||
virtual void calculateOverlappingPairs(btDispatcher* dispatcher)=0; | |||
virtual btOverlappingPairCache* getOverlappingPairCache()=0; | |||
virtual const btOverlappingPairCache* getOverlappingPairCache() const =0; | |||
///getAabb returns the axis aligned bounding box in the 'global' coordinate frame | |||
///will add some transform later | |||
virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const =0; | |||
///reset broadphase internal structures, to ensure determinism/reproducability | |||
virtual void resetPool(btDispatcher* dispatcher) { (void) dispatcher; }; | |||
virtual void printStats() = 0; | |||
}; | |||
#endif //BT_BROADPHASE_INTERFACE_H |
@@ -0,0 +1,17 @@ | |||
/* | |||
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 "btBroadphaseProxy.h" | |||
@@ -0,0 +1,270 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_BROADPHASE_PROXY_H | |||
#define BT_BROADPHASE_PROXY_H | |||
#include "LinearMath/btScalar.h" //for SIMD_FORCE_INLINE | |||
#include "LinearMath/btVector3.h" | |||
#include "LinearMath/btAlignedAllocator.h" | |||
/// btDispatcher uses these types | |||
/// IMPORTANT NOTE:The types are ordered polyhedral, implicit convex and concave | |||
/// to facilitate type checking | |||
/// CUSTOM_POLYHEDRAL_SHAPE_TYPE,CUSTOM_CONVEX_SHAPE_TYPE and CUSTOM_CONCAVE_SHAPE_TYPE can be used to extend Bullet without modifying source code | |||
enum BroadphaseNativeTypes | |||
{ | |||
// polyhedral convex shapes | |||
BOX_SHAPE_PROXYTYPE, | |||
TRIANGLE_SHAPE_PROXYTYPE, | |||
TETRAHEDRAL_SHAPE_PROXYTYPE, | |||
CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE, | |||
CONVEX_HULL_SHAPE_PROXYTYPE, | |||
CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE, | |||
CUSTOM_POLYHEDRAL_SHAPE_TYPE, | |||
//implicit convex shapes | |||
IMPLICIT_CONVEX_SHAPES_START_HERE, | |||
SPHERE_SHAPE_PROXYTYPE, | |||
MULTI_SPHERE_SHAPE_PROXYTYPE, | |||
CAPSULE_SHAPE_PROXYTYPE, | |||
CONE_SHAPE_PROXYTYPE, | |||
CONVEX_SHAPE_PROXYTYPE, | |||
CYLINDER_SHAPE_PROXYTYPE, | |||
UNIFORM_SCALING_SHAPE_PROXYTYPE, | |||
MINKOWSKI_SUM_SHAPE_PROXYTYPE, | |||
MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE, | |||
BOX_2D_SHAPE_PROXYTYPE, | |||
CONVEX_2D_SHAPE_PROXYTYPE, | |||
CUSTOM_CONVEX_SHAPE_TYPE, | |||
//concave shapes | |||
CONCAVE_SHAPES_START_HERE, | |||
//keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy! | |||
TRIANGLE_MESH_SHAPE_PROXYTYPE, | |||
SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE, | |||
///used for demo integration FAST/Swift collision library and Bullet | |||
FAST_CONCAVE_MESH_PROXYTYPE, | |||
//terrain | |||
TERRAIN_SHAPE_PROXYTYPE, | |||
///Used for GIMPACT Trimesh integration | |||
GIMPACT_SHAPE_PROXYTYPE, | |||
///Multimaterial mesh | |||
MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE, | |||
EMPTY_SHAPE_PROXYTYPE, | |||
STATIC_PLANE_PROXYTYPE, | |||
CUSTOM_CONCAVE_SHAPE_TYPE, | |||
CONCAVE_SHAPES_END_HERE, | |||
COMPOUND_SHAPE_PROXYTYPE, | |||
SOFTBODY_SHAPE_PROXYTYPE, | |||
HFFLUID_SHAPE_PROXYTYPE, | |||
HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE, | |||
INVALID_SHAPE_PROXYTYPE, | |||
MAX_BROADPHASE_COLLISION_TYPES | |||
}; | |||
///The btBroadphaseProxy is the main class that can be used with the Bullet broadphases. | |||
///It stores collision shape type information, collision filter information and a client object, typically a btCollisionObject or btRigidBody. | |||
ATTRIBUTE_ALIGNED16(struct) btBroadphaseProxy | |||
{ | |||
BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
///optional filtering to cull potential collisions | |||
enum CollisionFilterGroups | |||
{ | |||
DefaultFilter = 1, | |||
StaticFilter = 2, | |||
KinematicFilter = 4, | |||
DebrisFilter = 8, | |||
SensorTrigger = 16, | |||
CharacterFilter = 32, | |||
AllFilter = -1 //all bits sets: DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger | |||
}; | |||
//Usually the client btCollisionObject or Rigidbody class | |||
void* m_clientObject; | |||
short int m_collisionFilterGroup; | |||
short int m_collisionFilterMask; | |||
void* m_multiSapParentProxy; | |||
int m_uniqueId;//m_uniqueId is introduced for paircache. could get rid of this, by calculating the address offset etc. | |||
btVector3 m_aabbMin; | |||
btVector3 m_aabbMax; | |||
SIMD_FORCE_INLINE int getUid() const | |||
{ | |||
return m_uniqueId; | |||
} | |||
//used for memory pools | |||
btBroadphaseProxy() :m_clientObject(0),m_multiSapParentProxy(0) | |||
{ | |||
} | |||
btBroadphaseProxy(const btVector3& aabbMin,const btVector3& aabbMax,void* userPtr,short int collisionFilterGroup, short int collisionFilterMask,void* multiSapParentProxy=0) | |||
:m_clientObject(userPtr), | |||
m_collisionFilterGroup(collisionFilterGroup), | |||
m_collisionFilterMask(collisionFilterMask), | |||
m_aabbMin(aabbMin), | |||
m_aabbMax(aabbMax) | |||
{ | |||
m_multiSapParentProxy = multiSapParentProxy; | |||
} | |||
static SIMD_FORCE_INLINE bool isPolyhedral(int proxyType) | |||
{ | |||
return (proxyType < IMPLICIT_CONVEX_SHAPES_START_HERE); | |||
} | |||
static SIMD_FORCE_INLINE bool isConvex(int proxyType) | |||
{ | |||
return (proxyType < CONCAVE_SHAPES_START_HERE); | |||
} | |||
static SIMD_FORCE_INLINE bool isNonMoving(int proxyType) | |||
{ | |||
return (isConcave(proxyType) && !(proxyType==GIMPACT_SHAPE_PROXYTYPE)); | |||
} | |||
static SIMD_FORCE_INLINE bool isConcave(int proxyType) | |||
{ | |||
return ((proxyType > CONCAVE_SHAPES_START_HERE) && | |||
(proxyType < CONCAVE_SHAPES_END_HERE)); | |||
} | |||
static SIMD_FORCE_INLINE bool isCompound(int proxyType) | |||
{ | |||
return (proxyType == COMPOUND_SHAPE_PROXYTYPE); | |||
} | |||
static SIMD_FORCE_INLINE bool isSoftBody(int proxyType) | |||
{ | |||
return (proxyType == SOFTBODY_SHAPE_PROXYTYPE); | |||
} | |||
static SIMD_FORCE_INLINE bool isInfinite(int proxyType) | |||
{ | |||
return (proxyType == STATIC_PLANE_PROXYTYPE); | |||
} | |||
static SIMD_FORCE_INLINE bool isConvex2d(int proxyType) | |||
{ | |||
return (proxyType == BOX_2D_SHAPE_PROXYTYPE) || (proxyType == CONVEX_2D_SHAPE_PROXYTYPE); | |||
} | |||
} | |||
; | |||
class btCollisionAlgorithm; | |||
struct btBroadphaseProxy; | |||
///The btBroadphasePair class contains a pair of aabb-overlapping objects. | |||
///A btDispatcher can search a btCollisionAlgorithm that performs exact/narrowphase collision detection on the actual collision shapes. | |||
ATTRIBUTE_ALIGNED16(struct) btBroadphasePair | |||
{ | |||
btBroadphasePair () | |||
: | |||
m_pProxy0(0), | |||
m_pProxy1(0), | |||
m_algorithm(0), | |||
m_internalInfo1(0) | |||
{ | |||
} | |||
BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
btBroadphasePair(const btBroadphasePair& other) | |||
: m_pProxy0(other.m_pProxy0), | |||
m_pProxy1(other.m_pProxy1), | |||
m_algorithm(other.m_algorithm), | |||
m_internalInfo1(other.m_internalInfo1) | |||
{ | |||
} | |||
btBroadphasePair(btBroadphaseProxy& proxy0,btBroadphaseProxy& proxy1) | |||
{ | |||
//keep them sorted, so the std::set operations work | |||
if (proxy0.m_uniqueId < proxy1.m_uniqueId) | |||
{ | |||
m_pProxy0 = &proxy0; | |||
m_pProxy1 = &proxy1; | |||
} | |||
else | |||
{ | |||
m_pProxy0 = &proxy1; | |||
m_pProxy1 = &proxy0; | |||
} | |||
m_algorithm = 0; | |||
m_internalInfo1 = 0; | |||
} | |||
btBroadphaseProxy* m_pProxy0; | |||
btBroadphaseProxy* m_pProxy1; | |||
mutable btCollisionAlgorithm* m_algorithm; | |||
union { void* m_internalInfo1; int m_internalTmpValue;};//don't use this data, it will be removed in future version. | |||
}; | |||
/* | |||
//comparison for set operation, see Solid DT_Encounter | |||
SIMD_FORCE_INLINE bool operator<(const btBroadphasePair& a, const btBroadphasePair& b) | |||
{ | |||
return a.m_pProxy0 < b.m_pProxy0 || | |||
(a.m_pProxy0 == b.m_pProxy0 && a.m_pProxy1 < b.m_pProxy1); | |||
} | |||
*/ | |||
class btBroadphasePairSortPredicate | |||
{ | |||
public: | |||
bool operator() ( const btBroadphasePair& a, const btBroadphasePair& b ) const | |||
{ | |||
const int uidA0 = a.m_pProxy0 ? a.m_pProxy0->m_uniqueId : -1; | |||
const int uidB0 = b.m_pProxy0 ? b.m_pProxy0->m_uniqueId : -1; | |||
const int uidA1 = a.m_pProxy1 ? a.m_pProxy1->m_uniqueId : -1; | |||
const int uidB1 = b.m_pProxy1 ? b.m_pProxy1->m_uniqueId : -1; | |||
return uidA0 > uidB0 || | |||
(a.m_pProxy0 == b.m_pProxy0 && uidA1 > uidB1) || | |||
(a.m_pProxy0 == b.m_pProxy0 && a.m_pProxy1 == b.m_pProxy1 && a.m_algorithm > b.m_algorithm); | |||
} | |||
}; | |||
SIMD_FORCE_INLINE bool operator==(const btBroadphasePair& a, const btBroadphasePair& b) | |||
{ | |||
return (a.m_pProxy0 == b.m_pProxy0) && (a.m_pProxy1 == b.m_pProxy1); | |||
} | |||
#endif //BT_BROADPHASE_PROXY_H | |||
@@ -0,0 +1,23 @@ | |||
/* | |||
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 "btCollisionAlgorithm.h" | |||
#include "btDispatcher.h" | |||
btCollisionAlgorithm::btCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) | |||
{ | |||
m_dispatcher = ci.m_dispatcher1; | |||
} | |||
@@ -0,0 +1,80 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_COLLISION_ALGORITHM_H | |||
#define BT_COLLISION_ALGORITHM_H | |||
#include "LinearMath/btScalar.h" | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
struct btBroadphaseProxy; | |||
class btDispatcher; | |||
class btManifoldResult; | |||
class btCollisionObject; | |||
struct btDispatcherInfo; | |||
class btPersistentManifold; | |||
typedef btAlignedObjectArray<btPersistentManifold*> btManifoldArray; | |||
struct btCollisionAlgorithmConstructionInfo | |||
{ | |||
btCollisionAlgorithmConstructionInfo() | |||
:m_dispatcher1(0), | |||
m_manifold(0) | |||
{ | |||
} | |||
btCollisionAlgorithmConstructionInfo(btDispatcher* dispatcher,int temp) | |||
:m_dispatcher1(dispatcher) | |||
{ | |||
(void)temp; | |||
} | |||
btDispatcher* m_dispatcher1; | |||
btPersistentManifold* m_manifold; | |||
// int getDispatcherId(); | |||
}; | |||
///btCollisionAlgorithm is an collision interface that is compatible with the Broadphase and btDispatcher. | |||
///It is persistent over frames | |||
class btCollisionAlgorithm | |||
{ | |||
protected: | |||
btDispatcher* m_dispatcher; | |||
protected: | |||
// int getDispatcherId(); | |||
public: | |||
btCollisionAlgorithm() {}; | |||
btCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci); | |||
virtual ~btCollisionAlgorithm() {}; | |||
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) = 0; | |||
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) = 0; | |||
virtual void getAllContactManifolds(btManifoldArray& manifoldArray) = 0; | |||
}; | |||
#endif //BT_COLLISION_ALGORITHM_H |
@@ -0,0 +1,796 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
///btDbvtBroadphase implementation by Nathanael Presson | |||
#include "btDbvtBroadphase.h" | |||
// | |||
// Profiling | |||
// | |||
#if DBVT_BP_PROFILE||DBVT_BP_ENABLE_BENCHMARK | |||
#include <stdio.h> | |||
#endif | |||
#if DBVT_BP_PROFILE | |||
struct ProfileScope | |||
{ | |||
__forceinline ProfileScope(btClock& clock,unsigned long& value) : | |||
m_clock(&clock),m_value(&value),m_base(clock.getTimeMicroseconds()) | |||
{ | |||
} | |||
__forceinline ~ProfileScope() | |||
{ | |||
(*m_value)+=m_clock->getTimeMicroseconds()-m_base; | |||
} | |||
btClock* m_clock; | |||
unsigned long* m_value; | |||
unsigned long m_base; | |||
}; | |||
#define SPC(_value_) ProfileScope spc_scope(m_clock,_value_) | |||
#else | |||
#define SPC(_value_) | |||
#endif | |||
// | |||
// Helpers | |||
// | |||
// | |||
template <typename T> | |||
static inline void listappend(T* item,T*& list) | |||
{ | |||
item->links[0]=0; | |||
item->links[1]=list; | |||
if(list) list->links[0]=item; | |||
list=item; | |||
} | |||
// | |||
template <typename T> | |||
static inline void listremove(T* item,T*& list) | |||
{ | |||
if(item->links[0]) item->links[0]->links[1]=item->links[1]; else list=item->links[1]; | |||
if(item->links[1]) item->links[1]->links[0]=item->links[0]; | |||
} | |||
// | |||
template <typename T> | |||
static inline int listcount(T* root) | |||
{ | |||
int n=0; | |||
while(root) { ++n;root=root->links[1]; } | |||
return(n); | |||
} | |||
// | |||
template <typename T> | |||
static inline void clear(T& value) | |||
{ | |||
static const struct ZeroDummy : T {} zerodummy; | |||
value=zerodummy; | |||
} | |||
// | |||
// Colliders | |||
// | |||
/* Tree collider */ | |||
struct btDbvtTreeCollider : btDbvt::ICollide | |||
{ | |||
btDbvtBroadphase* pbp; | |||
btDbvtProxy* proxy; | |||
btDbvtTreeCollider(btDbvtBroadphase* p) : pbp(p) {} | |||
void Process(const btDbvtNode* na,const btDbvtNode* nb) | |||
{ | |||
if(na!=nb) | |||
{ | |||
btDbvtProxy* pa=(btDbvtProxy*)na->data; | |||
btDbvtProxy* pb=(btDbvtProxy*)nb->data; | |||
#if DBVT_BP_SORTPAIRS | |||
if(pa->m_uniqueId>pb->m_uniqueId) | |||
btSwap(pa,pb); | |||
#endif | |||
pbp->m_paircache->addOverlappingPair(pa,pb); | |||
++pbp->m_newpairs; | |||
} | |||
} | |||
void Process(const btDbvtNode* n) | |||
{ | |||
Process(n,proxy->leaf); | |||
} | |||
}; | |||
// | |||
// btDbvtBroadphase | |||
// | |||
// | |||
btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache* paircache) | |||
{ | |||
m_deferedcollide = false; | |||
m_needcleanup = true; | |||
m_releasepaircache = (paircache!=0)?false:true; | |||
m_prediction = 0; | |||
m_stageCurrent = 0; | |||
m_fixedleft = 0; | |||
m_fupdates = 1; | |||
m_dupdates = 0; | |||
m_cupdates = 10; | |||
m_newpairs = 1; | |||
m_updates_call = 0; | |||
m_updates_done = 0; | |||
m_updates_ratio = 0; | |||
m_paircache = paircache? paircache : new(btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache(); | |||
m_gid = 0; | |||
m_pid = 0; | |||
m_cid = 0; | |||
for(int i=0;i<=STAGECOUNT;++i) | |||
{ | |||
m_stageRoots[i]=0; | |||
} | |||
#if DBVT_BP_PROFILE | |||
clear(m_profiling); | |||
#endif | |||
} | |||
// | |||
btDbvtBroadphase::~btDbvtBroadphase() | |||
{ | |||
if(m_releasepaircache) | |||
{ | |||
m_paircache->~btOverlappingPairCache(); | |||
btAlignedFree(m_paircache); | |||
} | |||
} | |||
// | |||
btBroadphaseProxy* btDbvtBroadphase::createProxy( const btVector3& aabbMin, | |||
const btVector3& aabbMax, | |||
int /*shapeType*/, | |||
void* userPtr, | |||
short int collisionFilterGroup, | |||
short int collisionFilterMask, | |||
btDispatcher* /*dispatcher*/, | |||
void* /*multiSapProxy*/) | |||
{ | |||
btDbvtProxy* proxy=new(btAlignedAlloc(sizeof(btDbvtProxy),16)) btDbvtProxy( aabbMin,aabbMax,userPtr, | |||
collisionFilterGroup, | |||
collisionFilterMask); | |||
btDbvtAabbMm aabb = btDbvtVolume::FromMM(aabbMin,aabbMax); | |||
//bproxy->aabb = btDbvtVolume::FromMM(aabbMin,aabbMax); | |||
proxy->stage = m_stageCurrent; | |||
proxy->m_uniqueId = ++m_gid; | |||
proxy->leaf = m_sets[0].insert(aabb,proxy); | |||
listappend(proxy,m_stageRoots[m_stageCurrent]); | |||
if(!m_deferedcollide) | |||
{ | |||
btDbvtTreeCollider collider(this); | |||
collider.proxy=proxy; | |||
m_sets[0].collideTV(m_sets[0].m_root,aabb,collider); | |||
m_sets[1].collideTV(m_sets[1].m_root,aabb,collider); | |||
} | |||
return(proxy); | |||
} | |||
// | |||
void btDbvtBroadphase::destroyProxy( btBroadphaseProxy* absproxy, | |||
btDispatcher* dispatcher) | |||
{ | |||
btDbvtProxy* proxy=(btDbvtProxy*)absproxy; | |||
if(proxy->stage==STAGECOUNT) | |||
m_sets[1].remove(proxy->leaf); | |||
else | |||
m_sets[0].remove(proxy->leaf); | |||
listremove(proxy,m_stageRoots[proxy->stage]); | |||
m_paircache->removeOverlappingPairsContainingProxy(proxy,dispatcher); | |||
btAlignedFree(proxy); | |||
m_needcleanup=true; | |||
} | |||
void btDbvtBroadphase::getAabb(btBroadphaseProxy* absproxy,btVector3& aabbMin, btVector3& aabbMax ) const | |||
{ | |||
btDbvtProxy* proxy=(btDbvtProxy*)absproxy; | |||
aabbMin = proxy->m_aabbMin; | |||
aabbMax = proxy->m_aabbMax; | |||
} | |||
struct BroadphaseRayTester : btDbvt::ICollide | |||
{ | |||
btBroadphaseRayCallback& m_rayCallback; | |||
BroadphaseRayTester(btBroadphaseRayCallback& orgCallback) | |||
:m_rayCallback(orgCallback) | |||
{ | |||
} | |||
void Process(const btDbvtNode* leaf) | |||
{ | |||
btDbvtProxy* proxy=(btDbvtProxy*)leaf->data; | |||
m_rayCallback.process(proxy); | |||
} | |||
}; | |||
void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin,const btVector3& aabbMax) | |||
{ | |||
BroadphaseRayTester callback(rayCallback); | |||
m_sets[0].rayTestInternal( m_sets[0].m_root, | |||
rayFrom, | |||
rayTo, | |||
rayCallback.m_rayDirectionInverse, | |||
rayCallback.m_signs, | |||
rayCallback.m_lambda_max, | |||
aabbMin, | |||
aabbMax, | |||
callback); | |||
m_sets[1].rayTestInternal( m_sets[1].m_root, | |||
rayFrom, | |||
rayTo, | |||
rayCallback.m_rayDirectionInverse, | |||
rayCallback.m_signs, | |||
rayCallback.m_lambda_max, | |||
aabbMin, | |||
aabbMax, | |||
callback); | |||
} | |||
struct BroadphaseAabbTester : btDbvt::ICollide | |||
{ | |||
btBroadphaseAabbCallback& m_aabbCallback; | |||
BroadphaseAabbTester(btBroadphaseAabbCallback& orgCallback) | |||
:m_aabbCallback(orgCallback) | |||
{ | |||
} | |||
void Process(const btDbvtNode* leaf) | |||
{ | |||
btDbvtProxy* proxy=(btDbvtProxy*)leaf->data; | |||
m_aabbCallback.process(proxy); | |||
} | |||
}; | |||
void btDbvtBroadphase::aabbTest(const btVector3& aabbMin,const btVector3& aabbMax,btBroadphaseAabbCallback& aabbCallback) | |||
{ | |||
BroadphaseAabbTester callback(aabbCallback); | |||
const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(aabbMin,aabbMax); | |||
//process all children, that overlap with the given AABB bounds | |||
m_sets[0].collideTV(m_sets[0].m_root,bounds,callback); | |||
m_sets[1].collideTV(m_sets[1].m_root,bounds,callback); | |||
} | |||
// | |||
void btDbvtBroadphase::setAabb( btBroadphaseProxy* absproxy, | |||
const btVector3& aabbMin, | |||
const btVector3& aabbMax, | |||
btDispatcher* /*dispatcher*/) | |||
{ | |||
btDbvtProxy* proxy=(btDbvtProxy*)absproxy; | |||
ATTRIBUTE_ALIGNED16(btDbvtVolume) aabb=btDbvtVolume::FromMM(aabbMin,aabbMax); | |||
#if DBVT_BP_PREVENTFALSEUPDATE | |||
if(NotEqual(aabb,proxy->leaf->volume)) | |||
#endif | |||
{ | |||
bool docollide=false; | |||
if(proxy->stage==STAGECOUNT) | |||
{/* fixed -> dynamic set */ | |||
m_sets[1].remove(proxy->leaf); | |||
proxy->leaf=m_sets[0].insert(aabb,proxy); | |||
docollide=true; | |||
} | |||
else | |||
{/* dynamic set */ | |||
++m_updates_call; | |||
if(Intersect(proxy->leaf->volume,aabb)) | |||
{/* Moving */ | |||
const btVector3 delta=aabbMin-proxy->m_aabbMin; | |||
btVector3 velocity(((proxy->m_aabbMax-proxy->m_aabbMin)/2)*m_prediction); | |||
if(delta[0]<0) velocity[0]=-velocity[0]; | |||
if(delta[1]<0) velocity[1]=-velocity[1]; | |||
if(delta[2]<0) velocity[2]=-velocity[2]; | |||
if ( | |||
#ifdef DBVT_BP_MARGIN | |||
m_sets[0].update(proxy->leaf,aabb,velocity,DBVT_BP_MARGIN) | |||
#else | |||
m_sets[0].update(proxy->leaf,aabb,velocity) | |||
#endif | |||
) | |||
{ | |||
++m_updates_done; | |||
docollide=true; | |||
} | |||
} | |||
else | |||
{/* Teleporting */ | |||
m_sets[0].update(proxy->leaf,aabb); | |||
++m_updates_done; | |||
docollide=true; | |||
} | |||
} | |||
listremove(proxy,m_stageRoots[proxy->stage]); | |||
proxy->m_aabbMin = aabbMin; | |||
proxy->m_aabbMax = aabbMax; | |||
proxy->stage = m_stageCurrent; | |||
listappend(proxy,m_stageRoots[m_stageCurrent]); | |||
if(docollide) | |||
{ | |||
m_needcleanup=true; | |||
if(!m_deferedcollide) | |||
{ | |||
btDbvtTreeCollider collider(this); | |||
m_sets[1].collideTTpersistentStack(m_sets[1].m_root,proxy->leaf,collider); | |||
m_sets[0].collideTTpersistentStack(m_sets[0].m_root,proxy->leaf,collider); | |||
} | |||
} | |||
} | |||
} | |||
// | |||
void btDbvtBroadphase::setAabbForceUpdate( btBroadphaseProxy* absproxy, | |||
const btVector3& aabbMin, | |||
const btVector3& aabbMax, | |||
btDispatcher* /*dispatcher*/) | |||
{ | |||
btDbvtProxy* proxy=(btDbvtProxy*)absproxy; | |||
ATTRIBUTE_ALIGNED16(btDbvtVolume) aabb=btDbvtVolume::FromMM(aabbMin,aabbMax); | |||
bool docollide=false; | |||
if(proxy->stage==STAGECOUNT) | |||
{/* fixed -> dynamic set */ | |||
m_sets[1].remove(proxy->leaf); | |||
proxy->leaf=m_sets[0].insert(aabb,proxy); | |||
docollide=true; | |||
} | |||
else | |||
{/* dynamic set */ | |||
++m_updates_call; | |||
/* Teleporting */ | |||
m_sets[0].update(proxy->leaf,aabb); | |||
++m_updates_done; | |||
docollide=true; | |||
} | |||
listremove(proxy,m_stageRoots[proxy->stage]); | |||
proxy->m_aabbMin = aabbMin; | |||
proxy->m_aabbMax = aabbMax; | |||
proxy->stage = m_stageCurrent; | |||
listappend(proxy,m_stageRoots[m_stageCurrent]); | |||
if(docollide) | |||
{ | |||
m_needcleanup=true; | |||
if(!m_deferedcollide) | |||
{ | |||
btDbvtTreeCollider collider(this); | |||
m_sets[1].collideTTpersistentStack(m_sets[1].m_root,proxy->leaf,collider); | |||
m_sets[0].collideTTpersistentStack(m_sets[0].m_root,proxy->leaf,collider); | |||
} | |||
} | |||
} | |||
// | |||
void btDbvtBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) | |||
{ | |||
collide(dispatcher); | |||
#if DBVT_BP_PROFILE | |||
if(0==(m_pid%DBVT_BP_PROFILING_RATE)) | |||
{ | |||
printf("fixed(%u) dynamics(%u) pairs(%u)\r\n",m_sets[1].m_leaves,m_sets[0].m_leaves,m_paircache->getNumOverlappingPairs()); | |||
unsigned int total=m_profiling.m_total; | |||
if(total<=0) total=1; | |||
printf("ddcollide: %u%% (%uus)\r\n",(50+m_profiling.m_ddcollide*100)/total,m_profiling.m_ddcollide/DBVT_BP_PROFILING_RATE); | |||
printf("fdcollide: %u%% (%uus)\r\n",(50+m_profiling.m_fdcollide*100)/total,m_profiling.m_fdcollide/DBVT_BP_PROFILING_RATE); | |||
printf("cleanup: %u%% (%uus)\r\n",(50+m_profiling.m_cleanup*100)/total,m_profiling.m_cleanup/DBVT_BP_PROFILING_RATE); | |||
printf("total: %uus\r\n",total/DBVT_BP_PROFILING_RATE); | |||
const unsigned long sum=m_profiling.m_ddcollide+ | |||
m_profiling.m_fdcollide+ | |||
m_profiling.m_cleanup; | |||
printf("leaked: %u%% (%uus)\r\n",100-((50+sum*100)/total),(total-sum)/DBVT_BP_PROFILING_RATE); | |||
printf("job counts: %u%%\r\n",(m_profiling.m_jobcount*100)/((m_sets[0].m_leaves+m_sets[1].m_leaves)*DBVT_BP_PROFILING_RATE)); | |||
clear(m_profiling); | |||
m_clock.reset(); | |||
} | |||
#endif | |||
performDeferredRemoval(dispatcher); | |||
} | |||
void btDbvtBroadphase::performDeferredRemoval(btDispatcher* dispatcher) | |||
{ | |||
if (m_paircache->hasDeferredRemoval()) | |||
{ | |||
btBroadphasePairArray& overlappingPairArray = m_paircache->getOverlappingPairArray(); | |||
//perform a sort, to find duplicates and to sort 'invalid' pairs to the end | |||
overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); | |||
int invalidPair = 0; | |||
int i; | |||
btBroadphasePair previousPair; | |||
previousPair.m_pProxy0 = 0; | |||
previousPair.m_pProxy1 = 0; | |||
previousPair.m_algorithm = 0; | |||
for (i=0;i<overlappingPairArray.size();i++) | |||
{ | |||
btBroadphasePair& pair = overlappingPairArray[i]; | |||
bool isDuplicate = (pair == previousPair); | |||
previousPair = pair; | |||
bool needsRemoval = false; | |||
if (!isDuplicate) | |||
{ | |||
//important to perform AABB check that is consistent with the broadphase | |||
btDbvtProxy* pa=(btDbvtProxy*)pair.m_pProxy0; | |||
btDbvtProxy* pb=(btDbvtProxy*)pair.m_pProxy1; | |||
bool hasOverlap = Intersect(pa->leaf->volume,pb->leaf->volume); | |||
if (hasOverlap) | |||
{ | |||
needsRemoval = false; | |||
} else | |||
{ | |||
needsRemoval = true; | |||
} | |||
} else | |||
{ | |||
//remove duplicate | |||
needsRemoval = true; | |||
//should have no algorithm | |||
btAssert(!pair.m_algorithm); | |||
} | |||
if (needsRemoval) | |||
{ | |||
m_paircache->cleanOverlappingPair(pair,dispatcher); | |||
pair.m_pProxy0 = 0; | |||
pair.m_pProxy1 = 0; | |||
invalidPair++; | |||
} | |||
} | |||
//perform a sort, to sort 'invalid' pairs to the end | |||
overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); | |||
overlappingPairArray.resize(overlappingPairArray.size() - invalidPair); | |||
} | |||
} | |||
// | |||
void btDbvtBroadphase::collide(btDispatcher* dispatcher) | |||
{ | |||
/*printf("---------------------------------------------------------\n"); | |||
printf("m_sets[0].m_leaves=%d\n",m_sets[0].m_leaves); | |||
printf("m_sets[1].m_leaves=%d\n",m_sets[1].m_leaves); | |||
printf("numPairs = %d\n",getOverlappingPairCache()->getNumOverlappingPairs()); | |||
{ | |||
int i; | |||
for (i=0;i<getOverlappingPairCache()->getNumOverlappingPairs();i++) | |||
{ | |||
printf("pair[%d]=(%d,%d),",i,getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy0->getUid(), | |||
getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy1->getUid()); | |||
} | |||
printf("\n"); | |||
} | |||
*/ | |||
SPC(m_profiling.m_total); | |||
/* optimize */ | |||
m_sets[0].optimizeIncremental(1+(m_sets[0].m_leaves*m_dupdates)/100); | |||
if(m_fixedleft) | |||
{ | |||
const int count=1+(m_sets[1].m_leaves*m_fupdates)/100; | |||
m_sets[1].optimizeIncremental(1+(m_sets[1].m_leaves*m_fupdates)/100); | |||
m_fixedleft=btMax<int>(0,m_fixedleft-count); | |||
} | |||
/* dynamic -> fixed set */ | |||
m_stageCurrent=(m_stageCurrent+1)%STAGECOUNT; | |||
btDbvtProxy* current=m_stageRoots[m_stageCurrent]; | |||
if(current) | |||
{ | |||
btDbvtTreeCollider collider(this); | |||
do { | |||
btDbvtProxy* next=current->links[1]; | |||
listremove(current,m_stageRoots[current->stage]); | |||
listappend(current,m_stageRoots[STAGECOUNT]); | |||
#if DBVT_BP_ACCURATESLEEPING | |||
m_paircache->removeOverlappingPairsContainingProxy(current,dispatcher); | |||
collider.proxy=current; | |||
btDbvt::collideTV(m_sets[0].m_root,current->aabb,collider); | |||
btDbvt::collideTV(m_sets[1].m_root,current->aabb,collider); | |||
#endif | |||
m_sets[0].remove(current->leaf); | |||
ATTRIBUTE_ALIGNED16(btDbvtVolume) curAabb=btDbvtVolume::FromMM(current->m_aabbMin,current->m_aabbMax); | |||
current->leaf = m_sets[1].insert(curAabb,current); | |||
current->stage = STAGECOUNT; | |||
current = next; | |||
} while(current); | |||
m_fixedleft=m_sets[1].m_leaves; | |||
m_needcleanup=true; | |||
} | |||
/* collide dynamics */ | |||
{ | |||
btDbvtTreeCollider collider(this); | |||
if(m_deferedcollide) | |||
{ | |||
SPC(m_profiling.m_fdcollide); | |||
m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[1].m_root,collider); | |||
} | |||
if(m_deferedcollide) | |||
{ | |||
SPC(m_profiling.m_ddcollide); | |||
m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[0].m_root,collider); | |||
} | |||
} | |||
/* clean up */ | |||
if(m_needcleanup) | |||
{ | |||
SPC(m_profiling.m_cleanup); | |||
btBroadphasePairArray& pairs=m_paircache->getOverlappingPairArray(); | |||
if(pairs.size()>0) | |||
{ | |||
int ni=btMin(pairs.size(),btMax<int>(m_newpairs,(pairs.size()*m_cupdates)/100)); | |||
for(int i=0;i<ni;++i) | |||
{ | |||
btBroadphasePair& p=pairs[(m_cid+i)%pairs.size()]; | |||
btDbvtProxy* pa=(btDbvtProxy*)p.m_pProxy0; | |||
btDbvtProxy* pb=(btDbvtProxy*)p.m_pProxy1; | |||
if(!Intersect(pa->leaf->volume,pb->leaf->volume)) | |||
{ | |||
#if DBVT_BP_SORTPAIRS | |||
if(pa->m_uniqueId>pb->m_uniqueId) | |||
btSwap(pa,pb); | |||
#endif | |||
m_paircache->removeOverlappingPair(pa,pb,dispatcher); | |||
--ni;--i; | |||
} | |||
} | |||
if(pairs.size()>0) m_cid=(m_cid+ni)%pairs.size(); else m_cid=0; | |||
} | |||
} | |||
++m_pid; | |||
m_newpairs=1; | |||
m_needcleanup=false; | |||
if(m_updates_call>0) | |||
{ m_updates_ratio=m_updates_done/(btScalar)m_updates_call; } | |||
else | |||
{ m_updates_ratio=0; } | |||
m_updates_done/=2; | |||
m_updates_call/=2; | |||
} | |||
// | |||
void btDbvtBroadphase::optimize() | |||
{ | |||
m_sets[0].optimizeTopDown(); | |||
m_sets[1].optimizeTopDown(); | |||
} | |||
// | |||
btOverlappingPairCache* btDbvtBroadphase::getOverlappingPairCache() | |||
{ | |||
return(m_paircache); | |||
} | |||
// | |||
const btOverlappingPairCache* btDbvtBroadphase::getOverlappingPairCache() const | |||
{ | |||
return(m_paircache); | |||
} | |||
// | |||
void btDbvtBroadphase::getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const | |||
{ | |||
ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds; | |||
if(!m_sets[0].empty()) | |||
if(!m_sets[1].empty()) Merge( m_sets[0].m_root->volume, | |||
m_sets[1].m_root->volume,bounds); | |||
else | |||
bounds=m_sets[0].m_root->volume; | |||
else if(!m_sets[1].empty()) bounds=m_sets[1].m_root->volume; | |||
else | |||
bounds=btDbvtVolume::FromCR(btVector3(0,0,0),0); | |||
aabbMin=bounds.Mins(); | |||
aabbMax=bounds.Maxs(); | |||
} | |||
void btDbvtBroadphase::resetPool(btDispatcher* dispatcher) | |||
{ | |||
int totalObjects = m_sets[0].m_leaves + m_sets[1].m_leaves; | |||
if (!totalObjects) | |||
{ | |||
//reset internal dynamic tree data structures | |||
m_sets[0].clear(); | |||
m_sets[1].clear(); | |||
m_deferedcollide = false; | |||
m_needcleanup = true; | |||
m_stageCurrent = 0; | |||
m_fixedleft = 0; | |||
m_fupdates = 1; | |||
m_dupdates = 0; | |||
m_cupdates = 10; | |||
m_newpairs = 1; | |||
m_updates_call = 0; | |||
m_updates_done = 0; | |||
m_updates_ratio = 0; | |||
m_gid = 0; | |||
m_pid = 0; | |||
m_cid = 0; | |||
for(int i=0;i<=STAGECOUNT;++i) | |||
{ | |||
m_stageRoots[i]=0; | |||
} | |||
} | |||
} | |||
// | |||
void btDbvtBroadphase::printStats() | |||
{} | |||
// | |||
#if DBVT_BP_ENABLE_BENCHMARK | |||
struct btBroadphaseBenchmark | |||
{ | |||
struct Experiment | |||
{ | |||
const char* name; | |||
int object_count; | |||
int update_count; | |||
int spawn_count; | |||
int iterations; | |||
btScalar speed; | |||
btScalar amplitude; | |||
}; | |||
struct Object | |||
{ | |||
btVector3 center; | |||
btVector3 extents; | |||
btBroadphaseProxy* proxy; | |||
btScalar time; | |||
void update(btScalar speed,btScalar amplitude,btBroadphaseInterface* pbi) | |||
{ | |||
time += speed; | |||
center[0] = btCos(time*(btScalar)2.17)*amplitude+ | |||
btSin(time)*amplitude/2; | |||
center[1] = btCos(time*(btScalar)1.38)*amplitude+ | |||
btSin(time)*amplitude; | |||
center[2] = btSin(time*(btScalar)0.777)*amplitude; | |||
pbi->setAabb(proxy,center-extents,center+extents,0); | |||
} | |||
}; | |||
static int UnsignedRand(int range=RAND_MAX-1) { return(rand()%(range+1)); } | |||
static btScalar UnitRand() { return(UnsignedRand(16384)/(btScalar)16384); } | |||
static void OutputTime(const char* name,btClock& c,unsigned count=0) | |||
{ | |||
const unsigned long us=c.getTimeMicroseconds(); | |||
const unsigned long ms=(us+500)/1000; | |||
const btScalar sec=us/(btScalar)(1000*1000); | |||
if(count>0) | |||
printf("%s : %u us (%u ms), %.2f/s\r\n",name,us,ms,count/sec); | |||
else | |||
printf("%s : %u us (%u ms)\r\n",name,us,ms); | |||
} | |||
}; | |||
void btDbvtBroadphase::benchmark(btBroadphaseInterface* pbi) | |||
{ | |||
static const btBroadphaseBenchmark::Experiment experiments[]= | |||
{ | |||
{"1024o.10%",1024,10,0,8192,(btScalar)0.005,(btScalar)100}, | |||
/*{"4096o.10%",4096,10,0,8192,(btScalar)0.005,(btScalar)100}, | |||
{"8192o.10%",8192,10,0,8192,(btScalar)0.005,(btScalar)100},*/ | |||
}; | |||
static const int nexperiments=sizeof(experiments)/sizeof(experiments[0]); | |||
btAlignedObjectArray<btBroadphaseBenchmark::Object*> objects; | |||
btClock wallclock; | |||
/* Begin */ | |||
for(int iexp=0;iexp<nexperiments;++iexp) | |||
{ | |||
const btBroadphaseBenchmark::Experiment& experiment=experiments[iexp]; | |||
const int object_count=experiment.object_count; | |||
const int update_count=(object_count*experiment.update_count)/100; | |||
const int spawn_count=(object_count*experiment.spawn_count)/100; | |||
const btScalar speed=experiment.speed; | |||
const btScalar amplitude=experiment.amplitude; | |||
printf("Experiment #%u '%s':\r\n",iexp,experiment.name); | |||
printf("\tObjects: %u\r\n",object_count); | |||
printf("\tUpdate: %u\r\n",update_count); | |||
printf("\tSpawn: %u\r\n",spawn_count); | |||
printf("\tSpeed: %f\r\n",speed); | |||
printf("\tAmplitude: %f\r\n",amplitude); | |||
srand(180673); | |||
/* Create objects */ | |||
wallclock.reset(); | |||
objects.reserve(object_count); | |||
for(int i=0;i<object_count;++i) | |||
{ | |||
btBroadphaseBenchmark::Object* po=new btBroadphaseBenchmark::Object(); | |||
po->center[0]=btBroadphaseBenchmark::UnitRand()*50; | |||
po->center[1]=btBroadphaseBenchmark::UnitRand()*50; | |||
po->center[2]=btBroadphaseBenchmark::UnitRand()*50; | |||
po->extents[0]=btBroadphaseBenchmark::UnitRand()*2+2; | |||
po->extents[1]=btBroadphaseBenchmark::UnitRand()*2+2; | |||
po->extents[2]=btBroadphaseBenchmark::UnitRand()*2+2; | |||
po->time=btBroadphaseBenchmark::UnitRand()*2000; | |||
po->proxy=pbi->createProxy(po->center-po->extents,po->center+po->extents,0,po,1,1,0,0); | |||
objects.push_back(po); | |||
} | |||
btBroadphaseBenchmark::OutputTime("\tInitialization",wallclock); | |||
/* First update */ | |||
wallclock.reset(); | |||
for(int i=0;i<objects.size();++i) | |||
{ | |||
objects[i]->update(speed,amplitude,pbi); | |||
} | |||
btBroadphaseBenchmark::OutputTime("\tFirst update",wallclock); | |||
/* Updates */ | |||
wallclock.reset(); | |||
for(int i=0;i<experiment.iterations;++i) | |||
{ | |||
for(int j=0;j<update_count;++j) | |||
{ | |||
objects[j]->update(speed,amplitude,pbi); | |||
} | |||
pbi->calculateOverlappingPairs(0); | |||
} | |||
btBroadphaseBenchmark::OutputTime("\tUpdate",wallclock,experiment.iterations); | |||
/* Clean up */ | |||
wallclock.reset(); | |||
for(int i=0;i<objects.size();++i) | |||
{ | |||
pbi->destroyProxy(objects[i]->proxy,0); | |||
delete objects[i]; | |||
} | |||
objects.resize(0); | |||
btBroadphaseBenchmark::OutputTime("\tRelease",wallclock); | |||
} | |||
} | |||
#else | |||
void btDbvtBroadphase::benchmark(btBroadphaseInterface*) | |||
{} | |||
#endif | |||
#if DBVT_BP_PROFILE | |||
#undef SPC | |||
#endif | |||
@@ -0,0 +1,146 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
///btDbvtBroadphase implementation by Nathanael Presson | |||
#ifndef BT_DBVT_BROADPHASE_H | |||
#define BT_DBVT_BROADPHASE_H | |||
#include "BulletCollision/BroadphaseCollision/btDbvt.h" | |||
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" | |||
// | |||
// Compile time config | |||
// | |||
#define DBVT_BP_PROFILE 0 | |||
//#define DBVT_BP_SORTPAIRS 1 | |||
#define DBVT_BP_PREVENTFALSEUPDATE 0 | |||
#define DBVT_BP_ACCURATESLEEPING 0 | |||
#define DBVT_BP_ENABLE_BENCHMARK 0 | |||
#define DBVT_BP_MARGIN (btScalar)0.05 | |||
#if DBVT_BP_PROFILE | |||
#define DBVT_BP_PROFILING_RATE 256 | |||
#include "LinearMath/btQuickprof.h" | |||
#endif | |||
// | |||
// btDbvtProxy | |||
// | |||
struct btDbvtProxy : btBroadphaseProxy | |||
{ | |||
/* Fields */ | |||
//btDbvtAabbMm aabb; | |||
btDbvtNode* leaf; | |||
btDbvtProxy* links[2]; | |||
int stage; | |||
/* ctor */ | |||
btDbvtProxy(const btVector3& aabbMin,const btVector3& aabbMax,void* userPtr,short int collisionFilterGroup, short int collisionFilterMask) : | |||
btBroadphaseProxy(aabbMin,aabbMax,userPtr,collisionFilterGroup,collisionFilterMask) | |||
{ | |||
links[0]=links[1]=0; | |||
} | |||
}; | |||
typedef btAlignedObjectArray<btDbvtProxy*> btDbvtProxyArray; | |||
///The btDbvtBroadphase implements a broadphase using two dynamic AABB bounding volume hierarchies/trees (see btDbvt). | |||
///One tree is used for static/non-moving objects, and another tree is used for dynamic objects. Objects can move from one tree to the other. | |||
///This is a very fast broadphase, especially for very dynamic worlds where many objects are moving. Its insert/add and remove of objects is generally faster than the sweep and prune broadphases btAxisSweep3 and bt32BitAxisSweep3. | |||
struct btDbvtBroadphase : btBroadphaseInterface | |||
{ | |||
/* Config */ | |||
enum { | |||
DYNAMIC_SET = 0, /* Dynamic set index */ | |||
FIXED_SET = 1, /* Fixed set index */ | |||
STAGECOUNT = 2 /* Number of stages */ | |||
}; | |||
/* Fields */ | |||
btDbvt m_sets[2]; // Dbvt sets | |||
btDbvtProxy* m_stageRoots[STAGECOUNT+1]; // Stages list | |||
btOverlappingPairCache* m_paircache; // Pair cache | |||
btScalar m_prediction; // Velocity prediction | |||
int m_stageCurrent; // Current stage | |||
int m_fupdates; // % of fixed updates per frame | |||
int m_dupdates; // % of dynamic updates per frame | |||
int m_cupdates; // % of cleanup updates per frame | |||
int m_newpairs; // Number of pairs created | |||
int m_fixedleft; // Fixed optimization left | |||
unsigned m_updates_call; // Number of updates call | |||
unsigned m_updates_done; // Number of updates done | |||
btScalar m_updates_ratio; // m_updates_done/m_updates_call | |||
int m_pid; // Parse id | |||
int m_cid; // Cleanup index | |||
int m_gid; // Gen id | |||
bool m_releasepaircache; // Release pair cache on delete | |||
bool m_deferedcollide; // Defere dynamic/static collision to collide call | |||
bool m_needcleanup; // Need to run cleanup? | |||
#if DBVT_BP_PROFILE | |||
btClock m_clock; | |||
struct { | |||
unsigned long m_total; | |||
unsigned long m_ddcollide; | |||
unsigned long m_fdcollide; | |||
unsigned long m_cleanup; | |||
unsigned long m_jobcount; | |||
} m_profiling; | |||
#endif | |||
/* Methods */ | |||
btDbvtBroadphase(btOverlappingPairCache* paircache=0); | |||
~btDbvtBroadphase(); | |||
void collide(btDispatcher* dispatcher); | |||
void optimize(); | |||
/* btBroadphaseInterface Implementation */ | |||
btBroadphaseProxy* createProxy(const btVector3& aabbMin,const btVector3& aabbMax,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy); | |||
virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher); | |||
virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0), const btVector3& aabbMax = btVector3(0,0,0)); | |||
virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback); | |||
virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; | |||
virtual void calculateOverlappingPairs(btDispatcher* dispatcher); | |||
virtual btOverlappingPairCache* getOverlappingPairCache(); | |||
virtual const btOverlappingPairCache* getOverlappingPairCache() const; | |||
virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const; | |||
virtual void printStats(); | |||
///reset broadphase internal structures, to ensure determinism/reproducability | |||
virtual void resetPool(btDispatcher* dispatcher); | |||
void performDeferredRemoval(btDispatcher* dispatcher); | |||
void setVelocityPrediction(btScalar prediction) | |||
{ | |||
m_prediction = prediction; | |||
} | |||
btScalar getVelocityPrediction() const | |||
{ | |||
return m_prediction; | |||
} | |||
///this setAabbForceUpdate is similar to setAabb but always forces the aabb update. | |||
///it is not part of the btBroadphaseInterface but specific to btDbvtBroadphase. | |||
///it bypasses certain optimizations that prevent aabb updates (when the aabb shrinks), see | |||
///http://code.google.com/p/bullet/issues/detail?id=223 | |||
void setAabbForceUpdate( btBroadphaseProxy* absproxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* /*dispatcher*/); | |||
static void benchmark(btBroadphaseInterface*); | |||
}; | |||
#endif |
@@ -0,0 +1,22 @@ | |||
/* | |||
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 "btDispatcher.h" | |||
btDispatcher::~btDispatcher() | |||
{ | |||
} | |||
@@ -0,0 +1,110 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_DISPATCHER_H | |||
#define BT_DISPATCHER_H | |||
#include "LinearMath/btScalar.h" | |||
class btCollisionAlgorithm; | |||
struct btBroadphaseProxy; | |||
class btRigidBody; | |||
class btCollisionObject; | |||
class btOverlappingPairCache; | |||
class btPersistentManifold; | |||
class btStackAlloc; | |||
class btPoolAllocator; | |||
struct btDispatcherInfo | |||
{ | |||
enum DispatchFunc | |||
{ | |||
DISPATCH_DISCRETE = 1, | |||
DISPATCH_CONTINUOUS | |||
}; | |||
btDispatcherInfo() | |||
:m_timeStep(btScalar(0.)), | |||
m_stepCount(0), | |||
m_dispatchFunc(DISPATCH_DISCRETE), | |||
m_timeOfImpact(btScalar(1.)), | |||
m_useContinuous(true), | |||
m_debugDraw(0), | |||
m_enableSatConvex(false), | |||
m_enableSPU(true), | |||
m_useEpa(true), | |||
m_allowedCcdPenetration(btScalar(0.04)), | |||
m_useConvexConservativeDistanceUtil(false), | |||
m_convexConservativeDistanceThreshold(0.0f), | |||
m_stackAllocator(0) | |||
{ | |||
} | |||
btScalar m_timeStep; | |||
int m_stepCount; | |||
int m_dispatchFunc; | |||
mutable btScalar m_timeOfImpact; | |||
bool m_useContinuous; | |||
class btIDebugDraw* m_debugDraw; | |||
bool m_enableSatConvex; | |||
bool m_enableSPU; | |||
bool m_useEpa; | |||
btScalar m_allowedCcdPenetration; | |||
bool m_useConvexConservativeDistanceUtil; | |||
btScalar m_convexConservativeDistanceThreshold; | |||
btStackAlloc* m_stackAllocator; | |||
}; | |||
///The btDispatcher interface class can be used in combination with broadphase to dispatch calculations for overlapping pairs. | |||
///For example for pairwise collision detection, calculating contact points stored in btPersistentManifold or user callbacks (game logic). | |||
class btDispatcher | |||
{ | |||
public: | |||
virtual ~btDispatcher() ; | |||
virtual btCollisionAlgorithm* findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold=0) = 0; | |||
virtual btPersistentManifold* getNewManifold(void* body0,void* body1)=0; | |||
virtual void releaseManifold(btPersistentManifold* manifold)=0; | |||
virtual void clearManifold(btPersistentManifold* manifold)=0; | |||
virtual bool needsCollision(btCollisionObject* body0,btCollisionObject* body1) = 0; | |||
virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1)=0; | |||
virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) =0; | |||
virtual int getNumManifolds() const = 0; | |||
virtual btPersistentManifold* getManifoldByIndexInternal(int index) = 0; | |||
virtual btPersistentManifold** getInternalManifoldPointer() = 0; | |||
virtual btPoolAllocator* getInternalManifoldPool() = 0; | |||
virtual const btPoolAllocator* getInternalManifoldPool() const = 0; | |||
virtual void* allocateCollisionAlgorithm(int size) = 0; | |||
virtual void freeCollisionAlgorithm(void* ptr) = 0; | |||
}; | |||
#endif //BT_DISPATCHER_H |
@@ -0,0 +1,489 @@ | |||
/* | |||
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 "btMultiSapBroadphase.h" | |||
#include "btSimpleBroadphase.h" | |||
#include "LinearMath/btAabbUtil2.h" | |||
#include "btQuantizedBvh.h" | |||
/// btSapBroadphaseArray m_sapBroadphases; | |||
/// btOverlappingPairCache* m_overlappingPairs; | |||
extern int gOverlappingPairs; | |||
/* | |||
class btMultiSapSortedOverlappingPairCache : public btSortedOverlappingPairCache | |||
{ | |||
public: | |||
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) | |||
{ | |||
return btSortedOverlappingPairCache::addOverlappingPair((btBroadphaseProxy*)proxy0->m_multiSapParentProxy,(btBroadphaseProxy*)proxy1->m_multiSapParentProxy); | |||
} | |||
}; | |||
*/ | |||
btMultiSapBroadphase::btMultiSapBroadphase(int /*maxProxies*/,btOverlappingPairCache* pairCache) | |||
:m_overlappingPairs(pairCache), | |||
m_optimizedAabbTree(0), | |||
m_ownsPairCache(false), | |||
m_invalidPair(0) | |||
{ | |||
if (!m_overlappingPairs) | |||
{ | |||
m_ownsPairCache = true; | |||
void* mem = btAlignedAlloc(sizeof(btSortedOverlappingPairCache),16); | |||
m_overlappingPairs = new (mem)btSortedOverlappingPairCache(); | |||
} | |||
struct btMultiSapOverlapFilterCallback : public btOverlapFilterCallback | |||
{ | |||
virtual ~btMultiSapOverlapFilterCallback() | |||
{} | |||
// return true when pairs need collision | |||
virtual bool needBroadphaseCollision(btBroadphaseProxy* childProxy0,btBroadphaseProxy* childProxy1) const | |||
{ | |||
btBroadphaseProxy* multiProxy0 = (btBroadphaseProxy*)childProxy0->m_multiSapParentProxy; | |||
btBroadphaseProxy* multiProxy1 = (btBroadphaseProxy*)childProxy1->m_multiSapParentProxy; | |||
bool collides = (multiProxy0->m_collisionFilterGroup & multiProxy1->m_collisionFilterMask) != 0; | |||
collides = collides && (multiProxy1->m_collisionFilterGroup & multiProxy0->m_collisionFilterMask); | |||
return collides; | |||
} | |||
}; | |||
void* mem = btAlignedAlloc(sizeof(btMultiSapOverlapFilterCallback),16); | |||
m_filterCallback = new (mem)btMultiSapOverlapFilterCallback(); | |||
m_overlappingPairs->setOverlapFilterCallback(m_filterCallback); | |||
// mem = btAlignedAlloc(sizeof(btSimpleBroadphase),16); | |||
// m_simpleBroadphase = new (mem) btSimpleBroadphase(maxProxies,m_overlappingPairs); | |||
} | |||
btMultiSapBroadphase::~btMultiSapBroadphase() | |||
{ | |||
if (m_ownsPairCache) | |||
{ | |||
m_overlappingPairs->~btOverlappingPairCache(); | |||
btAlignedFree(m_overlappingPairs); | |||
} | |||
} | |||
void btMultiSapBroadphase::buildTree(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax) | |||
{ | |||
m_optimizedAabbTree = new btQuantizedBvh(); | |||
m_optimizedAabbTree->setQuantizationValues(bvhAabbMin,bvhAabbMax); | |||
QuantizedNodeArray& nodes = m_optimizedAabbTree->getLeafNodeArray(); | |||
for (int i=0;i<m_sapBroadphases.size();i++) | |||
{ | |||
btQuantizedBvhNode node; | |||
btVector3 aabbMin,aabbMax; | |||
m_sapBroadphases[i]->getBroadphaseAabb(aabbMin,aabbMax); | |||
m_optimizedAabbTree->quantize(&node.m_quantizedAabbMin[0],aabbMin,0); | |||
m_optimizedAabbTree->quantize(&node.m_quantizedAabbMax[0],aabbMax,1); | |||
int partId = 0; | |||
node.m_escapeIndexOrTriangleIndex = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | i; | |||
nodes.push_back(node); | |||
} | |||
m_optimizedAabbTree->buildInternal(); | |||
} | |||
btBroadphaseProxy* btMultiSapBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* /*ignoreMe*/) | |||
{ | |||
//void* ignoreMe -> we could think of recursive multi-sap, if someone is interested | |||
void* mem = btAlignedAlloc(sizeof(btMultiSapProxy),16); | |||
btMultiSapProxy* proxy = new (mem)btMultiSapProxy(aabbMin, aabbMax,shapeType,userPtr, collisionFilterGroup,collisionFilterMask); | |||
m_multiSapProxies.push_back(proxy); | |||
///this should deal with inserting/removal into child broadphases | |||
setAabb(proxy,aabbMin,aabbMax,dispatcher); | |||
return proxy; | |||
} | |||
void btMultiSapBroadphase::destroyProxy(btBroadphaseProxy* /*proxy*/,btDispatcher* /*dispatcher*/) | |||
{ | |||
///not yet | |||
btAssert(0); | |||
} | |||
void btMultiSapBroadphase::addToChildBroadphase(btMultiSapProxy* parentMultiSapProxy, btBroadphaseProxy* childProxy, btBroadphaseInterface* childBroadphase) | |||
{ | |||
void* mem = btAlignedAlloc(sizeof(btBridgeProxy),16); | |||
btBridgeProxy* bridgeProxyRef = new(mem) btBridgeProxy; | |||
bridgeProxyRef->m_childProxy = childProxy; | |||
bridgeProxyRef->m_childBroadphase = childBroadphase; | |||
parentMultiSapProxy->m_bridgeProxies.push_back(bridgeProxyRef); | |||
} | |||
bool boxIsContainedWithinBox(const btVector3& amin,const btVector3& amax,const btVector3& bmin,const btVector3& bmax); | |||
bool boxIsContainedWithinBox(const btVector3& amin,const btVector3& amax,const btVector3& bmin,const btVector3& bmax) | |||
{ | |||
return | |||
amin.getX() >= bmin.getX() && amax.getX() <= bmax.getX() && | |||
amin.getY() >= bmin.getY() && amax.getY() <= bmax.getY() && | |||
amin.getZ() >= bmin.getZ() && amax.getZ() <= bmax.getZ(); | |||
} | |||
void btMultiSapBroadphase::getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const | |||
{ | |||
btMultiSapProxy* multiProxy = static_cast<btMultiSapProxy*>(proxy); | |||
aabbMin = multiProxy->m_aabbMin; | |||
aabbMax = multiProxy->m_aabbMax; | |||
} | |||
void btMultiSapBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin,const btVector3& aabbMax) | |||
{ | |||
for (int i=0;i<m_multiSapProxies.size();i++) | |||
{ | |||
rayCallback.process(m_multiSapProxies[i]); | |||
} | |||
} | |||
//#include <stdio.h> | |||
void btMultiSapBroadphase::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher) | |||
{ | |||
btMultiSapProxy* multiProxy = static_cast<btMultiSapProxy*>(proxy); | |||
multiProxy->m_aabbMin = aabbMin; | |||
multiProxy->m_aabbMax = aabbMax; | |||
// bool fullyContained = false; | |||
// bool alreadyInSimple = false; | |||
struct MyNodeOverlapCallback : public btNodeOverlapCallback | |||
{ | |||
btMultiSapBroadphase* m_multiSap; | |||
btMultiSapProxy* m_multiProxy; | |||
btDispatcher* m_dispatcher; | |||
MyNodeOverlapCallback(btMultiSapBroadphase* multiSap,btMultiSapProxy* multiProxy,btDispatcher* dispatcher) | |||
:m_multiSap(multiSap), | |||
m_multiProxy(multiProxy), | |||
m_dispatcher(dispatcher) | |||
{ | |||
} | |||
virtual void processNode(int /*nodeSubPart*/, int broadphaseIndex) | |||
{ | |||
btBroadphaseInterface* childBroadphase = m_multiSap->getBroadphaseArray()[broadphaseIndex]; | |||
int containingBroadphaseIndex = -1; | |||
//already found? | |||
for (int i=0;i<m_multiProxy->m_bridgeProxies.size();i++) | |||
{ | |||
if (m_multiProxy->m_bridgeProxies[i]->m_childBroadphase == childBroadphase) | |||
{ | |||
containingBroadphaseIndex = i; | |||
break; | |||
} | |||
} | |||
if (containingBroadphaseIndex<0) | |||
{ | |||
//add it | |||
btBroadphaseProxy* childProxy = childBroadphase->createProxy(m_multiProxy->m_aabbMin,m_multiProxy->m_aabbMax,m_multiProxy->m_shapeType,m_multiProxy->m_clientObject,m_multiProxy->m_collisionFilterGroup,m_multiProxy->m_collisionFilterMask, m_dispatcher,m_multiProxy); | |||
m_multiSap->addToChildBroadphase(m_multiProxy,childProxy,childBroadphase); | |||
} | |||
} | |||
}; | |||
MyNodeOverlapCallback myNodeCallback(this,multiProxy,dispatcher); | |||
if (m_optimizedAabbTree) | |||
m_optimizedAabbTree->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax); | |||
int i; | |||
for ( i=0;i<multiProxy->m_bridgeProxies.size();i++) | |||
{ | |||
btVector3 worldAabbMin,worldAabbMax; | |||
multiProxy->m_bridgeProxies[i]->m_childBroadphase->getBroadphaseAabb(worldAabbMin,worldAabbMax); | |||
bool overlapsBroadphase = TestAabbAgainstAabb2(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax); | |||
if (!overlapsBroadphase) | |||
{ | |||
//remove it now | |||
btBridgeProxy* bridgeProxy = multiProxy->m_bridgeProxies[i]; | |||
btBroadphaseProxy* childProxy = bridgeProxy->m_childProxy; | |||
bridgeProxy->m_childBroadphase->destroyProxy(childProxy,dispatcher); | |||
multiProxy->m_bridgeProxies.swap( i,multiProxy->m_bridgeProxies.size()-1); | |||
multiProxy->m_bridgeProxies.pop_back(); | |||
} | |||
} | |||
/* | |||
if (1) | |||
{ | |||
//find broadphase that contain this multiProxy | |||
int numChildBroadphases = getBroadphaseArray().size(); | |||
for (int i=0;i<numChildBroadphases;i++) | |||
{ | |||
btBroadphaseInterface* childBroadphase = getBroadphaseArray()[i]; | |||
btVector3 worldAabbMin,worldAabbMax; | |||
childBroadphase->getBroadphaseAabb(worldAabbMin,worldAabbMax); | |||
bool overlapsBroadphase = TestAabbAgainstAabb2(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax); | |||
// fullyContained = fullyContained || boxIsContainedWithinBox(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax); | |||
int containingBroadphaseIndex = -1; | |||
//if already contains this | |||
for (int i=0;i<multiProxy->m_bridgeProxies.size();i++) | |||
{ | |||
if (multiProxy->m_bridgeProxies[i]->m_childBroadphase == childBroadphase) | |||
{ | |||
containingBroadphaseIndex = i; | |||
} | |||
alreadyInSimple = alreadyInSimple || (multiProxy->m_bridgeProxies[i]->m_childBroadphase == m_simpleBroadphase); | |||
} | |||
if (overlapsBroadphase) | |||
{ | |||
if (containingBroadphaseIndex<0) | |||
{ | |||
btBroadphaseProxy* childProxy = childBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher); | |||
childProxy->m_multiSapParentProxy = multiProxy; | |||
addToChildBroadphase(multiProxy,childProxy,childBroadphase); | |||
} | |||
} else | |||
{ | |||
if (containingBroadphaseIndex>=0) | |||
{ | |||
//remove | |||
btBridgeProxy* bridgeProxy = multiProxy->m_bridgeProxies[containingBroadphaseIndex]; | |||
btBroadphaseProxy* childProxy = bridgeProxy->m_childProxy; | |||
bridgeProxy->m_childBroadphase->destroyProxy(childProxy,dispatcher); | |||
multiProxy->m_bridgeProxies.swap( containingBroadphaseIndex,multiProxy->m_bridgeProxies.size()-1); | |||
multiProxy->m_bridgeProxies.pop_back(); | |||
} | |||
} | |||
} | |||
///If we are in no other child broadphase, stick the proxy in the global 'simple' broadphase (brute force) | |||
///hopefully we don't end up with many entries here (can assert/provide feedback on stats) | |||
if (0)//!multiProxy->m_bridgeProxies.size()) | |||
{ | |||
///we don't pass the userPtr but our multisap proxy. We need to patch this, before processing an actual collision | |||
///this is needed to be able to calculate the aabb overlap | |||
btBroadphaseProxy* childProxy = m_simpleBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher); | |||
childProxy->m_multiSapParentProxy = multiProxy; | |||
addToChildBroadphase(multiProxy,childProxy,m_simpleBroadphase); | |||
} | |||
} | |||
if (!multiProxy->m_bridgeProxies.size()) | |||
{ | |||
///we don't pass the userPtr but our multisap proxy. We need to patch this, before processing an actual collision | |||
///this is needed to be able to calculate the aabb overlap | |||
btBroadphaseProxy* childProxy = m_simpleBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher); | |||
childProxy->m_multiSapParentProxy = multiProxy; | |||
addToChildBroadphase(multiProxy,childProxy,m_simpleBroadphase); | |||
} | |||
*/ | |||
//update | |||
for ( i=0;i<multiProxy->m_bridgeProxies.size();i++) | |||
{ | |||
btBridgeProxy* bridgeProxyRef = multiProxy->m_bridgeProxies[i]; | |||
bridgeProxyRef->m_childBroadphase->setAabb(bridgeProxyRef->m_childProxy,aabbMin,aabbMax,dispatcher); | |||
} | |||
} | |||
bool stopUpdating=false; | |||
class btMultiSapBroadphasePairSortPredicate | |||
{ | |||
public: | |||
bool operator() ( const btBroadphasePair& a1, const btBroadphasePair& b1 ) const | |||
{ | |||
btMultiSapBroadphase::btMultiSapProxy* aProxy0 = a1.m_pProxy0 ? (btMultiSapBroadphase::btMultiSapProxy*)a1.m_pProxy0->m_multiSapParentProxy : 0; | |||
btMultiSapBroadphase::btMultiSapProxy* aProxy1 = a1.m_pProxy1 ? (btMultiSapBroadphase::btMultiSapProxy*)a1.m_pProxy1->m_multiSapParentProxy : 0; | |||
btMultiSapBroadphase::btMultiSapProxy* bProxy0 = b1.m_pProxy0 ? (btMultiSapBroadphase::btMultiSapProxy*)b1.m_pProxy0->m_multiSapParentProxy : 0; | |||
btMultiSapBroadphase::btMultiSapProxy* bProxy1 = b1.m_pProxy1 ? (btMultiSapBroadphase::btMultiSapProxy*)b1.m_pProxy1->m_multiSapParentProxy : 0; | |||
return aProxy0 > bProxy0 || | |||
(aProxy0 == bProxy0 && aProxy1 > bProxy1) || | |||
(aProxy0 == bProxy0 && aProxy1 == bProxy1 && a1.m_algorithm > b1.m_algorithm); | |||
} | |||
}; | |||
///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb | |||
void btMultiSapBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) | |||
{ | |||
// m_simpleBroadphase->calculateOverlappingPairs(dispatcher); | |||
if (!stopUpdating && getOverlappingPairCache()->hasDeferredRemoval()) | |||
{ | |||
btBroadphasePairArray& overlappingPairArray = getOverlappingPairCache()->getOverlappingPairArray(); | |||
// quicksort(overlappingPairArray,0,overlappingPairArray.size()); | |||
overlappingPairArray.quickSort(btMultiSapBroadphasePairSortPredicate()); | |||
//perform a sort, to find duplicates and to sort 'invalid' pairs to the end | |||
// overlappingPairArray.heapSort(btMultiSapBroadphasePairSortPredicate()); | |||
overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); | |||
m_invalidPair = 0; | |||
int i; | |||
btBroadphasePair previousPair; | |||
previousPair.m_pProxy0 = 0; | |||
previousPair.m_pProxy1 = 0; | |||
previousPair.m_algorithm = 0; | |||
for (i=0;i<overlappingPairArray.size();i++) | |||
{ | |||
btBroadphasePair& pair = overlappingPairArray[i]; | |||
btMultiSapProxy* aProxy0 = pair.m_pProxy0 ? (btMultiSapProxy*)pair.m_pProxy0->m_multiSapParentProxy : 0; | |||
btMultiSapProxy* aProxy1 = pair.m_pProxy1 ? (btMultiSapProxy*)pair.m_pProxy1->m_multiSapParentProxy : 0; | |||
btMultiSapProxy* bProxy0 = previousPair.m_pProxy0 ? (btMultiSapProxy*)previousPair.m_pProxy0->m_multiSapParentProxy : 0; | |||
btMultiSapProxy* bProxy1 = previousPair.m_pProxy1 ? (btMultiSapProxy*)previousPair.m_pProxy1->m_multiSapParentProxy : 0; | |||
bool isDuplicate = (aProxy0 == bProxy0) && (aProxy1 == bProxy1); | |||
previousPair = pair; | |||
bool needsRemoval = false; | |||
if (!isDuplicate) | |||
{ | |||
bool hasOverlap = testAabbOverlap(pair.m_pProxy0,pair.m_pProxy1); | |||
if (hasOverlap) | |||
{ | |||
needsRemoval = false;//callback->processOverlap(pair); | |||
} else | |||
{ | |||
needsRemoval = true; | |||
} | |||
} else | |||
{ | |||
//remove duplicate | |||
needsRemoval = true; | |||
//should have no algorithm | |||
btAssert(!pair.m_algorithm); | |||
} | |||
if (needsRemoval) | |||
{ | |||
getOverlappingPairCache()->cleanOverlappingPair(pair,dispatcher); | |||
// m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); | |||
// m_overlappingPairArray.pop_back(); | |||
pair.m_pProxy0 = 0; | |||
pair.m_pProxy1 = 0; | |||
m_invalidPair++; | |||
gOverlappingPairs--; | |||
} | |||
} | |||
///if you don't like to skip the invalid pairs in the array, execute following code: | |||
#define CLEAN_INVALID_PAIRS 1 | |||
#ifdef CLEAN_INVALID_PAIRS | |||
//perform a sort, to sort 'invalid' pairs to the end | |||
//overlappingPairArray.heapSort(btMultiSapBroadphasePairSortPredicate()); | |||
overlappingPairArray.quickSort(btMultiSapBroadphasePairSortPredicate()); | |||
overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); | |||
m_invalidPair = 0; | |||
#endif//CLEAN_INVALID_PAIRS | |||
//printf("overlappingPairArray.size()=%d\n",overlappingPairArray.size()); | |||
} | |||
} | |||
bool btMultiSapBroadphase::testAabbOverlap(btBroadphaseProxy* childProxy0,btBroadphaseProxy* childProxy1) | |||
{ | |||
btMultiSapProxy* multiSapProxy0 = (btMultiSapProxy*)childProxy0->m_multiSapParentProxy; | |||
btMultiSapProxy* multiSapProxy1 = (btMultiSapProxy*)childProxy1->m_multiSapParentProxy; | |||
return TestAabbAgainstAabb2(multiSapProxy0->m_aabbMin,multiSapProxy0->m_aabbMax, | |||
multiSapProxy1->m_aabbMin,multiSapProxy1->m_aabbMax); | |||
} | |||
void btMultiSapBroadphase::printStats() | |||
{ | |||
/* printf("---------------------------------\n"); | |||
printf("btMultiSapBroadphase.h\n"); | |||
printf("numHandles = %d\n",m_multiSapProxies.size()); | |||
//find broadphase that contain this multiProxy | |||
int numChildBroadphases = getBroadphaseArray().size(); | |||
for (int i=0;i<numChildBroadphases;i++) | |||
{ | |||
btBroadphaseInterface* childBroadphase = getBroadphaseArray()[i]; | |||
childBroadphase->printStats(); | |||
} | |||
*/ | |||
} | |||
void btMultiSapBroadphase::resetPool(btDispatcher* dispatcher) | |||
{ | |||
// not yet | |||
} |
@@ -0,0 +1,151 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_MULTI_SAP_BROADPHASE | |||
#define BT_MULTI_SAP_BROADPHASE | |||
#include "btBroadphaseInterface.h" | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
#include "btOverlappingPairCache.h" | |||
class btBroadphaseInterface; | |||
class btSimpleBroadphase; | |||
typedef btAlignedObjectArray<btBroadphaseInterface*> btSapBroadphaseArray; | |||
///The btMultiSapBroadphase is a research project, not recommended to use in production. Use btAxisSweep3 or btDbvtBroadphase instead. | |||
///The btMultiSapBroadphase is a broadphase that contains multiple SAP broadphases. | |||
///The user can add SAP broadphases that cover the world. A btBroadphaseProxy can be in multiple child broadphases at the same time. | |||
///A btQuantizedBvh acceleration structures finds overlapping SAPs for each btBroadphaseProxy. | |||
///See http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=328 | |||
///and http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1329 | |||
class btMultiSapBroadphase :public btBroadphaseInterface | |||
{ | |||
btSapBroadphaseArray m_sapBroadphases; | |||
btSimpleBroadphase* m_simpleBroadphase; | |||
btOverlappingPairCache* m_overlappingPairs; | |||
class btQuantizedBvh* m_optimizedAabbTree; | |||
bool m_ownsPairCache; | |||
btOverlapFilterCallback* m_filterCallback; | |||
int m_invalidPair; | |||
struct btBridgeProxy | |||
{ | |||
btBroadphaseProxy* m_childProxy; | |||
btBroadphaseInterface* m_childBroadphase; | |||
}; | |||
public: | |||
struct btMultiSapProxy : public btBroadphaseProxy | |||
{ | |||
///array with all the entries that this proxy belongs to | |||
btAlignedObjectArray<btBridgeProxy*> m_bridgeProxies; | |||
btVector3 m_aabbMin; | |||
btVector3 m_aabbMax; | |||
int m_shapeType; | |||
/* void* m_userPtr; | |||
short int m_collisionFilterGroup; | |||
short int m_collisionFilterMask; | |||
*/ | |||
btMultiSapProxy(const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask) | |||
:btBroadphaseProxy(aabbMin,aabbMax,userPtr,collisionFilterGroup,collisionFilterMask), | |||
m_aabbMin(aabbMin), | |||
m_aabbMax(aabbMax), | |||
m_shapeType(shapeType) | |||
{ | |||
m_multiSapParentProxy =this; | |||
} | |||
}; | |||
protected: | |||
btAlignedObjectArray<btMultiSapProxy*> m_multiSapProxies; | |||
public: | |||
btMultiSapBroadphase(int maxProxies = 16384,btOverlappingPairCache* pairCache=0); | |||
btSapBroadphaseArray& getBroadphaseArray() | |||
{ | |||
return m_sapBroadphases; | |||
} | |||
const btSapBroadphaseArray& getBroadphaseArray() const | |||
{ | |||
return m_sapBroadphases; | |||
} | |||
virtual ~btMultiSapBroadphase(); | |||
virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy); | |||
virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher); | |||
virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; | |||
virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin=btVector3(0,0,0),const btVector3& aabbMax=btVector3(0,0,0)); | |||
void addToChildBroadphase(btMultiSapProxy* parentMultiSapProxy, btBroadphaseProxy* childProxy, btBroadphaseInterface* childBroadphase); | |||
///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb | |||
virtual void calculateOverlappingPairs(btDispatcher* dispatcher); | |||
bool testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); | |||
virtual btOverlappingPairCache* getOverlappingPairCache() | |||
{ | |||
return m_overlappingPairs; | |||
} | |||
virtual const btOverlappingPairCache* getOverlappingPairCache() const | |||
{ | |||
return m_overlappingPairs; | |||
} | |||
///getAabb returns the axis aligned bounding box in the 'global' coordinate frame | |||
///will add some transform later | |||
virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const | |||
{ | |||
aabbMin.setValue(-BT_LARGE_FLOAT,-BT_LARGE_FLOAT,-BT_LARGE_FLOAT); | |||
aabbMax.setValue(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT); | |||
} | |||
void buildTree(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax); | |||
virtual void printStats(); | |||
void quicksort (btBroadphasePairArray& a, int lo, int hi); | |||
///reset broadphase internal structures, to ensure determinism/reproducability | |||
virtual void resetPool(btDispatcher* dispatcher); | |||
}; | |||
#endif //BT_MULTI_SAP_BROADPHASE |
@@ -0,0 +1,633 @@ | |||
/* | |||
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 "btOverlappingPairCache.h" | |||
#include "btDispatcher.h" | |||
#include "btCollisionAlgorithm.h" | |||
#include "LinearMath/btAabbUtil2.h" | |||
#include <stdio.h> | |||
int gOverlappingPairs = 0; | |||
int gRemovePairs =0; | |||
int gAddedPairs =0; | |||
int gFindPairs =0; | |||
btHashedOverlappingPairCache::btHashedOverlappingPairCache(): | |||
m_overlapFilterCallback(0), | |||
m_blockedForChanges(false), | |||
m_ghostPairCallback(0) | |||
{ | |||
int initialAllocatedSize= 2; | |||
m_overlappingPairArray.reserve(initialAllocatedSize); | |||
growTables(); | |||
} | |||
btHashedOverlappingPairCache::~btHashedOverlappingPairCache() | |||
{ | |||
} | |||
void btHashedOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher) | |||
{ | |||
if (pair.m_algorithm) | |||
{ | |||
{ | |||
pair.m_algorithm->~btCollisionAlgorithm(); | |||
dispatcher->freeCollisionAlgorithm(pair.m_algorithm); | |||
pair.m_algorithm=0; | |||
} | |||
} | |||
} | |||
void btHashedOverlappingPairCache::cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher) | |||
{ | |||
class CleanPairCallback : public btOverlapCallback | |||
{ | |||
btBroadphaseProxy* m_cleanProxy; | |||
btOverlappingPairCache* m_pairCache; | |||
btDispatcher* m_dispatcher; | |||
public: | |||
CleanPairCallback(btBroadphaseProxy* cleanProxy,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) | |||
:m_cleanProxy(cleanProxy), | |||
m_pairCache(pairCache), | |||
m_dispatcher(dispatcher) | |||
{ | |||
} | |||
virtual bool processOverlap(btBroadphasePair& pair) | |||
{ | |||
if ((pair.m_pProxy0 == m_cleanProxy) || | |||
(pair.m_pProxy1 == m_cleanProxy)) | |||
{ | |||
m_pairCache->cleanOverlappingPair(pair,m_dispatcher); | |||
} | |||
return false; | |||
} | |||
}; | |||
CleanPairCallback cleanPairs(proxy,this,dispatcher); | |||
processAllOverlappingPairs(&cleanPairs,dispatcher); | |||
} | |||
void btHashedOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher) | |||
{ | |||
class RemovePairCallback : public btOverlapCallback | |||
{ | |||
btBroadphaseProxy* m_obsoleteProxy; | |||
public: | |||
RemovePairCallback(btBroadphaseProxy* obsoleteProxy) | |||
:m_obsoleteProxy(obsoleteProxy) | |||
{ | |||
} | |||
virtual bool processOverlap(btBroadphasePair& pair) | |||
{ | |||
return ((pair.m_pProxy0 == m_obsoleteProxy) || | |||
(pair.m_pProxy1 == m_obsoleteProxy)); | |||
} | |||
}; | |||
RemovePairCallback removeCallback(proxy); | |||
processAllOverlappingPairs(&removeCallback,dispatcher); | |||
} | |||
btBroadphasePair* btHashedOverlappingPairCache::findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) | |||
{ | |||
gFindPairs++; | |||
if(proxy0->m_uniqueId>proxy1->m_uniqueId) | |||
btSwap(proxy0,proxy1); | |||
int proxyId1 = proxy0->getUid(); | |||
int proxyId2 = proxy1->getUid(); | |||
/*if (proxyId1 > proxyId2) | |||
btSwap(proxyId1, proxyId2);*/ | |||
int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1), static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1)); | |||
if (hash >= m_hashTable.size()) | |||
{ | |||
return NULL; | |||
} | |||
int index = m_hashTable[hash]; | |||
while (index != BT_NULL_PAIR && equalsPair(m_overlappingPairArray[index], proxyId1, proxyId2) == false) | |||
{ | |||
index = m_next[index]; | |||
} | |||
if (index == BT_NULL_PAIR) | |||
{ | |||
return NULL; | |||
} | |||
btAssert(index < m_overlappingPairArray.size()); | |||
return &m_overlappingPairArray[index]; | |||
} | |||
//#include <stdio.h> | |||
void btHashedOverlappingPairCache::growTables() | |||
{ | |||
int newCapacity = m_overlappingPairArray.capacity(); | |||
if (m_hashTable.size() < newCapacity) | |||
{ | |||
//grow hashtable and next table | |||
int curHashtableSize = m_hashTable.size(); | |||
m_hashTable.resize(newCapacity); | |||
m_next.resize(newCapacity); | |||
int i; | |||
for (i= 0; i < newCapacity; ++i) | |||
{ | |||
m_hashTable[i] = BT_NULL_PAIR; | |||
} | |||
for (i = 0; i < newCapacity; ++i) | |||
{ | |||
m_next[i] = BT_NULL_PAIR; | |||
} | |||
for(i=0;i<curHashtableSize;i++) | |||
{ | |||
const btBroadphasePair& pair = m_overlappingPairArray[i]; | |||
int proxyId1 = pair.m_pProxy0->getUid(); | |||
int proxyId2 = pair.m_pProxy1->getUid(); | |||
/*if (proxyId1 > proxyId2) | |||
btSwap(proxyId1, proxyId2);*/ | |||
int hashValue = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1)); // New hash value with new mask | |||
m_next[i] = m_hashTable[hashValue]; | |||
m_hashTable[hashValue] = i; | |||
} | |||
} | |||
} | |||
btBroadphasePair* btHashedOverlappingPairCache::internalAddPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) | |||
{ | |||
if(proxy0->m_uniqueId>proxy1->m_uniqueId) | |||
btSwap(proxy0,proxy1); | |||
int proxyId1 = proxy0->getUid(); | |||
int proxyId2 = proxy1->getUid(); | |||
/*if (proxyId1 > proxyId2) | |||
btSwap(proxyId1, proxyId2);*/ | |||
int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1)); // New hash value with new mask | |||
btBroadphasePair* pair = internalFindPair(proxy0, proxy1, hash); | |||
if (pair != NULL) | |||
{ | |||
return pair; | |||
} | |||
/*for(int i=0;i<m_overlappingPairArray.size();++i) | |||
{ | |||
if( (m_overlappingPairArray[i].m_pProxy0==proxy0)&& | |||
(m_overlappingPairArray[i].m_pProxy1==proxy1)) | |||
{ | |||
printf("Adding duplicated %u<>%u\r\n",proxyId1,proxyId2); | |||
internalFindPair(proxy0, proxy1, hash); | |||
} | |||
}*/ | |||
int count = m_overlappingPairArray.size(); | |||
int oldCapacity = m_overlappingPairArray.capacity(); | |||
void* mem = &m_overlappingPairArray.expandNonInitializing(); | |||
//this is where we add an actual pair, so also call the 'ghost' | |||
if (m_ghostPairCallback) | |||
m_ghostPairCallback->addOverlappingPair(proxy0,proxy1); | |||
int newCapacity = m_overlappingPairArray.capacity(); | |||
if (oldCapacity < newCapacity) | |||
{ | |||
growTables(); | |||
//hash with new capacity | |||
hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1)); | |||
} | |||
pair = new (mem) btBroadphasePair(*proxy0,*proxy1); | |||
// pair->m_pProxy0 = proxy0; | |||
// pair->m_pProxy1 = proxy1; | |||
pair->m_algorithm = 0; | |||
pair->m_internalTmpValue = 0; | |||
m_next[count] = m_hashTable[hash]; | |||
m_hashTable[hash] = count; | |||
return pair; | |||
} | |||
void* btHashedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1,btDispatcher* dispatcher) | |||
{ | |||
gRemovePairs++; | |||
if(proxy0->m_uniqueId>proxy1->m_uniqueId) | |||
btSwap(proxy0,proxy1); | |||
int proxyId1 = proxy0->getUid(); | |||
int proxyId2 = proxy1->getUid(); | |||
/*if (proxyId1 > proxyId2) | |||
btSwap(proxyId1, proxyId2);*/ | |||
int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1)); | |||
btBroadphasePair* pair = internalFindPair(proxy0, proxy1, hash); | |||
if (pair == NULL) | |||
{ | |||
return 0; | |||
} | |||
cleanOverlappingPair(*pair,dispatcher); | |||
void* userData = pair->m_internalInfo1; | |||
btAssert(pair->m_pProxy0->getUid() == proxyId1); | |||
btAssert(pair->m_pProxy1->getUid() == proxyId2); | |||
int pairIndex = int(pair - &m_overlappingPairArray[0]); | |||
btAssert(pairIndex < m_overlappingPairArray.size()); | |||
// Remove the pair from the hash table. | |||
int index = m_hashTable[hash]; | |||
btAssert(index != BT_NULL_PAIR); | |||
int previous = BT_NULL_PAIR; | |||
while (index != pairIndex) | |||
{ | |||
previous = index; | |||
index = m_next[index]; | |||
} | |||
if (previous != BT_NULL_PAIR) | |||
{ | |||
btAssert(m_next[previous] == pairIndex); | |||
m_next[previous] = m_next[pairIndex]; | |||
} | |||
else | |||
{ | |||
m_hashTable[hash] = m_next[pairIndex]; | |||
} | |||
// We now move the last pair into spot of the | |||
// pair being removed. We need to fix the hash | |||
// table indices to support the move. | |||
int lastPairIndex = m_overlappingPairArray.size() - 1; | |||
if (m_ghostPairCallback) | |||
m_ghostPairCallback->removeOverlappingPair(proxy0, proxy1,dispatcher); | |||
// If the removed pair is the last pair, we are done. | |||
if (lastPairIndex == pairIndex) | |||
{ | |||
m_overlappingPairArray.pop_back(); | |||
return userData; | |||
} | |||
// Remove the last pair from the hash table. | |||
const btBroadphasePair* last = &m_overlappingPairArray[lastPairIndex]; | |||
/* missing swap here too, Nat. */ | |||
int lastHash = static_cast<int>(getHash(static_cast<unsigned int>(last->m_pProxy0->getUid()), static_cast<unsigned int>(last->m_pProxy1->getUid())) & (m_overlappingPairArray.capacity()-1)); | |||
index = m_hashTable[lastHash]; | |||
btAssert(index != BT_NULL_PAIR); | |||
previous = BT_NULL_PAIR; | |||
while (index != lastPairIndex) | |||
{ | |||
previous = index; | |||
index = m_next[index]; | |||
} | |||
if (previous != BT_NULL_PAIR) | |||
{ | |||
btAssert(m_next[previous] == lastPairIndex); | |||
m_next[previous] = m_next[lastPairIndex]; | |||
} | |||
else | |||
{ | |||
m_hashTable[lastHash] = m_next[lastPairIndex]; | |||
} | |||
// Copy the last pair into the remove pair's spot. | |||
m_overlappingPairArray[pairIndex] = m_overlappingPairArray[lastPairIndex]; | |||
// Insert the last pair into the hash table | |||
m_next[pairIndex] = m_hashTable[lastHash]; | |||
m_hashTable[lastHash] = pairIndex; | |||
m_overlappingPairArray.pop_back(); | |||
return userData; | |||
} | |||
//#include <stdio.h> | |||
void btHashedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher) | |||
{ | |||
int i; | |||
// printf("m_overlappingPairArray.size()=%d\n",m_overlappingPairArray.size()); | |||
for (i=0;i<m_overlappingPairArray.size();) | |||
{ | |||
btBroadphasePair* pair = &m_overlappingPairArray[i]; | |||
if (callback->processOverlap(*pair)) | |||
{ | |||
removeOverlappingPair(pair->m_pProxy0,pair->m_pProxy1,dispatcher); | |||
gOverlappingPairs--; | |||
} else | |||
{ | |||
i++; | |||
} | |||
} | |||
} | |||
void btHashedOverlappingPairCache::sortOverlappingPairs(btDispatcher* dispatcher) | |||
{ | |||
///need to keep hashmap in sync with pair address, so rebuild all | |||
btBroadphasePairArray tmpPairs; | |||
int i; | |||
for (i=0;i<m_overlappingPairArray.size();i++) | |||
{ | |||
tmpPairs.push_back(m_overlappingPairArray[i]); | |||
} | |||
for (i=0;i<tmpPairs.size();i++) | |||
{ | |||
removeOverlappingPair(tmpPairs[i].m_pProxy0,tmpPairs[i].m_pProxy1,dispatcher); | |||
} | |||
for (i = 0; i < m_next.size(); i++) | |||
{ | |||
m_next[i] = BT_NULL_PAIR; | |||
} | |||
tmpPairs.quickSort(btBroadphasePairSortPredicate()); | |||
for (i=0;i<tmpPairs.size();i++) | |||
{ | |||
addOverlappingPair(tmpPairs[i].m_pProxy0,tmpPairs[i].m_pProxy1); | |||
} | |||
} | |||
void* btSortedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1, btDispatcher* dispatcher ) | |||
{ | |||
if (!hasDeferredRemoval()) | |||
{ | |||
btBroadphasePair findPair(*proxy0,*proxy1); | |||
int findIndex = m_overlappingPairArray.findLinearSearch(findPair); | |||
if (findIndex < m_overlappingPairArray.size()) | |||
{ | |||
gOverlappingPairs--; | |||
btBroadphasePair& pair = m_overlappingPairArray[findIndex]; | |||
void* userData = pair.m_internalInfo1; | |||
cleanOverlappingPair(pair,dispatcher); | |||
if (m_ghostPairCallback) | |||
m_ghostPairCallback->removeOverlappingPair(proxy0, proxy1,dispatcher); | |||
m_overlappingPairArray.swap(findIndex,m_overlappingPairArray.capacity()-1); | |||
m_overlappingPairArray.pop_back(); | |||
return userData; | |||
} | |||
} | |||
return 0; | |||
} | |||
btBroadphasePair* btSortedOverlappingPairCache::addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) | |||
{ | |||
//don't add overlap with own | |||
btAssert(proxy0 != proxy1); | |||
if (!needsBroadphaseCollision(proxy0,proxy1)) | |||
return 0; | |||
void* mem = &m_overlappingPairArray.expandNonInitializing(); | |||
btBroadphasePair* pair = new (mem) btBroadphasePair(*proxy0,*proxy1); | |||
gOverlappingPairs++; | |||
gAddedPairs++; | |||
if (m_ghostPairCallback) | |||
m_ghostPairCallback->addOverlappingPair(proxy0, proxy1); | |||
return pair; | |||
} | |||
///this findPair becomes really slow. Either sort the list to speedup the query, or | |||
///use a different solution. It is mainly used for Removing overlapping pairs. Removal could be delayed. | |||
///we could keep a linked list in each proxy, and store pair in one of the proxies (with lowest memory address) | |||
///Also we can use a 2D bitmap, which can be useful for a future GPU implementation | |||
btBroadphasePair* btSortedOverlappingPairCache::findPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) | |||
{ | |||
if (!needsBroadphaseCollision(proxy0,proxy1)) | |||
return 0; | |||
btBroadphasePair tmpPair(*proxy0,*proxy1); | |||
int findIndex = m_overlappingPairArray.findLinearSearch(tmpPair); | |||
if (findIndex < m_overlappingPairArray.size()) | |||
{ | |||
//btAssert(it != m_overlappingPairSet.end()); | |||
btBroadphasePair* pair = &m_overlappingPairArray[findIndex]; | |||
return pair; | |||
} | |||
return 0; | |||
} | |||
//#include <stdio.h> | |||
void btSortedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher) | |||
{ | |||
int i; | |||
for (i=0;i<m_overlappingPairArray.size();) | |||
{ | |||
btBroadphasePair* pair = &m_overlappingPairArray[i]; | |||
if (callback->processOverlap(*pair)) | |||
{ | |||
cleanOverlappingPair(*pair,dispatcher); | |||
pair->m_pProxy0 = 0; | |||
pair->m_pProxy1 = 0; | |||
m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); | |||
m_overlappingPairArray.pop_back(); | |||
gOverlappingPairs--; | |||
} else | |||
{ | |||
i++; | |||
} | |||
} | |||
} | |||
btSortedOverlappingPairCache::btSortedOverlappingPairCache(): | |||
m_blockedForChanges(false), | |||
m_hasDeferredRemoval(true), | |||
m_overlapFilterCallback(0), | |||
m_ghostPairCallback(0) | |||
{ | |||
int initialAllocatedSize= 2; | |||
m_overlappingPairArray.reserve(initialAllocatedSize); | |||
} | |||
btSortedOverlappingPairCache::~btSortedOverlappingPairCache() | |||
{ | |||
} | |||
void btSortedOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher) | |||
{ | |||
if (pair.m_algorithm) | |||
{ | |||
{ | |||
pair.m_algorithm->~btCollisionAlgorithm(); | |||
dispatcher->freeCollisionAlgorithm(pair.m_algorithm); | |||
pair.m_algorithm=0; | |||
gRemovePairs--; | |||
} | |||
} | |||
} | |||
void btSortedOverlappingPairCache::cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher) | |||
{ | |||
class CleanPairCallback : public btOverlapCallback | |||
{ | |||
btBroadphaseProxy* m_cleanProxy; | |||
btOverlappingPairCache* m_pairCache; | |||
btDispatcher* m_dispatcher; | |||
public: | |||
CleanPairCallback(btBroadphaseProxy* cleanProxy,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) | |||
:m_cleanProxy(cleanProxy), | |||
m_pairCache(pairCache), | |||
m_dispatcher(dispatcher) | |||
{ | |||
} | |||
virtual bool processOverlap(btBroadphasePair& pair) | |||
{ | |||
if ((pair.m_pProxy0 == m_cleanProxy) || | |||
(pair.m_pProxy1 == m_cleanProxy)) | |||
{ | |||
m_pairCache->cleanOverlappingPair(pair,m_dispatcher); | |||
} | |||
return false; | |||
} | |||
}; | |||
CleanPairCallback cleanPairs(proxy,this,dispatcher); | |||
processAllOverlappingPairs(&cleanPairs,dispatcher); | |||
} | |||
void btSortedOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher) | |||
{ | |||
class RemovePairCallback : public btOverlapCallback | |||
{ | |||
btBroadphaseProxy* m_obsoleteProxy; | |||
public: | |||
RemovePairCallback(btBroadphaseProxy* obsoleteProxy) | |||
:m_obsoleteProxy(obsoleteProxy) | |||
{ | |||
} | |||
virtual bool processOverlap(btBroadphasePair& pair) | |||
{ | |||
return ((pair.m_pProxy0 == m_obsoleteProxy) || | |||
(pair.m_pProxy1 == m_obsoleteProxy)); | |||
} | |||
}; | |||
RemovePairCallback removeCallback(proxy); | |||
processAllOverlappingPairs(&removeCallback,dispatcher); | |||
} | |||
void btSortedOverlappingPairCache::sortOverlappingPairs(btDispatcher* dispatcher) | |||
{ | |||
//should already be sorted | |||
} | |||
@@ -0,0 +1,469 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_OVERLAPPING_PAIR_CACHE_H | |||
#define BT_OVERLAPPING_PAIR_CACHE_H | |||
#include "btBroadphaseInterface.h" | |||
#include "btBroadphaseProxy.h" | |||
#include "btOverlappingPairCallback.h" | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
class btDispatcher; | |||
typedef btAlignedObjectArray<btBroadphasePair> btBroadphasePairArray; | |||
struct btOverlapCallback | |||
{ | |||
virtual ~btOverlapCallback() | |||
{} | |||
//return true for deletion of the pair | |||
virtual bool processOverlap(btBroadphasePair& pair) = 0; | |||
}; | |||
struct btOverlapFilterCallback | |||
{ | |||
virtual ~btOverlapFilterCallback() | |||
{} | |||
// return true when pairs need collision | |||
virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const = 0; | |||
}; | |||
extern int gRemovePairs; | |||
extern int gAddedPairs; | |||
extern int gFindPairs; | |||
const int BT_NULL_PAIR=0xffffffff; | |||
///The btOverlappingPairCache provides an interface for overlapping pair management (add, remove, storage), used by the btBroadphaseInterface broadphases. | |||
///The btHashedOverlappingPairCache and btSortedOverlappingPairCache classes are two implementations. | |||
class btOverlappingPairCache : public btOverlappingPairCallback | |||
{ | |||
public: | |||
virtual ~btOverlappingPairCache() {} // this is needed so we can get to the derived class destructor | |||
virtual btBroadphasePair* getOverlappingPairArrayPtr() = 0; | |||
virtual const btBroadphasePair* getOverlappingPairArrayPtr() const = 0; | |||
virtual btBroadphasePairArray& getOverlappingPairArray() = 0; | |||
virtual void cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher) = 0; | |||
virtual int getNumOverlappingPairs() const = 0; | |||
virtual void cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher) = 0; | |||
virtual void setOverlapFilterCallback(btOverlapFilterCallback* callback) = 0; | |||
virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher) = 0; | |||
virtual btBroadphasePair* findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) = 0; | |||
virtual bool hasDeferredRemoval() = 0; | |||
virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback)=0; | |||
virtual void sortOverlappingPairs(btDispatcher* dispatcher) = 0; | |||
}; | |||
/// Hash-space based Pair Cache, thanks to Erin Catto, Box2D, http://www.box2d.org, and Pierre Terdiman, Codercorner, http://codercorner.com | |||
class btHashedOverlappingPairCache : public btOverlappingPairCache | |||
{ | |||
btBroadphasePairArray m_overlappingPairArray; | |||
btOverlapFilterCallback* m_overlapFilterCallback; | |||
bool m_blockedForChanges; | |||
public: | |||
btHashedOverlappingPairCache(); | |||
virtual ~btHashedOverlappingPairCache(); | |||
void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher); | |||
SIMD_FORCE_INLINE bool needsBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const | |||
{ | |||
if (m_overlapFilterCallback) | |||
return m_overlapFilterCallback->needBroadphaseCollision(proxy0,proxy1); | |||
bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; | |||
collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); | |||
return collides; | |||
} | |||
// Add a pair and return the new pair. If the pair already exists, | |||
// no new pair is created and the old one is returned. | |||
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) | |||
{ | |||
gAddedPairs++; | |||
if (!needsBroadphaseCollision(proxy0,proxy1)) | |||
return 0; | |||
return internalAddPair(proxy0,proxy1); | |||
} | |||
void cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher); | |||
virtual btBroadphasePair* getOverlappingPairArrayPtr() | |||
{ | |||
return &m_overlappingPairArray[0]; | |||
} | |||
const btBroadphasePair* getOverlappingPairArrayPtr() const | |||
{ | |||
return &m_overlappingPairArray[0]; | |||
} | |||
btBroadphasePairArray& getOverlappingPairArray() | |||
{ | |||
return m_overlappingPairArray; | |||
} | |||
const btBroadphasePairArray& getOverlappingPairArray() const | |||
{ | |||
return m_overlappingPairArray; | |||
} | |||
void cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher); | |||
btBroadphasePair* findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1); | |||
int GetCount() const { return m_overlappingPairArray.size(); } | |||
// btBroadphasePair* GetPairs() { return m_pairs; } | |||
btOverlapFilterCallback* getOverlapFilterCallback() | |||
{ | |||
return m_overlapFilterCallback; | |||
} | |||
void setOverlapFilterCallback(btOverlapFilterCallback* callback) | |||
{ | |||
m_overlapFilterCallback = callback; | |||
} | |||
int getNumOverlappingPairs() const | |||
{ | |||
return m_overlappingPairArray.size(); | |||
} | |||
private: | |||
btBroadphasePair* internalAddPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); | |||
void growTables(); | |||
SIMD_FORCE_INLINE bool equalsPair(const btBroadphasePair& pair, int proxyId1, int proxyId2) | |||
{ | |||
return pair.m_pProxy0->getUid() == proxyId1 && pair.m_pProxy1->getUid() == proxyId2; | |||
} | |||
/* | |||
// Thomas Wang's hash, see: http://www.concentric.net/~Ttwang/tech/inthash.htm | |||
// This assumes proxyId1 and proxyId2 are 16-bit. | |||
SIMD_FORCE_INLINE int getHash(int proxyId1, int proxyId2) | |||
{ | |||
int key = (proxyId2 << 16) | proxyId1; | |||
key = ~key + (key << 15); | |||
key = key ^ (key >> 12); | |||
key = key + (key << 2); | |||
key = key ^ (key >> 4); | |||
key = key * 2057; | |||
key = key ^ (key >> 16); | |||
return key; | |||
} | |||
*/ | |||
SIMD_FORCE_INLINE unsigned int getHash(unsigned int proxyId1, unsigned int proxyId2) | |||
{ | |||
int key = static_cast<int>(((unsigned int)proxyId1) | (((unsigned int)proxyId2) <<16)); | |||
// Thomas Wang's hash | |||
key += ~(key << 15); | |||
key ^= (key >> 10); | |||
key += (key << 3); | |||
key ^= (key >> 6); | |||
key += ~(key << 11); | |||
key ^= (key >> 16); | |||
return static_cast<unsigned int>(key); | |||
} | |||
SIMD_FORCE_INLINE btBroadphasePair* internalFindPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1, int hash) | |||
{ | |||
int proxyId1 = proxy0->getUid(); | |||
int proxyId2 = proxy1->getUid(); | |||
#if 0 // wrong, 'equalsPair' use unsorted uids, copy-past devil striked again. Nat. | |||
if (proxyId1 > proxyId2) | |||
btSwap(proxyId1, proxyId2); | |||
#endif | |||
int index = m_hashTable[hash]; | |||
while( index != BT_NULL_PAIR && equalsPair(m_overlappingPairArray[index], proxyId1, proxyId2) == false) | |||
{ | |||
index = m_next[index]; | |||
} | |||
if ( index == BT_NULL_PAIR ) | |||
{ | |||
return NULL; | |||
} | |||
btAssert(index < m_overlappingPairArray.size()); | |||
return &m_overlappingPairArray[index]; | |||
} | |||
virtual bool hasDeferredRemoval() | |||
{ | |||
return false; | |||
} | |||
virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback) | |||
{ | |||
m_ghostPairCallback = ghostPairCallback; | |||
} | |||
virtual void sortOverlappingPairs(btDispatcher* dispatcher); | |||
protected: | |||
btAlignedObjectArray<int> m_hashTable; | |||
btAlignedObjectArray<int> m_next; | |||
btOverlappingPairCallback* m_ghostPairCallback; | |||
}; | |||
///btSortedOverlappingPairCache maintains the objects with overlapping AABB | |||
///Typically managed by the Broadphase, Axis3Sweep or btSimpleBroadphase | |||
class btSortedOverlappingPairCache : public btOverlappingPairCache | |||
{ | |||
protected: | |||
//avoid brute-force finding all the time | |||
btBroadphasePairArray m_overlappingPairArray; | |||
//during the dispatch, check that user doesn't destroy/create proxy | |||
bool m_blockedForChanges; | |||
///by default, do the removal during the pair traversal | |||
bool m_hasDeferredRemoval; | |||
//if set, use the callback instead of the built in filter in needBroadphaseCollision | |||
btOverlapFilterCallback* m_overlapFilterCallback; | |||
btOverlappingPairCallback* m_ghostPairCallback; | |||
public: | |||
btSortedOverlappingPairCache(); | |||
virtual ~btSortedOverlappingPairCache(); | |||
virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher); | |||
void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher); | |||
void cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher); | |||
btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); | |||
btBroadphasePair* findPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); | |||
void cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
inline bool needsBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const | |||
{ | |||
if (m_overlapFilterCallback) | |||
return m_overlapFilterCallback->needBroadphaseCollision(proxy0,proxy1); | |||
bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; | |||
collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); | |||
return collides; | |||
} | |||
btBroadphasePairArray& getOverlappingPairArray() | |||
{ | |||
return m_overlappingPairArray; | |||
} | |||
const btBroadphasePairArray& getOverlappingPairArray() const | |||
{ | |||
return m_overlappingPairArray; | |||
} | |||
btBroadphasePair* getOverlappingPairArrayPtr() | |||
{ | |||
return &m_overlappingPairArray[0]; | |||
} | |||
const btBroadphasePair* getOverlappingPairArrayPtr() const | |||
{ | |||
return &m_overlappingPairArray[0]; | |||
} | |||
int getNumOverlappingPairs() const | |||
{ | |||
return m_overlappingPairArray.size(); | |||
} | |||
btOverlapFilterCallback* getOverlapFilterCallback() | |||
{ | |||
return m_overlapFilterCallback; | |||
} | |||
void setOverlapFilterCallback(btOverlapFilterCallback* callback) | |||
{ | |||
m_overlapFilterCallback = callback; | |||
} | |||
virtual bool hasDeferredRemoval() | |||
{ | |||
return m_hasDeferredRemoval; | |||
} | |||
virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback) | |||
{ | |||
m_ghostPairCallback = ghostPairCallback; | |||
} | |||
virtual void sortOverlappingPairs(btDispatcher* dispatcher); | |||
}; | |||
///btNullPairCache skips add/removal of overlapping pairs. Userful for benchmarking and unit testing. | |||
class btNullPairCache : public btOverlappingPairCache | |||
{ | |||
btBroadphasePairArray m_overlappingPairArray; | |||
public: | |||
virtual btBroadphasePair* getOverlappingPairArrayPtr() | |||
{ | |||
return &m_overlappingPairArray[0]; | |||
} | |||
const btBroadphasePair* getOverlappingPairArrayPtr() const | |||
{ | |||
return &m_overlappingPairArray[0]; | |||
} | |||
btBroadphasePairArray& getOverlappingPairArray() | |||
{ | |||
return m_overlappingPairArray; | |||
} | |||
virtual void cleanOverlappingPair(btBroadphasePair& /*pair*/,btDispatcher* /*dispatcher*/) | |||
{ | |||
} | |||
virtual int getNumOverlappingPairs() const | |||
{ | |||
return 0; | |||
} | |||
virtual void cleanProxyFromPairs(btBroadphaseProxy* /*proxy*/,btDispatcher* /*dispatcher*/) | |||
{ | |||
} | |||
virtual void setOverlapFilterCallback(btOverlapFilterCallback* /*callback*/) | |||
{ | |||
} | |||
virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* /*dispatcher*/) | |||
{ | |||
} | |||
virtual btBroadphasePair* findPair(btBroadphaseProxy* /*proxy0*/, btBroadphaseProxy* /*proxy1*/) | |||
{ | |||
return 0; | |||
} | |||
virtual bool hasDeferredRemoval() | |||
{ | |||
return true; | |||
} | |||
virtual void setInternalGhostPairCallback(btOverlappingPairCallback* /* ghostPairCallback */) | |||
{ | |||
} | |||
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* /*proxy0*/,btBroadphaseProxy* /*proxy1*/) | |||
{ | |||
return 0; | |||
} | |||
virtual void* removeOverlappingPair(btBroadphaseProxy* /*proxy0*/,btBroadphaseProxy* /*proxy1*/,btDispatcher* /*dispatcher*/) | |||
{ | |||
return 0; | |||
} | |||
virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* /*proxy0*/,btDispatcher* /*dispatcher*/) | |||
{ | |||
} | |||
virtual void sortOverlappingPairs(btDispatcher* dispatcher) | |||
{ | |||
(void) dispatcher; | |||
} | |||
}; | |||
#endif //BT_OVERLAPPING_PAIR_CACHE_H | |||
@@ -0,0 +1,40 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef OVERLAPPING_PAIR_CALLBACK_H | |||
#define OVERLAPPING_PAIR_CALLBACK_H | |||
class btDispatcher; | |||
struct btBroadphasePair; | |||
///The btOverlappingPairCallback class is an additional optional broadphase user callback for adding/removing overlapping pairs, similar interface to btOverlappingPairCache. | |||
class btOverlappingPairCallback | |||
{ | |||
public: | |||
virtual ~btOverlappingPairCallback() | |||
{ | |||
} | |||
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) = 0; | |||
virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher) = 0; | |||
virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy0,btDispatcher* dispatcher) = 0; | |||
}; | |||
#endif //OVERLAPPING_PAIR_CALLBACK_H |
@@ -0,0 +1,579 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_QUANTIZED_BVH_H | |||
#define BT_QUANTIZED_BVH_H | |||
class btSerializer; | |||
//#define DEBUG_CHECK_DEQUANTIZATION 1 | |||
#ifdef DEBUG_CHECK_DEQUANTIZATION | |||
#ifdef __SPU__ | |||
#define printf spu_printf | |||
#endif //__SPU__ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#endif //DEBUG_CHECK_DEQUANTIZATION | |||
#include "LinearMath/btVector3.h" | |||
#include "LinearMath/btAlignedAllocator.h" | |||
#ifdef BT_USE_DOUBLE_PRECISION | |||
#define btQuantizedBvhData btQuantizedBvhDoubleData | |||
#define btOptimizedBvhNodeData btOptimizedBvhNodeDoubleData | |||
#define btQuantizedBvhDataName "btQuantizedBvhDoubleData" | |||
#else | |||
#define btQuantizedBvhData btQuantizedBvhFloatData | |||
#define btOptimizedBvhNodeData btOptimizedBvhNodeFloatData | |||
#define btQuantizedBvhDataName "btQuantizedBvhFloatData" | |||
#endif | |||
//http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrf__m128.asp | |||
//Note: currently we have 16 bytes per quantized node | |||
#define MAX_SUBTREE_SIZE_IN_BYTES 2048 | |||
// 10 gives the potential for 1024 parts, with at most 2^21 (2097152) (minus one | |||
// actually) triangles each (since the sign bit is reserved | |||
#define MAX_NUM_PARTS_IN_BITS 10 | |||
///btQuantizedBvhNode is a compressed aabb node, 16 bytes. | |||
///Node can be used for leafnode or internal node. Leafnodes can point to 32-bit triangle index (non-negative range). | |||
ATTRIBUTE_ALIGNED16 (struct) btQuantizedBvhNode | |||
{ | |||
BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
//12 bytes | |||
unsigned short int m_quantizedAabbMin[3]; | |||
unsigned short int m_quantizedAabbMax[3]; | |||
//4 bytes | |||
int m_escapeIndexOrTriangleIndex; | |||
bool isLeafNode() const | |||
{ | |||
//skipindex is negative (internal node), triangleindex >=0 (leafnode) | |||
return (m_escapeIndexOrTriangleIndex >= 0); | |||
} | |||
int getEscapeIndex() const | |||
{ | |||
btAssert(!isLeafNode()); | |||
return -m_escapeIndexOrTriangleIndex; | |||
} | |||
int getTriangleIndex() const | |||
{ | |||
btAssert(isLeafNode()); | |||
// Get only the lower bits where the triangle index is stored | |||
return (m_escapeIndexOrTriangleIndex&~((~0)<<(31-MAX_NUM_PARTS_IN_BITS))); | |||
} | |||
int getPartId() const | |||
{ | |||
btAssert(isLeafNode()); | |||
// Get only the highest bits where the part index is stored | |||
return (m_escapeIndexOrTriangleIndex>>(31-MAX_NUM_PARTS_IN_BITS)); | |||
} | |||
} | |||
; | |||
/// btOptimizedBvhNode contains both internal and leaf node information. | |||
/// Total node size is 44 bytes / node. You can use the compressed version of 16 bytes. | |||
ATTRIBUTE_ALIGNED16 (struct) btOptimizedBvhNode | |||
{ | |||
BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
//32 bytes | |||
btVector3 m_aabbMinOrg; | |||
btVector3 m_aabbMaxOrg; | |||
//4 | |||
int m_escapeIndex; | |||
//8 | |||
//for child nodes | |||
int m_subPart; | |||
int m_triangleIndex; | |||
//pad the size to 64 bytes | |||
char m_padding[20]; | |||
}; | |||
///btBvhSubtreeInfo provides info to gather a subtree of limited size | |||
ATTRIBUTE_ALIGNED16(class) btBvhSubtreeInfo | |||
{ | |||
public: | |||
BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
//12 bytes | |||
unsigned short int m_quantizedAabbMin[3]; | |||
unsigned short int m_quantizedAabbMax[3]; | |||
//4 bytes, points to the root of the subtree | |||
int m_rootNodeIndex; | |||
//4 bytes | |||
int m_subtreeSize; | |||
int m_padding[3]; | |||
btBvhSubtreeInfo() | |||
{ | |||
//memset(&m_padding[0], 0, sizeof(m_padding)); | |||
} | |||
void setAabbFromQuantizeNode(const btQuantizedBvhNode& quantizedNode) | |||
{ | |||
m_quantizedAabbMin[0] = quantizedNode.m_quantizedAabbMin[0]; | |||
m_quantizedAabbMin[1] = quantizedNode.m_quantizedAabbMin[1]; | |||
m_quantizedAabbMin[2] = quantizedNode.m_quantizedAabbMin[2]; | |||
m_quantizedAabbMax[0] = quantizedNode.m_quantizedAabbMax[0]; | |||
m_quantizedAabbMax[1] = quantizedNode.m_quantizedAabbMax[1]; | |||
m_quantizedAabbMax[2] = quantizedNode.m_quantizedAabbMax[2]; | |||
} | |||
} | |||
; | |||
class btNodeOverlapCallback | |||
{ | |||
public: | |||
virtual ~btNodeOverlapCallback() {}; | |||
virtual void processNode(int subPart, int triangleIndex) = 0; | |||
}; | |||
#include "LinearMath/btAlignedAllocator.h" | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
///for code readability: | |||
typedef btAlignedObjectArray<btOptimizedBvhNode> NodeArray; | |||
typedef btAlignedObjectArray<btQuantizedBvhNode> QuantizedNodeArray; | |||
typedef btAlignedObjectArray<btBvhSubtreeInfo> BvhSubtreeInfoArray; | |||
///The btQuantizedBvh class stores an AABB tree that can be quickly traversed on CPU and Cell SPU. | |||
///It is used by the btBvhTriangleMeshShape as midphase, and by the btMultiSapBroadphase. | |||
///It is recommended to use quantization for better performance and lower memory requirements. | |||
ATTRIBUTE_ALIGNED16(class) btQuantizedBvh | |||
{ | |||
public: | |||
enum btTraversalMode | |||
{ | |||
TRAVERSAL_STACKLESS = 0, | |||
TRAVERSAL_STACKLESS_CACHE_FRIENDLY, | |||
TRAVERSAL_RECURSIVE | |||
}; | |||
protected: | |||
btVector3 m_bvhAabbMin; | |||
btVector3 m_bvhAabbMax; | |||
btVector3 m_bvhQuantization; | |||
int m_bulletVersion; //for serialization versioning. It could also be used to detect endianess. | |||
int m_curNodeIndex; | |||
//quantization data | |||
bool m_useQuantization; | |||
NodeArray m_leafNodes; | |||
NodeArray m_contiguousNodes; | |||
QuantizedNodeArray m_quantizedLeafNodes; | |||
QuantizedNodeArray m_quantizedContiguousNodes; | |||
btTraversalMode m_traversalMode; | |||
BvhSubtreeInfoArray m_SubtreeHeaders; | |||
//This is only used for serialization so we don't have to add serialization directly to btAlignedObjectArray | |||
mutable int m_subtreeHeaderCount; | |||
///two versions, one for quantized and normal nodes. This allows code-reuse while maintaining readability (no template/macro!) | |||
///this might be refactored into a virtual, it is usually not calculated at run-time | |||
void setInternalNodeAabbMin(int nodeIndex, const btVector3& aabbMin) | |||
{ | |||
if (m_useQuantization) | |||
{ | |||
quantize(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] ,aabbMin,0); | |||
} else | |||
{ | |||
m_contiguousNodes[nodeIndex].m_aabbMinOrg = aabbMin; | |||
} | |||
} | |||
void setInternalNodeAabbMax(int nodeIndex,const btVector3& aabbMax) | |||
{ | |||
if (m_useQuantization) | |||
{ | |||
quantize(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0],aabbMax,1); | |||
} else | |||
{ | |||
m_contiguousNodes[nodeIndex].m_aabbMaxOrg = aabbMax; | |||
} | |||
} | |||
btVector3 getAabbMin(int nodeIndex) const | |||
{ | |||
if (m_useQuantization) | |||
{ | |||
return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMin[0]); | |||
} | |||
//non-quantized | |||
return m_leafNodes[nodeIndex].m_aabbMinOrg; | |||
} | |||
btVector3 getAabbMax(int nodeIndex) const | |||
{ | |||
if (m_useQuantization) | |||
{ | |||
return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMax[0]); | |||
} | |||
//non-quantized | |||
return m_leafNodes[nodeIndex].m_aabbMaxOrg; | |||
} | |||
void setInternalNodeEscapeIndex(int nodeIndex, int escapeIndex) | |||
{ | |||
if (m_useQuantization) | |||
{ | |||
m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = -escapeIndex; | |||
} | |||
else | |||
{ | |||
m_contiguousNodes[nodeIndex].m_escapeIndex = escapeIndex; | |||
} | |||
} | |||
void mergeInternalNodeAabb(int nodeIndex,const btVector3& newAabbMin,const btVector3& newAabbMax) | |||
{ | |||
if (m_useQuantization) | |||
{ | |||
unsigned short int quantizedAabbMin[3]; | |||
unsigned short int quantizedAabbMax[3]; | |||
quantize(quantizedAabbMin,newAabbMin,0); | |||
quantize(quantizedAabbMax,newAabbMax,1); | |||
for (int i=0;i<3;i++) | |||
{ | |||
if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] > quantizedAabbMin[i]) | |||
m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] = quantizedAabbMin[i]; | |||
if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] < quantizedAabbMax[i]) | |||
m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] = quantizedAabbMax[i]; | |||
} | |||
} else | |||
{ | |||
//non-quantized | |||
m_contiguousNodes[nodeIndex].m_aabbMinOrg.setMin(newAabbMin); | |||
m_contiguousNodes[nodeIndex].m_aabbMaxOrg.setMax(newAabbMax); | |||
} | |||
} | |||
void swapLeafNodes(int firstIndex,int secondIndex); | |||
void assignInternalNodeFromLeafNode(int internalNode,int leafNodeIndex); | |||
protected: | |||
void buildTree (int startIndex,int endIndex); | |||
int calcSplittingAxis(int startIndex,int endIndex); | |||
int sortAndCalcSplittingIndex(int startIndex,int endIndex,int splitAxis); | |||
void walkStacklessTree(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const; | |||
void walkStacklessQuantizedTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex,int endNodeIndex) const; | |||
void walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,int startNodeIndex,int endNodeIndex) const; | |||
void walkStacklessTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex,int endNodeIndex) const; | |||
///tree traversal designed for small-memory processors like PS3 SPU | |||
void walkStacklessQuantizedTreeCacheFriendly(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const; | |||
///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal | |||
void walkRecursiveQuantizedTreeAgainstQueryAabb(const btQuantizedBvhNode* currentNode,btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const; | |||
///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal | |||
void walkRecursiveQuantizedTreeAgainstQuantizedTree(const btQuantizedBvhNode* treeNodeA,const btQuantizedBvhNode* treeNodeB,btNodeOverlapCallback* nodeCallback) const; | |||
void updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex); | |||
public: | |||
BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
btQuantizedBvh(); | |||
virtual ~btQuantizedBvh(); | |||
///***************************************** expert/internal use only ************************* | |||
void setQuantizationValues(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,btScalar quantizationMargin=btScalar(1.0)); | |||
QuantizedNodeArray& getLeafNodeArray() { return m_quantizedLeafNodes; } | |||
///buildInternal is expert use only: assumes that setQuantizationValues and LeafNodeArray are initialized | |||
void buildInternal(); | |||
///***************************************** expert/internal use only ************************* | |||
void reportAabbOverlappingNodex(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const; | |||
void reportRayOverlappingNodex (btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget) const; | |||
void reportBoxCastOverlappingNodex(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin,const btVector3& aabbMax) const; | |||
SIMD_FORCE_INLINE void quantize(unsigned short* out, const btVector3& point,int isMax) const | |||
{ | |||
btAssert(m_useQuantization); | |||
btAssert(point.getX() <= m_bvhAabbMax.getX()); | |||
btAssert(point.getY() <= m_bvhAabbMax.getY()); | |||
btAssert(point.getZ() <= m_bvhAabbMax.getZ()); | |||
btAssert(point.getX() >= m_bvhAabbMin.getX()); | |||
btAssert(point.getY() >= m_bvhAabbMin.getY()); | |||
btAssert(point.getZ() >= m_bvhAabbMin.getZ()); | |||
btVector3 v = (point - m_bvhAabbMin) * m_bvhQuantization; | |||
///Make sure rounding is done in a way that unQuantize(quantizeWithClamp(...)) is conservative | |||
///end-points always set the first bit, so that they are sorted properly (so that neighbouring AABBs overlap properly) | |||
///@todo: double-check this | |||
if (isMax) | |||
{ | |||
out[0] = (unsigned short) (((unsigned short)(v.getX()+btScalar(1.)) | 1)); | |||
out[1] = (unsigned short) (((unsigned short)(v.getY()+btScalar(1.)) | 1)); | |||
out[2] = (unsigned short) (((unsigned short)(v.getZ()+btScalar(1.)) | 1)); | |||
} else | |||
{ | |||
out[0] = (unsigned short) (((unsigned short)(v.getX()) & 0xfffe)); | |||
out[1] = (unsigned short) (((unsigned short)(v.getY()) & 0xfffe)); | |||
out[2] = (unsigned short) (((unsigned short)(v.getZ()) & 0xfffe)); | |||
} | |||
#ifdef DEBUG_CHECK_DEQUANTIZATION | |||
btVector3 newPoint = unQuantize(out); | |||
if (isMax) | |||
{ | |||
if (newPoint.getX() < point.getX()) | |||
{ | |||
printf("unconservative X, diffX = %f, oldX=%f,newX=%f\n",newPoint.getX()-point.getX(), newPoint.getX(),point.getX()); | |||
} | |||
if (newPoint.getY() < point.getY()) | |||
{ | |||
printf("unconservative Y, diffY = %f, oldY=%f,newY=%f\n",newPoint.getY()-point.getY(), newPoint.getY(),point.getY()); | |||
} | |||
if (newPoint.getZ() < point.getZ()) | |||
{ | |||
printf("unconservative Z, diffZ = %f, oldZ=%f,newZ=%f\n",newPoint.getZ()-point.getZ(), newPoint.getZ(),point.getZ()); | |||
} | |||
} else | |||
{ | |||
if (newPoint.getX() > point.getX()) | |||
{ | |||
printf("unconservative X, diffX = %f, oldX=%f,newX=%f\n",newPoint.getX()-point.getX(), newPoint.getX(),point.getX()); | |||
} | |||
if (newPoint.getY() > point.getY()) | |||
{ | |||
printf("unconservative Y, diffY = %f, oldY=%f,newY=%f\n",newPoint.getY()-point.getY(), newPoint.getY(),point.getY()); | |||
} | |||
if (newPoint.getZ() > point.getZ()) | |||
{ | |||
printf("unconservative Z, diffZ = %f, oldZ=%f,newZ=%f\n",newPoint.getZ()-point.getZ(), newPoint.getZ(),point.getZ()); | |||
} | |||
} | |||
#endif //DEBUG_CHECK_DEQUANTIZATION | |||
} | |||
SIMD_FORCE_INLINE void quantizeWithClamp(unsigned short* out, const btVector3& point2,int isMax) const | |||
{ | |||
btAssert(m_useQuantization); | |||
btVector3 clampedPoint(point2); | |||
clampedPoint.setMax(m_bvhAabbMin); | |||
clampedPoint.setMin(m_bvhAabbMax); | |||
quantize(out,clampedPoint,isMax); | |||
} | |||
SIMD_FORCE_INLINE btVector3 unQuantize(const unsigned short* vecIn) const | |||
{ | |||
btVector3 vecOut; | |||
vecOut.setValue( | |||
(btScalar)(vecIn[0]) / (m_bvhQuantization.getX()), | |||
(btScalar)(vecIn[1]) / (m_bvhQuantization.getY()), | |||
(btScalar)(vecIn[2]) / (m_bvhQuantization.getZ())); | |||
vecOut += m_bvhAabbMin; | |||
return vecOut; | |||
} | |||
///setTraversalMode let's you choose between stackless, recursive or stackless cache friendly tree traversal. Note this is only implemented for quantized trees. | |||
void setTraversalMode(btTraversalMode traversalMode) | |||
{ | |||
m_traversalMode = traversalMode; | |||
} | |||
SIMD_FORCE_INLINE QuantizedNodeArray& getQuantizedNodeArray() | |||
{ | |||
return m_quantizedContiguousNodes; | |||
} | |||
SIMD_FORCE_INLINE BvhSubtreeInfoArray& getSubtreeInfoArray() | |||
{ | |||
return m_SubtreeHeaders; | |||
} | |||
//////////////////////////////////////////////////////////////////// | |||
/////Calculate space needed to store BVH for serialization | |||
unsigned calculateSerializeBufferSize() const; | |||
/// Data buffer MUST be 16 byte aligned | |||
virtual bool serialize(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian) const; | |||
///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place' | |||
static btQuantizedBvh *deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian); | |||
static unsigned int getAlignmentSerializationPadding(); | |||
////////////////////////////////////////////////////////////////////// | |||
virtual int calculateSerializeBufferSizeNew() const; | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
virtual void deSerializeFloat(struct btQuantizedBvhFloatData& quantizedBvhFloatData); | |||
virtual void deSerializeDouble(struct btQuantizedBvhDoubleData& quantizedBvhDoubleData); | |||
//////////////////////////////////////////////////////////////////// | |||
SIMD_FORCE_INLINE bool isQuantized() | |||
{ | |||
return m_useQuantization; | |||
} | |||
private: | |||
// Special "copy" constructor that allows for in-place deserialization | |||
// Prevents btVector3's default constructor from being called, but doesn't inialize much else | |||
// ownsMemory should most likely be false if deserializing, and if you are not, don't call this (it also changes the function signature, which we need) | |||
btQuantizedBvh(btQuantizedBvh &other, bool ownsMemory); | |||
} | |||
; | |||
struct btBvhSubtreeInfoData | |||
{ | |||
int m_rootNodeIndex; | |||
int m_subtreeSize; | |||
unsigned short m_quantizedAabbMin[3]; | |||
unsigned short m_quantizedAabbMax[3]; | |||
}; | |||
struct btOptimizedBvhNodeFloatData | |||
{ | |||
btVector3FloatData m_aabbMinOrg; | |||
btVector3FloatData m_aabbMaxOrg; | |||
int m_escapeIndex; | |||
int m_subPart; | |||
int m_triangleIndex; | |||
char m_pad[4]; | |||
}; | |||
struct btOptimizedBvhNodeDoubleData | |||
{ | |||
btVector3DoubleData m_aabbMinOrg; | |||
btVector3DoubleData m_aabbMaxOrg; | |||
int m_escapeIndex; | |||
int m_subPart; | |||
int m_triangleIndex; | |||
char m_pad[4]; | |||
}; | |||
struct btQuantizedBvhNodeData | |||
{ | |||
unsigned short m_quantizedAabbMin[3]; | |||
unsigned short m_quantizedAabbMax[3]; | |||
int m_escapeIndexOrTriangleIndex; | |||
}; | |||
struct btQuantizedBvhFloatData | |||
{ | |||
btVector3FloatData m_bvhAabbMin; | |||
btVector3FloatData m_bvhAabbMax; | |||
btVector3FloatData m_bvhQuantization; | |||
int m_curNodeIndex; | |||
int m_useQuantization; | |||
int m_numContiguousLeafNodes; | |||
int m_numQuantizedContiguousNodes; | |||
btOptimizedBvhNodeFloatData *m_contiguousNodesPtr; | |||
btQuantizedBvhNodeData *m_quantizedContiguousNodesPtr; | |||
btBvhSubtreeInfoData *m_subTreeInfoPtr; | |||
int m_traversalMode; | |||
int m_numSubtreeHeaders; | |||
}; | |||
struct btQuantizedBvhDoubleData | |||
{ | |||
btVector3DoubleData m_bvhAabbMin; | |||
btVector3DoubleData m_bvhAabbMax; | |||
btVector3DoubleData m_bvhQuantization; | |||
int m_curNodeIndex; | |||
int m_useQuantization; | |||
int m_numContiguousLeafNodes; | |||
int m_numQuantizedContiguousNodes; | |||
btOptimizedBvhNodeDoubleData *m_contiguousNodesPtr; | |||
btQuantizedBvhNodeData *m_quantizedContiguousNodesPtr; | |||
int m_traversalMode; | |||
int m_numSubtreeHeaders; | |||
btBvhSubtreeInfoData *m_subTreeInfoPtr; | |||
}; | |||
SIMD_FORCE_INLINE int btQuantizedBvh::calculateSerializeBufferSizeNew() const | |||
{ | |||
return sizeof(btQuantizedBvhData); | |||
} | |||
#endif //BT_QUANTIZED_BVH_H |
@@ -0,0 +1,349 @@ | |||
/* | |||
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 "btSimpleBroadphase.h" | |||
#include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" | |||
#include "LinearMath/btVector3.h" | |||
#include "LinearMath/btTransform.h" | |||
#include "LinearMath/btMatrix3x3.h" | |||
#include "LinearMath/btAabbUtil2.h" | |||
#include <new> | |||
extern int gOverlappingPairs; | |||
void btSimpleBroadphase::validate() | |||
{ | |||
for (int i=0;i<m_numHandles;i++) | |||
{ | |||
for (int j=i+1;j<m_numHandles;j++) | |||
{ | |||
btAssert(&m_pHandles[i] != &m_pHandles[j]); | |||
} | |||
} | |||
} | |||
btSimpleBroadphase::btSimpleBroadphase(int maxProxies, btOverlappingPairCache* overlappingPairCache) | |||
:m_pairCache(overlappingPairCache), | |||
m_ownsPairCache(false), | |||
m_invalidPair(0) | |||
{ | |||
if (!overlappingPairCache) | |||
{ | |||
void* mem = btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16); | |||
m_pairCache = new (mem)btHashedOverlappingPairCache(); | |||
m_ownsPairCache = true; | |||
} | |||
// allocate handles buffer and put all handles on free list | |||
m_pHandlesRawPtr = btAlignedAlloc(sizeof(btSimpleBroadphaseProxy)*maxProxies,16); | |||
m_pHandles = new(m_pHandlesRawPtr) btSimpleBroadphaseProxy[maxProxies]; | |||
m_maxHandles = maxProxies; | |||
m_numHandles = 0; | |||
m_firstFreeHandle = 0; | |||
m_LastHandleIndex = -1; | |||
{ | |||
for (int i = m_firstFreeHandle; i < maxProxies; i++) | |||
{ | |||
m_pHandles[i].SetNextFree(i + 1); | |||
m_pHandles[i].m_uniqueId = i+2;//any UID will do, we just avoid too trivial values (0,1) for debugging purposes | |||
} | |||
m_pHandles[maxProxies - 1].SetNextFree(0); | |||
} | |||
} | |||
btSimpleBroadphase::~btSimpleBroadphase() | |||
{ | |||
btAlignedFree(m_pHandlesRawPtr); | |||
if (m_ownsPairCache) | |||
{ | |||
m_pairCache->~btOverlappingPairCache(); | |||
btAlignedFree(m_pairCache); | |||
} | |||
} | |||
btBroadphaseProxy* btSimpleBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* /*dispatcher*/,void* multiSapProxy) | |||
{ | |||
if (m_numHandles >= m_maxHandles) | |||
{ | |||
btAssert(0); | |||
return 0; //should never happen, but don't let the game crash ;-) | |||
} | |||
btAssert(aabbMin[0]<= aabbMax[0] && aabbMin[1]<= aabbMax[1] && aabbMin[2]<= aabbMax[2]); | |||
int newHandleIndex = allocHandle(); | |||
btSimpleBroadphaseProxy* proxy = new (&m_pHandles[newHandleIndex])btSimpleBroadphaseProxy(aabbMin,aabbMax,shapeType,userPtr,collisionFilterGroup,collisionFilterMask,multiSapProxy); | |||
return proxy; | |||
} | |||
class RemovingOverlapCallback : public btOverlapCallback | |||
{ | |||
protected: | |||
virtual bool processOverlap(btBroadphasePair& pair) | |||
{ | |||
(void)pair; | |||
btAssert(0); | |||
return false; | |||
} | |||
}; | |||
class RemovePairContainingProxy | |||
{ | |||
btBroadphaseProxy* m_targetProxy; | |||
public: | |||
virtual ~RemovePairContainingProxy() | |||
{ | |||
} | |||
protected: | |||
virtual bool processOverlap(btBroadphasePair& pair) | |||
{ | |||
btSimpleBroadphaseProxy* proxy0 = static_cast<btSimpleBroadphaseProxy*>(pair.m_pProxy0); | |||
btSimpleBroadphaseProxy* proxy1 = static_cast<btSimpleBroadphaseProxy*>(pair.m_pProxy1); | |||
return ((m_targetProxy == proxy0 || m_targetProxy == proxy1)); | |||
}; | |||
}; | |||
void btSimpleBroadphase::destroyProxy(btBroadphaseProxy* proxyOrg,btDispatcher* dispatcher) | |||
{ | |||
btSimpleBroadphaseProxy* proxy0 = static_cast<btSimpleBroadphaseProxy*>(proxyOrg); | |||
freeHandle(proxy0); | |||
m_pairCache->removeOverlappingPairsContainingProxy(proxyOrg,dispatcher); | |||
//validate(); | |||
} | |||
void btSimpleBroadphase::getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const | |||
{ | |||
const btSimpleBroadphaseProxy* sbp = getSimpleProxyFromProxy(proxy); | |||
aabbMin = sbp->m_aabbMin; | |||
aabbMax = sbp->m_aabbMax; | |||
} | |||
void btSimpleBroadphase::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* /*dispatcher*/) | |||
{ | |||
btSimpleBroadphaseProxy* sbp = getSimpleProxyFromProxy(proxy); | |||
sbp->m_aabbMin = aabbMin; | |||
sbp->m_aabbMax = aabbMax; | |||
} | |||
void btSimpleBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin,const btVector3& aabbMax) | |||
{ | |||
for (int i=0; i <= m_LastHandleIndex; i++) | |||
{ | |||
btSimpleBroadphaseProxy* proxy = &m_pHandles[i]; | |||
if(!proxy->m_clientObject) | |||
{ | |||
continue; | |||
} | |||
rayCallback.process(proxy); | |||
} | |||
} | |||
void btSimpleBroadphase::aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) | |||
{ | |||
for (int i=0; i <= m_LastHandleIndex; i++) | |||
{ | |||
btSimpleBroadphaseProxy* proxy = &m_pHandles[i]; | |||
if(!proxy->m_clientObject) | |||
{ | |||
continue; | |||
} | |||
if (TestAabbAgainstAabb2(aabbMin,aabbMax,proxy->m_aabbMin,proxy->m_aabbMax)) | |||
{ | |||
callback.process(proxy); | |||
} | |||
} | |||
} | |||
bool btSimpleBroadphase::aabbOverlap(btSimpleBroadphaseProxy* proxy0,btSimpleBroadphaseProxy* proxy1) | |||
{ | |||
return proxy0->m_aabbMin[0] <= proxy1->m_aabbMax[0] && proxy1->m_aabbMin[0] <= proxy0->m_aabbMax[0] && | |||
proxy0->m_aabbMin[1] <= proxy1->m_aabbMax[1] && proxy1->m_aabbMin[1] <= proxy0->m_aabbMax[1] && | |||
proxy0->m_aabbMin[2] <= proxy1->m_aabbMax[2] && proxy1->m_aabbMin[2] <= proxy0->m_aabbMax[2]; | |||
} | |||
//then remove non-overlapping ones | |||
class CheckOverlapCallback : public btOverlapCallback | |||
{ | |||
public: | |||
virtual bool processOverlap(btBroadphasePair& pair) | |||
{ | |||
return (!btSimpleBroadphase::aabbOverlap(static_cast<btSimpleBroadphaseProxy*>(pair.m_pProxy0),static_cast<btSimpleBroadphaseProxy*>(pair.m_pProxy1))); | |||
} | |||
}; | |||
void btSimpleBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) | |||
{ | |||
//first check for new overlapping pairs | |||
int i,j; | |||
if (m_numHandles >= 0) | |||
{ | |||
int new_largest_index = -1; | |||
for (i=0; i <= m_LastHandleIndex; i++) | |||
{ | |||
btSimpleBroadphaseProxy* proxy0 = &m_pHandles[i]; | |||
if(!proxy0->m_clientObject) | |||
{ | |||
continue; | |||
} | |||
new_largest_index = i; | |||
for (j=i+1; j <= m_LastHandleIndex; j++) | |||
{ | |||
btSimpleBroadphaseProxy* proxy1 = &m_pHandles[j]; | |||
btAssert(proxy0 != proxy1); | |||
if(!proxy1->m_clientObject) | |||
{ | |||
continue; | |||
} | |||
btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0); | |||
btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1); | |||
if (aabbOverlap(p0,p1)) | |||
{ | |||
if ( !m_pairCache->findPair(proxy0,proxy1)) | |||
{ | |||
m_pairCache->addOverlappingPair(proxy0,proxy1); | |||
} | |||
} else | |||
{ | |||
if (!m_pairCache->hasDeferredRemoval()) | |||
{ | |||
if ( m_pairCache->findPair(proxy0,proxy1)) | |||
{ | |||
m_pairCache->removeOverlappingPair(proxy0,proxy1,dispatcher); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
m_LastHandleIndex = new_largest_index; | |||
if (m_ownsPairCache && m_pairCache->hasDeferredRemoval()) | |||
{ | |||
btBroadphasePairArray& overlappingPairArray = m_pairCache->getOverlappingPairArray(); | |||
//perform a sort, to find duplicates and to sort 'invalid' pairs to the end | |||
overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); | |||
overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); | |||
m_invalidPair = 0; | |||
btBroadphasePair previousPair; | |||
previousPair.m_pProxy0 = 0; | |||
previousPair.m_pProxy1 = 0; | |||
previousPair.m_algorithm = 0; | |||
for (i=0;i<overlappingPairArray.size();i++) | |||
{ | |||
btBroadphasePair& pair = overlappingPairArray[i]; | |||
bool isDuplicate = (pair == previousPair); | |||
previousPair = pair; | |||
bool needsRemoval = false; | |||
if (!isDuplicate) | |||
{ | |||
bool hasOverlap = testAabbOverlap(pair.m_pProxy0,pair.m_pProxy1); | |||
if (hasOverlap) | |||
{ | |||
needsRemoval = false;//callback->processOverlap(pair); | |||
} else | |||
{ | |||
needsRemoval = true; | |||
} | |||
} else | |||
{ | |||
//remove duplicate | |||
needsRemoval = true; | |||
//should have no algorithm | |||
btAssert(!pair.m_algorithm); | |||
} | |||
if (needsRemoval) | |||
{ | |||
m_pairCache->cleanOverlappingPair(pair,dispatcher); | |||
// m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); | |||
// m_overlappingPairArray.pop_back(); | |||
pair.m_pProxy0 = 0; | |||
pair.m_pProxy1 = 0; | |||
m_invalidPair++; | |||
gOverlappingPairs--; | |||
} | |||
} | |||
///if you don't like to skip the invalid pairs in the array, execute following code: | |||
#define CLEAN_INVALID_PAIRS 1 | |||
#ifdef CLEAN_INVALID_PAIRS | |||
//perform a sort, to sort 'invalid' pairs to the end | |||
overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); | |||
overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); | |||
m_invalidPair = 0; | |||
#endif//CLEAN_INVALID_PAIRS | |||
} | |||
} | |||
} | |||
bool btSimpleBroadphase::testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) | |||
{ | |||
btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0); | |||
btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1); | |||
return aabbOverlap(p0,p1); | |||
} | |||
void btSimpleBroadphase::resetPool(btDispatcher* dispatcher) | |||
{ | |||
//not yet | |||
} |
@@ -0,0 +1,171 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_SIMPLE_BROADPHASE_H | |||
#define BT_SIMPLE_BROADPHASE_H | |||
#include "btOverlappingPairCache.h" | |||
struct btSimpleBroadphaseProxy : public btBroadphaseProxy | |||
{ | |||
int m_nextFree; | |||
// int m_handleId; | |||
btSimpleBroadphaseProxy() {}; | |||
btSimpleBroadphaseProxy(const btVector3& minpt,const btVector3& maxpt,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,void* multiSapProxy) | |||
:btBroadphaseProxy(minpt,maxpt,userPtr,collisionFilterGroup,collisionFilterMask,multiSapProxy) | |||
{ | |||
(void)shapeType; | |||
} | |||
SIMD_FORCE_INLINE void SetNextFree(int next) {m_nextFree = next;} | |||
SIMD_FORCE_INLINE int GetNextFree() const {return m_nextFree;} | |||
}; | |||
///The SimpleBroadphase is just a unit-test for btAxisSweep3, bt32BitAxisSweep3, or btDbvtBroadphase, so use those classes instead. | |||
///It is a brute force aabb culling broadphase based on O(n^2) aabb checks | |||
class btSimpleBroadphase : public btBroadphaseInterface | |||
{ | |||
protected: | |||
int m_numHandles; // number of active handles | |||
int m_maxHandles; // max number of handles | |||
int m_LastHandleIndex; | |||
btSimpleBroadphaseProxy* m_pHandles; // handles pool | |||
void* m_pHandlesRawPtr; | |||
int m_firstFreeHandle; // free handles list | |||
int allocHandle() | |||
{ | |||
btAssert(m_numHandles < m_maxHandles); | |||
int freeHandle = m_firstFreeHandle; | |||
m_firstFreeHandle = m_pHandles[freeHandle].GetNextFree(); | |||
m_numHandles++; | |||
if(freeHandle > m_LastHandleIndex) | |||
{ | |||
m_LastHandleIndex = freeHandle; | |||
} | |||
return freeHandle; | |||
} | |||
void freeHandle(btSimpleBroadphaseProxy* proxy) | |||
{ | |||
int handle = int(proxy-m_pHandles); | |||
btAssert(handle >= 0 && handle < m_maxHandles); | |||
if(handle == m_LastHandleIndex) | |||
{ | |||
m_LastHandleIndex--; | |||
} | |||
proxy->SetNextFree(m_firstFreeHandle); | |||
m_firstFreeHandle = handle; | |||
proxy->m_clientObject = 0; | |||
m_numHandles--; | |||
} | |||
btOverlappingPairCache* m_pairCache; | |||
bool m_ownsPairCache; | |||
int m_invalidPair; | |||
inline btSimpleBroadphaseProxy* getSimpleProxyFromProxy(btBroadphaseProxy* proxy) | |||
{ | |||
btSimpleBroadphaseProxy* proxy0 = static_cast<btSimpleBroadphaseProxy*>(proxy); | |||
return proxy0; | |||
} | |||
inline const btSimpleBroadphaseProxy* getSimpleProxyFromProxy(btBroadphaseProxy* proxy) const | |||
{ | |||
const btSimpleBroadphaseProxy* proxy0 = static_cast<const btSimpleBroadphaseProxy*>(proxy); | |||
return proxy0; | |||
} | |||
///reset broadphase internal structures, to ensure determinism/reproducability | |||
virtual void resetPool(btDispatcher* dispatcher); | |||
void validate(); | |||
protected: | |||
public: | |||
btSimpleBroadphase(int maxProxies=16384,btOverlappingPairCache* overlappingPairCache=0); | |||
virtual ~btSimpleBroadphase(); | |||
static bool aabbOverlap(btSimpleBroadphaseProxy* proxy0,btSimpleBroadphaseProxy* proxy1); | |||
virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy); | |||
virtual void calculateOverlappingPairs(btDispatcher* dispatcher); | |||
virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher); | |||
virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; | |||
virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0),const btVector3& aabbMax=btVector3(0,0,0)); | |||
virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback); | |||
btOverlappingPairCache* getOverlappingPairCache() | |||
{ | |||
return m_pairCache; | |||
} | |||
const btOverlappingPairCache* getOverlappingPairCache() const | |||
{ | |||
return m_pairCache; | |||
} | |||
bool testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); | |||
///getAabb returns the axis aligned bounding box in the 'global' coordinate frame | |||
///will add some transform later | |||
virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const | |||
{ | |||
aabbMin.setValue(-BT_LARGE_FLOAT,-BT_LARGE_FLOAT,-BT_LARGE_FLOAT); | |||
aabbMax.setValue(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT); | |||
} | |||
virtual void printStats() | |||
{ | |||
// printf("btSimpleBroadphase.h\n"); | |||
// printf("numHandles = %d, maxHandles = %d\n",m_numHandles,m_maxHandles); | |||
} | |||
}; | |||
#endif //BT_SIMPLE_BROADPHASE_H | |||
@@ -0,0 +1,201 @@ | |||
/* | |||
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 "LinearMath/btScalar.h" | |||
#include "SphereTriangleDetector.h" | |||
#include "BulletCollision/CollisionShapes/btTriangleShape.h" | |||
#include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
SphereTriangleDetector::SphereTriangleDetector(btSphereShape* sphere,btTriangleShape* triangle,btScalar contactBreakingThreshold) | |||
:m_sphere(sphere), | |||
m_triangle(triangle), | |||
m_contactBreakingThreshold(contactBreakingThreshold) | |||
{ | |||
} | |||
void SphereTriangleDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults) | |||
{ | |||
(void)debugDraw; | |||
const btTransform& transformA = input.m_transformA; | |||
const btTransform& transformB = input.m_transformB; | |||
btVector3 point,normal; | |||
btScalar timeOfImpact = btScalar(1.); | |||
btScalar depth = btScalar(0.); | |||
// output.m_distance = btScalar(BT_LARGE_FLOAT); | |||
//move sphere into triangle space | |||
btTransform sphereInTr = transformB.inverseTimes(transformA); | |||
if (collide(sphereInTr.getOrigin(),point,normal,depth,timeOfImpact,m_contactBreakingThreshold)) | |||
{ | |||
if (swapResults) | |||
{ | |||
btVector3 normalOnB = transformB.getBasis()*normal; | |||
btVector3 normalOnA = -normalOnB; | |||
btVector3 pointOnA = transformB*point+normalOnB*depth; | |||
output.addContactPoint(normalOnA,pointOnA,depth); | |||
} else | |||
{ | |||
output.addContactPoint(transformB.getBasis()*normal,transformB*point,depth); | |||
} | |||
} | |||
} | |||
// See also geometrictools.com | |||
// Basic idea: D = |p - (lo + t0*lv)| where t0 = lv . (p - lo) / lv . lv | |||
btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest); | |||
btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest) { | |||
btVector3 diff = p - from; | |||
btVector3 v = to - from; | |||
btScalar t = v.dot(diff); | |||
if (t > 0) { | |||
btScalar dotVV = v.dot(v); | |||
if (t < dotVV) { | |||
t /= dotVV; | |||
diff -= t*v; | |||
} else { | |||
t = 1; | |||
diff -= v; | |||
} | |||
} else | |||
t = 0; | |||
nearest = from + t*v; | |||
return diff.dot(diff); | |||
} | |||
bool SphereTriangleDetector::facecontains(const btVector3 &p,const btVector3* vertices,btVector3& normal) { | |||
btVector3 lp(p); | |||
btVector3 lnormal(normal); | |||
return pointInTriangle(vertices, lnormal, &lp); | |||
} | |||
bool SphereTriangleDetector::collide(const btVector3& sphereCenter,btVector3 &point, btVector3& resultNormal, btScalar& depth, btScalar &timeOfImpact, btScalar contactBreakingThreshold) | |||
{ | |||
const btVector3* vertices = &m_triangle->getVertexPtr(0); | |||
btScalar radius = m_sphere->getRadius(); | |||
btScalar radiusWithThreshold = radius + contactBreakingThreshold; | |||
btVector3 normal = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]); | |||
normal.normalize(); | |||
btVector3 p1ToCentre = sphereCenter - vertices[0]; | |||
btScalar distanceFromPlane = p1ToCentre.dot(normal); | |||
if (distanceFromPlane < btScalar(0.)) | |||
{ | |||
//triangle facing the other way | |||
distanceFromPlane *= btScalar(-1.); | |||
normal *= btScalar(-1.); | |||
} | |||
bool isInsideContactPlane = distanceFromPlane < radiusWithThreshold; | |||
// Check for contact / intersection | |||
bool hasContact = false; | |||
btVector3 contactPoint; | |||
if (isInsideContactPlane) { | |||
if (facecontains(sphereCenter,vertices,normal)) { | |||
// Inside the contact wedge - touches a point on the shell plane | |||
hasContact = true; | |||
contactPoint = sphereCenter - normal*distanceFromPlane; | |||
} else { | |||
// Could be inside one of the contact capsules | |||
btScalar contactCapsuleRadiusSqr = radiusWithThreshold*radiusWithThreshold; | |||
btVector3 nearestOnEdge; | |||
for (int i = 0; i < m_triangle->getNumEdges(); i++) { | |||
btVector3 pa; | |||
btVector3 pb; | |||
m_triangle->getEdge(i,pa,pb); | |||
btScalar distanceSqr = SegmentSqrDistance(pa,pb,sphereCenter, nearestOnEdge); | |||
if (distanceSqr < contactCapsuleRadiusSqr) { | |||
// Yep, we're inside a capsule | |||
hasContact = true; | |||
contactPoint = nearestOnEdge; | |||
} | |||
} | |||
} | |||
} | |||
if (hasContact) { | |||
btVector3 contactToCentre = sphereCenter - contactPoint; | |||
btScalar distanceSqr = contactToCentre.length2(); | |||
if (distanceSqr < radiusWithThreshold*radiusWithThreshold) | |||
{ | |||
if (distanceSqr>SIMD_EPSILON) | |||
{ | |||
btScalar distance = btSqrt(distanceSqr); | |||
resultNormal = contactToCentre; | |||
resultNormal.normalize(); | |||
point = contactPoint; | |||
depth = -(radius-distance); | |||
} else | |||
{ | |||
btScalar distance = 0.f; | |||
resultNormal = normal; | |||
point = contactPoint; | |||
depth = -radius; | |||
} | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
bool SphereTriangleDetector::pointInTriangle(const btVector3 vertices[], const btVector3 &normal, btVector3 *p ) | |||
{ | |||
const btVector3* p1 = &vertices[0]; | |||
const btVector3* p2 = &vertices[1]; | |||
const btVector3* p3 = &vertices[2]; | |||
btVector3 edge1( *p2 - *p1 ); | |||
btVector3 edge2( *p3 - *p2 ); | |||
btVector3 edge3( *p1 - *p3 ); | |||
btVector3 p1_to_p( *p - *p1 ); | |||
btVector3 p2_to_p( *p - *p2 ); | |||
btVector3 p3_to_p( *p - *p3 ); | |||
btVector3 edge1_normal( edge1.cross(normal)); | |||
btVector3 edge2_normal( edge2.cross(normal)); | |||
btVector3 edge3_normal( edge3.cross(normal)); | |||
btScalar r1, r2, r3; | |||
r1 = edge1_normal.dot( p1_to_p ); | |||
r2 = edge2_normal.dot( p2_to_p ); | |||
r3 = edge3_normal.dot( p3_to_p ); | |||
if ( ( r1 > 0 && r2 > 0 && r3 > 0 ) || | |||
( r1 <= 0 && r2 <= 0 && r3 <= 0 ) ) | |||
return true; | |||
return false; | |||
} |
@@ -0,0 +1,51 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_SPHERE_TRIANGLE_DETECTOR_H | |||
#define BT_SPHERE_TRIANGLE_DETECTOR_H | |||
#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" | |||
class btSphereShape; | |||
class btTriangleShape; | |||
/// sphere-triangle to match the btDiscreteCollisionDetectorInterface | |||
struct SphereTriangleDetector : public btDiscreteCollisionDetectorInterface | |||
{ | |||
virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults=false); | |||
SphereTriangleDetector(btSphereShape* sphere,btTriangleShape* triangle, btScalar contactBreakingThreshold); | |||
virtual ~SphereTriangleDetector() {}; | |||
bool collide(const btVector3& sphereCenter,btVector3 &point, btVector3& resultNormal, btScalar& depth, btScalar &timeOfImpact, btScalar contactBreakingThreshold); | |||
private: | |||
bool pointInTriangle(const btVector3 vertices[], const btVector3 &normal, btVector3 *p ); | |||
bool facecontains(const btVector3 &p,const btVector3* vertices,btVector3& normal); | |||
btSphereShape* m_sphere; | |||
btTriangleShape* m_triangle; | |||
btScalar m_contactBreakingThreshold; | |||
}; | |||
#endif //BT_SPHERE_TRIANGLE_DETECTOR_H | |||
@@ -0,0 +1,47 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com | |||
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 "btActivatingCollisionAlgorithm.h" | |||
#include "btCollisionDispatcher.h" | |||
#include "btCollisionObject.h" | |||
btActivatingCollisionAlgorithm::btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci) | |||
:btCollisionAlgorithm(ci) | |||
//, | |||
//m_colObj0(0), | |||
//m_colObj1(0) | |||
{ | |||
} | |||
btActivatingCollisionAlgorithm::btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* colObj0,btCollisionObject* colObj1) | |||
:btCollisionAlgorithm(ci) | |||
//, | |||
//m_colObj0(0), | |||
//m_colObj1(0) | |||
{ | |||
// if (ci.m_dispatcher1->needsCollision(colObj0,colObj1)) | |||
// { | |||
// m_colObj0 = colObj0; | |||
// m_colObj1 = colObj1; | |||
// | |||
// m_colObj0->activate(); | |||
// m_colObj1->activate(); | |||
// } | |||
} | |||
btActivatingCollisionAlgorithm::~btActivatingCollisionAlgorithm() | |||
{ | |||
// m_colObj0->activate(); | |||
// m_colObj1->activate(); | |||
} |
@@ -0,0 +1,36 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com | |||
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. | |||
*/ | |||
#ifndef __BT_ACTIVATING_COLLISION_ALGORITHM_H | |||
#define __BT_ACTIVATING_COLLISION_ALGORITHM_H | |||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" | |||
///This class is not enabled yet (work-in-progress) to more aggressively activate objects. | |||
class btActivatingCollisionAlgorithm : public btCollisionAlgorithm | |||
{ | |||
// btCollisionObject* m_colObj0; | |||
// btCollisionObject* m_colObj1; | |||
public: | |||
btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci); | |||
btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* colObj0,btCollisionObject* colObj1); | |||
virtual ~btActivatingCollisionAlgorithm(); | |||
}; | |||
#endif //__BT_ACTIVATING_COLLISION_ALGORITHM_H |
@@ -0,0 +1,435 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
* The b2CollidePolygons routines are Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com | |||
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. | |||
*/ | |||
///btBox2dBox2dCollisionAlgorithm, with modified b2CollidePolygons routines from the Box2D library. | |||
///The modifications include: switching from b2Vec to btVector3, redefinition of b2Dot, b2Cross | |||
#include "btBox2dBox2dCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
#include "BulletCollision/CollisionShapes/btBoxShape.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
#include "BulletCollision/CollisionDispatch/btBoxBoxDetector.h" | |||
#include "BulletCollision/CollisionShapes/btBox2dShape.h" | |||
#define USE_PERSISTENT_CONTACTS 1 | |||
btBox2dBox2dCollisionAlgorithm::btBox2dBox2dCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* obj0,btCollisionObject* obj1) | |||
: btActivatingCollisionAlgorithm(ci,obj0,obj1), | |||
m_ownManifold(false), | |||
m_manifoldPtr(mf) | |||
{ | |||
if (!m_manifoldPtr && m_dispatcher->needsCollision(obj0,obj1)) | |||
{ | |||
m_manifoldPtr = m_dispatcher->getNewManifold(obj0,obj1); | |||
m_ownManifold = true; | |||
} | |||
} | |||
btBox2dBox2dCollisionAlgorithm::~btBox2dBox2dCollisionAlgorithm() | |||
{ | |||
if (m_ownManifold) | |||
{ | |||
if (m_manifoldPtr) | |||
m_dispatcher->releaseManifold(m_manifoldPtr); | |||
} | |||
} | |||
void b2CollidePolygons(btManifoldResult* manifold, const btBox2dShape* polyA, const btTransform& xfA, const btBox2dShape* polyB, const btTransform& xfB); | |||
//#include <stdio.h> | |||
void btBox2dBox2dCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
if (!m_manifoldPtr) | |||
return; | |||
btCollisionObject* col0 = body0; | |||
btCollisionObject* col1 = body1; | |||
btBox2dShape* box0 = (btBox2dShape*)col0->getCollisionShape(); | |||
btBox2dShape* box1 = (btBox2dShape*)col1->getCollisionShape(); | |||
resultOut->setPersistentManifold(m_manifoldPtr); | |||
b2CollidePolygons(resultOut,box0,col0->getWorldTransform(),box1,col1->getWorldTransform()); | |||
// refreshContactPoints is only necessary when using persistent contact points. otherwise all points are newly added | |||
if (m_ownManifold) | |||
{ | |||
resultOut->refreshContactPoints(); | |||
} | |||
} | |||
btScalar btBox2dBox2dCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* /*body0*/,btCollisionObject* /*body1*/,const btDispatcherInfo& /*dispatchInfo*/,btManifoldResult* /*resultOut*/) | |||
{ | |||
//not yet | |||
return 1.f; | |||
} | |||
struct ClipVertex | |||
{ | |||
btVector3 v; | |||
int id; | |||
//b2ContactID id; | |||
//b2ContactID id; | |||
}; | |||
#define b2Dot(a,b) (a).dot(b) | |||
#define b2Mul(a,b) (a)*(b) | |||
#define b2MulT(a,b) (a).transpose()*(b) | |||
#define b2Cross(a,b) (a).cross(b) | |||
#define btCrossS(a,s) btVector3(s * a.getY(), -s * a.getX(),0.f) | |||
int b2_maxManifoldPoints =2; | |||
static int ClipSegmentToLine(ClipVertex vOut[2], ClipVertex vIn[2], | |||
const btVector3& normal, btScalar offset) | |||
{ | |||
// Start with no output points | |||
int numOut = 0; | |||
// Calculate the distance of end points to the line | |||
btScalar distance0 = b2Dot(normal, vIn[0].v) - offset; | |||
btScalar distance1 = b2Dot(normal, vIn[1].v) - offset; | |||
// If the points are behind the plane | |||
if (distance0 <= 0.0f) vOut[numOut++] = vIn[0]; | |||
if (distance1 <= 0.0f) vOut[numOut++] = vIn[1]; | |||
// If the points are on different sides of the plane | |||
if (distance0 * distance1 < 0.0f) | |||
{ | |||
// Find intersection point of edge and plane | |||
btScalar interp = distance0 / (distance0 - distance1); | |||
vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v); | |||
if (distance0 > 0.0f) | |||
{ | |||
vOut[numOut].id = vIn[0].id; | |||
} | |||
else | |||
{ | |||
vOut[numOut].id = vIn[1].id; | |||
} | |||
++numOut; | |||
} | |||
return numOut; | |||
} | |||
// Find the separation between poly1 and poly2 for a give edge normal on poly1. | |||
static btScalar EdgeSeparation(const btBox2dShape* poly1, const btTransform& xf1, int edge1, | |||
const btBox2dShape* poly2, const btTransform& xf2) | |||
{ | |||
const btVector3* vertices1 = poly1->getVertices(); | |||
const btVector3* normals1 = poly1->getNormals(); | |||
int count2 = poly2->getVertexCount(); | |||
const btVector3* vertices2 = poly2->getVertices(); | |||
btAssert(0 <= edge1 && edge1 < poly1->getVertexCount()); | |||
// Convert normal from poly1's frame into poly2's frame. | |||
btVector3 normal1World = b2Mul(xf1.getBasis(), normals1[edge1]); | |||
btVector3 normal1 = b2MulT(xf2.getBasis(), normal1World); | |||
// Find support vertex on poly2 for -normal. | |||
int index = 0; | |||
btScalar minDot = BT_LARGE_FLOAT; | |||
for (int i = 0; i < count2; ++i) | |||
{ | |||
btScalar dot = b2Dot(vertices2[i], normal1); | |||
if (dot < minDot) | |||
{ | |||
minDot = dot; | |||
index = i; | |||
} | |||
} | |||
btVector3 v1 = b2Mul(xf1, vertices1[edge1]); | |||
btVector3 v2 = b2Mul(xf2, vertices2[index]); | |||
btScalar separation = b2Dot(v2 - v1, normal1World); | |||
return separation; | |||
} | |||
// Find the max separation between poly1 and poly2 using edge normals from poly1. | |||
static btScalar FindMaxSeparation(int* edgeIndex, | |||
const btBox2dShape* poly1, const btTransform& xf1, | |||
const btBox2dShape* poly2, const btTransform& xf2) | |||
{ | |||
int count1 = poly1->getVertexCount(); | |||
const btVector3* normals1 = poly1->getNormals(); | |||
// Vector pointing from the centroid of poly1 to the centroid of poly2. | |||
btVector3 d = b2Mul(xf2, poly2->getCentroid()) - b2Mul(xf1, poly1->getCentroid()); | |||
btVector3 dLocal1 = b2MulT(xf1.getBasis(), d); | |||
// Find edge normal on poly1 that has the largest projection onto d. | |||
int edge = 0; | |||
btScalar maxDot = -BT_LARGE_FLOAT; | |||
for (int i = 0; i < count1; ++i) | |||
{ | |||
btScalar dot = b2Dot(normals1[i], dLocal1); | |||
if (dot > maxDot) | |||
{ | |||
maxDot = dot; | |||
edge = i; | |||
} | |||
} | |||
// Get the separation for the edge normal. | |||
btScalar s = EdgeSeparation(poly1, xf1, edge, poly2, xf2); | |||
if (s > 0.0f) | |||
{ | |||
return s; | |||
} | |||
// Check the separation for the previous edge normal. | |||
int prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; | |||
btScalar sPrev = EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); | |||
if (sPrev > 0.0f) | |||
{ | |||
return sPrev; | |||
} | |||
// Check the separation for the next edge normal. | |||
int nextEdge = edge + 1 < count1 ? edge + 1 : 0; | |||
btScalar sNext = EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); | |||
if (sNext > 0.0f) | |||
{ | |||
return sNext; | |||
} | |||
// Find the best edge and the search direction. | |||
int bestEdge; | |||
btScalar bestSeparation; | |||
int increment; | |||
if (sPrev > s && sPrev > sNext) | |||
{ | |||
increment = -1; | |||
bestEdge = prevEdge; | |||
bestSeparation = sPrev; | |||
} | |||
else if (sNext > s) | |||
{ | |||
increment = 1; | |||
bestEdge = nextEdge; | |||
bestSeparation = sNext; | |||
} | |||
else | |||
{ | |||
*edgeIndex = edge; | |||
return s; | |||
} | |||
// Perform a local search for the best edge normal. | |||
for ( ; ; ) | |||
{ | |||
if (increment == -1) | |||
edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; | |||
else | |||
edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0; | |||
s = EdgeSeparation(poly1, xf1, edge, poly2, xf2); | |||
if (s > 0.0f) | |||
{ | |||
return s; | |||
} | |||
if (s > bestSeparation) | |||
{ | |||
bestEdge = edge; | |||
bestSeparation = s; | |||
} | |||
else | |||
{ | |||
break; | |||
} | |||
} | |||
*edgeIndex = bestEdge; | |||
return bestSeparation; | |||
} | |||
static void FindIncidentEdge(ClipVertex c[2], | |||
const btBox2dShape* poly1, const btTransform& xf1, int edge1, | |||
const btBox2dShape* poly2, const btTransform& xf2) | |||
{ | |||
const btVector3* normals1 = poly1->getNormals(); | |||
int count2 = poly2->getVertexCount(); | |||
const btVector3* vertices2 = poly2->getVertices(); | |||
const btVector3* normals2 = poly2->getNormals(); | |||
btAssert(0 <= edge1 && edge1 < poly1->getVertexCount()); | |||
// Get the normal of the reference edge in poly2's frame. | |||
btVector3 normal1 = b2MulT(xf2.getBasis(), b2Mul(xf1.getBasis(), normals1[edge1])); | |||
// Find the incident edge on poly2. | |||
int index = 0; | |||
btScalar minDot = BT_LARGE_FLOAT; | |||
for (int i = 0; i < count2; ++i) | |||
{ | |||
btScalar dot = b2Dot(normal1, normals2[i]); | |||
if (dot < minDot) | |||
{ | |||
minDot = dot; | |||
index = i; | |||
} | |||
} | |||
// Build the clip vertices for the incident edge. | |||
int i1 = index; | |||
int i2 = i1 + 1 < count2 ? i1 + 1 : 0; | |||
c[0].v = b2Mul(xf2, vertices2[i1]); | |||
// c[0].id.features.referenceEdge = (unsigned char)edge1; | |||
// c[0].id.features.incidentEdge = (unsigned char)i1; | |||
// c[0].id.features.incidentVertex = 0; | |||
c[1].v = b2Mul(xf2, vertices2[i2]); | |||
// c[1].id.features.referenceEdge = (unsigned char)edge1; | |||
// c[1].id.features.incidentEdge = (unsigned char)i2; | |||
// c[1].id.features.incidentVertex = 1; | |||
} | |||
// Find edge normal of max separation on A - return if separating axis is found | |||
// Find edge normal of max separation on B - return if separation axis is found | |||
// Choose reference edge as min(minA, minB) | |||
// Find incident edge | |||
// Clip | |||
// The normal points from 1 to 2 | |||
void b2CollidePolygons(btManifoldResult* manifold, | |||
const btBox2dShape* polyA, const btTransform& xfA, | |||
const btBox2dShape* polyB, const btTransform& xfB) | |||
{ | |||
int edgeA = 0; | |||
btScalar separationA = FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB); | |||
if (separationA > 0.0f) | |||
return; | |||
int edgeB = 0; | |||
btScalar separationB = FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA); | |||
if (separationB > 0.0f) | |||
return; | |||
const btBox2dShape* poly1; // reference poly | |||
const btBox2dShape* poly2; // incident poly | |||
btTransform xf1, xf2; | |||
int edge1; // reference edge | |||
unsigned char flip; | |||
const btScalar k_relativeTol = 0.98f; | |||
const btScalar k_absoluteTol = 0.001f; | |||
// TODO_ERIN use "radius" of poly for absolute tolerance. | |||
if (separationB > k_relativeTol * separationA + k_absoluteTol) | |||
{ | |||
poly1 = polyB; | |||
poly2 = polyA; | |||
xf1 = xfB; | |||
xf2 = xfA; | |||
edge1 = edgeB; | |||
flip = 1; | |||
} | |||
else | |||
{ | |||
poly1 = polyA; | |||
poly2 = polyB; | |||
xf1 = xfA; | |||
xf2 = xfB; | |||
edge1 = edgeA; | |||
flip = 0; | |||
} | |||
ClipVertex incidentEdge[2]; | |||
FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); | |||
int count1 = poly1->getVertexCount(); | |||
const btVector3* vertices1 = poly1->getVertices(); | |||
btVector3 v11 = vertices1[edge1]; | |||
btVector3 v12 = edge1 + 1 < count1 ? vertices1[edge1+1] : vertices1[0]; | |||
btVector3 dv = v12 - v11; | |||
btVector3 sideNormal = b2Mul(xf1.getBasis(), v12 - v11); | |||
sideNormal.normalize(); | |||
btVector3 frontNormal = btCrossS(sideNormal, 1.0f); | |||
v11 = b2Mul(xf1, v11); | |||
v12 = b2Mul(xf1, v12); | |||
btScalar frontOffset = b2Dot(frontNormal, v11); | |||
btScalar sideOffset1 = -b2Dot(sideNormal, v11); | |||
btScalar sideOffset2 = b2Dot(sideNormal, v12); | |||
// Clip incident edge against extruded edge1 side edges. | |||
ClipVertex clipPoints1[2]; | |||
clipPoints1[0].v.setValue(0,0,0); | |||
clipPoints1[1].v.setValue(0,0,0); | |||
ClipVertex clipPoints2[2]; | |||
clipPoints2[0].v.setValue(0,0,0); | |||
clipPoints2[1].v.setValue(0,0,0); | |||
int np; | |||
// Clip to box side 1 | |||
np = ClipSegmentToLine(clipPoints1, incidentEdge, -sideNormal, sideOffset1); | |||
if (np < 2) | |||
return; | |||
// Clip to negative box side 1 | |||
np = ClipSegmentToLine(clipPoints2, clipPoints1, sideNormal, sideOffset2); | |||
if (np < 2) | |||
{ | |||
return; | |||
} | |||
// Now clipPoints2 contains the clipped points. | |||
btVector3 manifoldNormal = flip ? -frontNormal : frontNormal; | |||
int pointCount = 0; | |||
for (int i = 0; i < b2_maxManifoldPoints; ++i) | |||
{ | |||
btScalar separation = b2Dot(frontNormal, clipPoints2[i].v) - frontOffset; | |||
if (separation <= 0.0f) | |||
{ | |||
//b2ManifoldPoint* cp = manifold->points + pointCount; | |||
//btScalar separation = separation; | |||
//cp->localPoint1 = b2MulT(xfA, clipPoints2[i].v); | |||
//cp->localPoint2 = b2MulT(xfB, clipPoints2[i].v); | |||
manifold->addContactPoint(-manifoldNormal,clipPoints2[i].v,separation); | |||
// cp->id = clipPoints2[i].id; | |||
// cp->id.features.flip = flip; | |||
++pointCount; | |||
} | |||
} | |||
// manifold->pointCount = pointCount;} | |||
} |
@@ -0,0 +1,66 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_BOX_2D_BOX_2D__COLLISION_ALGORITHM_H | |||
#define BT_BOX_2D_BOX_2D__COLLISION_ALGORITHM_H | |||
#include "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
class btPersistentManifold; | |||
///box-box collision detection | |||
class btBox2dBox2dCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
{ | |||
bool m_ownManifold; | |||
btPersistentManifold* m_manifoldPtr; | |||
public: | |||
btBox2dBox2dCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) | |||
: btActivatingCollisionAlgorithm(ci) {} | |||
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
btBox2dBox2dCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); | |||
virtual ~btBox2dBox2dCollisionAlgorithm(); | |||
virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
{ | |||
if (m_manifoldPtr && m_ownManifold) | |||
{ | |||
manifoldArray.push_back(m_manifoldPtr); | |||
} | |||
} | |||
struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
int bbsize = sizeof(btBox2dBox2dCollisionAlgorithm); | |||
void* ptr = ci.m_dispatcher1->allocateCollisionAlgorithm(bbsize); | |||
return new(ptr) btBox2dBox2dCollisionAlgorithm(0,ci,body0,body1); | |||
} | |||
}; | |||
}; | |||
#endif //BT_BOX_2D_BOX_2D__COLLISION_ALGORITHM_H | |||
@@ -0,0 +1,85 @@ | |||
/* | |||
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 "btBoxBoxCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
#include "BulletCollision/CollisionShapes/btBoxShape.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
#include "btBoxBoxDetector.h" | |||
#define USE_PERSISTENT_CONTACTS 1 | |||
btBoxBoxCollisionAlgorithm::btBoxBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* obj0,btCollisionObject* obj1) | |||
: btActivatingCollisionAlgorithm(ci,obj0,obj1), | |||
m_ownManifold(false), | |||
m_manifoldPtr(mf) | |||
{ | |||
if (!m_manifoldPtr && m_dispatcher->needsCollision(obj0,obj1)) | |||
{ | |||
m_manifoldPtr = m_dispatcher->getNewManifold(obj0,obj1); | |||
m_ownManifold = true; | |||
} | |||
} | |||
btBoxBoxCollisionAlgorithm::~btBoxBoxCollisionAlgorithm() | |||
{ | |||
if (m_ownManifold) | |||
{ | |||
if (m_manifoldPtr) | |||
m_dispatcher->releaseManifold(m_manifoldPtr); | |||
} | |||
} | |||
void btBoxBoxCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
if (!m_manifoldPtr) | |||
return; | |||
btCollisionObject* col0 = body0; | |||
btCollisionObject* col1 = body1; | |||
btBoxShape* box0 = (btBoxShape*)col0->getCollisionShape(); | |||
btBoxShape* box1 = (btBoxShape*)col1->getCollisionShape(); | |||
/// report a contact. internally this will be kept persistent, and contact reduction is done | |||
resultOut->setPersistentManifold(m_manifoldPtr); | |||
#ifndef USE_PERSISTENT_CONTACTS | |||
m_manifoldPtr->clearManifold(); | |||
#endif //USE_PERSISTENT_CONTACTS | |||
btDiscreteCollisionDetectorInterface::ClosestPointInput input; | |||
input.m_maximumDistanceSquared = BT_LARGE_FLOAT; | |||
input.m_transformA = body0->getWorldTransform(); | |||
input.m_transformB = body1->getWorldTransform(); | |||
btBoxBoxDetector detector(box0,box1); | |||
detector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); | |||
#ifdef USE_PERSISTENT_CONTACTS | |||
// refreshContactPoints is only necessary when using persistent contact points. otherwise all points are newly added | |||
if (m_ownManifold) | |||
{ | |||
resultOut->refreshContactPoints(); | |||
} | |||
#endif //USE_PERSISTENT_CONTACTS | |||
} | |||
btScalar btBoxBoxCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* /*body0*/,btCollisionObject* /*body1*/,const btDispatcherInfo& /*dispatchInfo*/,btManifoldResult* /*resultOut*/) | |||
{ | |||
//not yet | |||
return 1.f; | |||
} |
@@ -0,0 +1,66 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_BOX_BOX__COLLISION_ALGORITHM_H | |||
#define BT_BOX_BOX__COLLISION_ALGORITHM_H | |||
#include "btActivatingCollisionAlgorithm.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
class btPersistentManifold; | |||
///box-box collision detection | |||
class btBoxBoxCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
{ | |||
bool m_ownManifold; | |||
btPersistentManifold* m_manifoldPtr; | |||
public: | |||
btBoxBoxCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) | |||
: btActivatingCollisionAlgorithm(ci) {} | |||
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
btBoxBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); | |||
virtual ~btBoxBoxCollisionAlgorithm(); | |||
virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
{ | |||
if (m_manifoldPtr && m_ownManifold) | |||
{ | |||
manifoldArray.push_back(m_manifoldPtr); | |||
} | |||
} | |||
struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
int bbsize = sizeof(btBoxBoxCollisionAlgorithm); | |||
void* ptr = ci.m_dispatcher1->allocateCollisionAlgorithm(bbsize); | |||
return new(ptr) btBoxBoxCollisionAlgorithm(0,ci,body0,body1); | |||
} | |||
}; | |||
}; | |||
#endif //BT_BOX_BOX__COLLISION_ALGORITHM_H | |||
@@ -0,0 +1,718 @@ | |||
/* | |||
* Box-Box collision detection re-distributed under the ZLib license with permission from Russell L. Smith | |||
* Original version is from Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. | |||
* All rights reserved. Email: russ@q12.org Web: www.q12.org | |||
Bullet Continuous Collision Detection and Physics Library | |||
Bullet is 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. | |||
*/ | |||
///ODE box-box collision detection is adapted to work with Bullet | |||
#include "btBoxBoxDetector.h" | |||
#include "BulletCollision/CollisionShapes/btBoxShape.h" | |||
#include <float.h> | |||
#include <string.h> | |||
btBoxBoxDetector::btBoxBoxDetector(btBoxShape* box1,btBoxShape* box2) | |||
: m_box1(box1), | |||
m_box2(box2) | |||
{ | |||
} | |||
// given two boxes (p1,R1,side1) and (p2,R2,side2), collide them together and | |||
// generate contact points. this returns 0 if there is no contact otherwise | |||
// it returns the number of contacts generated. | |||
// `normal' returns the contact normal. | |||
// `depth' returns the maximum penetration depth along that normal. | |||
// `return_code' returns a number indicating the type of contact that was | |||
// detected: | |||
// 1,2,3 = box 2 intersects with a face of box 1 | |||
// 4,5,6 = box 1 intersects with a face of box 2 | |||
// 7..15 = edge-edge contact | |||
// `maxc' is the maximum number of contacts allowed to be generated, i.e. | |||
// the size of the `contact' array. | |||
// `contact' and `skip' are the contact array information provided to the | |||
// collision functions. this function only fills in the position and depth | |||
// fields. | |||
struct dContactGeom; | |||
#define dDOTpq(a,b,p,q) ((a)[0]*(b)[0] + (a)[p]*(b)[q] + (a)[2*(p)]*(b)[2*(q)]) | |||
#define dInfinity FLT_MAX | |||
/*PURE_INLINE btScalar dDOT (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,1); } | |||
PURE_INLINE btScalar dDOT13 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,3); } | |||
PURE_INLINE btScalar dDOT31 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,3,1); } | |||
PURE_INLINE btScalar dDOT33 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,3,3); } | |||
*/ | |||
static btScalar dDOT (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,1); } | |||
static btScalar dDOT44 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,4,4); } | |||
static btScalar dDOT41 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,4,1); } | |||
static btScalar dDOT14 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,4); } | |||
#define dMULTIPLYOP1_331(A,op,B,C) \ | |||
{\ | |||
(A)[0] op dDOT41((B),(C)); \ | |||
(A)[1] op dDOT41((B+1),(C)); \ | |||
(A)[2] op dDOT41((B+2),(C)); \ | |||
} | |||
#define dMULTIPLYOP0_331(A,op,B,C) \ | |||
{ \ | |||
(A)[0] op dDOT((B),(C)); \ | |||
(A)[1] op dDOT((B+4),(C)); \ | |||
(A)[2] op dDOT((B+8),(C)); \ | |||
} | |||
#define dMULTIPLY1_331(A,B,C) dMULTIPLYOP1_331(A,=,B,C) | |||
#define dMULTIPLY0_331(A,B,C) dMULTIPLYOP0_331(A,=,B,C) | |||
typedef btScalar dMatrix3[4*3]; | |||
void dLineClosestApproach (const btVector3& pa, const btVector3& ua, | |||
const btVector3& pb, const btVector3& ub, | |||
btScalar *alpha, btScalar *beta); | |||
void dLineClosestApproach (const btVector3& pa, const btVector3& ua, | |||
const btVector3& pb, const btVector3& ub, | |||
btScalar *alpha, btScalar *beta) | |||
{ | |||
btVector3 p; | |||
p[0] = pb[0] - pa[0]; | |||
p[1] = pb[1] - pa[1]; | |||
p[2] = pb[2] - pa[2]; | |||
btScalar uaub = dDOT(ua,ub); | |||
btScalar q1 = dDOT(ua,p); | |||
btScalar q2 = -dDOT(ub,p); | |||
btScalar d = 1-uaub*uaub; | |||
if (d <= btScalar(0.0001f)) { | |||
// @@@ this needs to be made more robust | |||
*alpha = 0; | |||
*beta = 0; | |||
} | |||
else { | |||
d = 1.f/d; | |||
*alpha = (q1 + uaub*q2)*d; | |||
*beta = (uaub*q1 + q2)*d; | |||
} | |||
} | |||
// find all the intersection points between the 2D rectangle with vertices | |||
// at (+/-h[0],+/-h[1]) and the 2D quadrilateral with vertices (p[0],p[1]), | |||
// (p[2],p[3]),(p[4],p[5]),(p[6],p[7]). | |||
// | |||
// the intersection points are returned as x,y pairs in the 'ret' array. | |||
// the number of intersection points is returned by the function (this will | |||
// be in the range 0 to 8). | |||
static int intersectRectQuad2 (btScalar h[2], btScalar p[8], btScalar ret[16]) | |||
{ | |||
// q (and r) contain nq (and nr) coordinate points for the current (and | |||
// chopped) polygons | |||
int nq=4,nr=0; | |||
btScalar buffer[16]; | |||
btScalar *q = p; | |||
btScalar *r = ret; | |||
for (int dir=0; dir <= 1; dir++) { | |||
// direction notation: xy[0] = x axis, xy[1] = y axis | |||
for (int sign=-1; sign <= 1; sign += 2) { | |||
// chop q along the line xy[dir] = sign*h[dir] | |||
btScalar *pq = q; | |||
btScalar *pr = r; | |||
nr = 0; | |||
for (int i=nq; i > 0; i--) { | |||
// go through all points in q and all lines between adjacent points | |||
if (sign*pq[dir] < h[dir]) { | |||
// this point is inside the chopping line | |||
pr[0] = pq[0]; | |||
pr[1] = pq[1]; | |||
pr += 2; | |||
nr++; | |||
if (nr & 8) { | |||
q = r; | |||
goto done; | |||
} | |||
} | |||
btScalar *nextq = (i > 1) ? pq+2 : q; | |||
if ((sign*pq[dir] < h[dir]) ^ (sign*nextq[dir] < h[dir])) { | |||
// this line crosses the chopping line | |||
pr[1-dir] = pq[1-dir] + (nextq[1-dir]-pq[1-dir]) / | |||
(nextq[dir]-pq[dir]) * (sign*h[dir]-pq[dir]); | |||
pr[dir] = sign*h[dir]; | |||
pr += 2; | |||
nr++; | |||
if (nr & 8) { | |||
q = r; | |||
goto done; | |||
} | |||
} | |||
pq += 2; | |||
} | |||
q = r; | |||
r = (q==ret) ? buffer : ret; | |||
nq = nr; | |||
} | |||
} | |||
done: | |||
if (q != ret) memcpy (ret,q,nr*2*sizeof(btScalar)); | |||
return nr; | |||
} | |||
#define M__PI 3.14159265f | |||
// given n points in the plane (array p, of size 2*n), generate m points that | |||
// best represent the whole set. the definition of 'best' here is not | |||
// predetermined - the idea is to select points that give good box-box | |||
// collision detection behavior. the chosen point indexes are returned in the | |||
// array iret (of size m). 'i0' is always the first entry in the array. | |||
// n must be in the range [1..8]. m must be in the range [1..n]. i0 must be | |||
// in the range [0..n-1]. | |||
void cullPoints2 (int n, btScalar p[], int m, int i0, int iret[]); | |||
void cullPoints2 (int n, btScalar p[], int m, int i0, int iret[]) | |||
{ | |||
// compute the centroid of the polygon in cx,cy | |||
int i,j; | |||
btScalar a,cx,cy,q; | |||
if (n==1) { | |||
cx = p[0]; | |||
cy = p[1]; | |||
} | |||
else if (n==2) { | |||
cx = btScalar(0.5)*(p[0] + p[2]); | |||
cy = btScalar(0.5)*(p[1] + p[3]); | |||
} | |||
else { | |||
a = 0; | |||
cx = 0; | |||
cy = 0; | |||
for (i=0; i<(n-1); i++) { | |||
q = p[i*2]*p[i*2+3] - p[i*2+2]*p[i*2+1]; | |||
a += q; | |||
cx += q*(p[i*2]+p[i*2+2]); | |||
cy += q*(p[i*2+1]+p[i*2+3]); | |||
} | |||
q = p[n*2-2]*p[1] - p[0]*p[n*2-1]; | |||
if (btFabs(a+q) > SIMD_EPSILON) | |||
{ | |||
a = 1.f/(btScalar(3.0)*(a+q)); | |||
} else | |||
{ | |||
a=BT_LARGE_FLOAT; | |||
} | |||
cx = a*(cx + q*(p[n*2-2]+p[0])); | |||
cy = a*(cy + q*(p[n*2-1]+p[1])); | |||
} | |||
// compute the angle of each point w.r.t. the centroid | |||
btScalar A[8]; | |||
for (i=0; i<n; i++) A[i] = btAtan2(p[i*2+1]-cy,p[i*2]-cx); | |||
// search for points that have angles closest to A[i0] + i*(2*pi/m). | |||
int avail[8]; | |||
for (i=0; i<n; i++) avail[i] = 1; | |||
avail[i0] = 0; | |||
iret[0] = i0; | |||
iret++; | |||
for (j=1; j<m; j++) { | |||
a = btScalar(j)*(2*M__PI/m) + A[i0]; | |||
if (a > M__PI) a -= 2*M__PI; | |||
btScalar maxdiff=1e9,diff; | |||
*iret = i0; // iret is not allowed to keep this value, but it sometimes does, when diff=#QNAN0 | |||
for (i=0; i<n; i++) { | |||
if (avail[i]) { | |||
diff = btFabs (A[i]-a); | |||
if (diff > M__PI) diff = 2*M__PI - diff; | |||
if (diff < maxdiff) { | |||
maxdiff = diff; | |||
*iret = i; | |||
} | |||
} | |||
} | |||
#if defined(DEBUG) || defined (_DEBUG) | |||
btAssert (*iret != i0); // ensure iret got set | |||
#endif | |||
avail[*iret] = 0; | |||
iret++; | |||
} | |||
} | |||
int dBoxBox2 (const btVector3& p1, const dMatrix3 R1, | |||
const btVector3& side1, const btVector3& p2, | |||
const dMatrix3 R2, const btVector3& side2, | |||
btVector3& normal, btScalar *depth, int *return_code, | |||
int maxc, dContactGeom * /*contact*/, int /*skip*/,btDiscreteCollisionDetectorInterface::Result& output); | |||
int dBoxBox2 (const btVector3& p1, const dMatrix3 R1, | |||
const btVector3& side1, const btVector3& p2, | |||
const dMatrix3 R2, const btVector3& side2, | |||
btVector3& normal, btScalar *depth, int *return_code, | |||
int maxc, dContactGeom * /*contact*/, int /*skip*/,btDiscreteCollisionDetectorInterface::Result& output) | |||
{ | |||
const btScalar fudge_factor = btScalar(1.05); | |||
btVector3 p,pp,normalC(0.f,0.f,0.f); | |||
const btScalar *normalR = 0; | |||
btScalar A[3],B[3],R11,R12,R13,R21,R22,R23,R31,R32,R33, | |||
Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33,s,s2,l; | |||
int i,j,invert_normal,code; | |||
// get vector from centers of box 1 to box 2, relative to box 1 | |||
p = p2 - p1; | |||
dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1 | |||
// get side lengths / 2 | |||
A[0] = side1[0]*btScalar(0.5); | |||
A[1] = side1[1]*btScalar(0.5); | |||
A[2] = side1[2]*btScalar(0.5); | |||
B[0] = side2[0]*btScalar(0.5); | |||
B[1] = side2[1]*btScalar(0.5); | |||
B[2] = side2[2]*btScalar(0.5); | |||
// Rij is R1'*R2, i.e. the relative rotation between R1 and R2 | |||
R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2); | |||
R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2); | |||
R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2); | |||
Q11 = btFabs(R11); Q12 = btFabs(R12); Q13 = btFabs(R13); | |||
Q21 = btFabs(R21); Q22 = btFabs(R22); Q23 = btFabs(R23); | |||
Q31 = btFabs(R31); Q32 = btFabs(R32); Q33 = btFabs(R33); | |||
// for all 15 possible separating axes: | |||
// * see if the axis separates the boxes. if so, return 0. | |||
// * find the depth of the penetration along the separating axis (s2) | |||
// * if this is the largest depth so far, record it. | |||
// the normal vector will be set to the separating axis with the smallest | |||
// depth. note: normalR is set to point to a column of R1 or R2 if that is | |||
// the smallest depth normal so far. otherwise normalR is 0 and normalC is | |||
// set to a vector relative to body 1. invert_normal is 1 if the sign of | |||
// the normal should be flipped. | |||
#define TST(expr1,expr2,norm,cc) \ | |||
s2 = btFabs(expr1) - (expr2); \ | |||
if (s2 > 0) return 0; \ | |||
if (s2 > s) { \ | |||
s = s2; \ | |||
normalR = norm; \ | |||
invert_normal = ((expr1) < 0); \ | |||
code = (cc); \ | |||
} | |||
s = -dInfinity; | |||
invert_normal = 0; | |||
code = 0; | |||
// separating axis = u1,u2,u3 | |||
TST (pp[0],(A[0] + B[0]*Q11 + B[1]*Q12 + B[2]*Q13),R1+0,1); | |||
TST (pp[1],(A[1] + B[0]*Q21 + B[1]*Q22 + B[2]*Q23),R1+1,2); | |||
TST (pp[2],(A[2] + B[0]*Q31 + B[1]*Q32 + B[2]*Q33),R1+2,3); | |||
// separating axis = v1,v2,v3 | |||
TST (dDOT41(R2+0,p),(A[0]*Q11 + A[1]*Q21 + A[2]*Q31 + B[0]),R2+0,4); | |||
TST (dDOT41(R2+1,p),(A[0]*Q12 + A[1]*Q22 + A[2]*Q32 + B[1]),R2+1,5); | |||
TST (dDOT41(R2+2,p),(A[0]*Q13 + A[1]*Q23 + A[2]*Q33 + B[2]),R2+2,6); | |||
// note: cross product axes need to be scaled when s is computed. | |||
// normal (n1,n2,n3) is relative to box 1. | |||
#undef TST | |||
#define TST(expr1,expr2,n1,n2,n3,cc) \ | |||
s2 = btFabs(expr1) - (expr2); \ | |||
if (s2 > SIMD_EPSILON) return 0; \ | |||
l = btSqrt((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \ | |||
if (l > SIMD_EPSILON) { \ | |||
s2 /= l; \ | |||
if (s2*fudge_factor > s) { \ | |||
s = s2; \ | |||
normalR = 0; \ | |||
normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \ | |||
invert_normal = ((expr1) < 0); \ | |||
code = (cc); \ | |||
} \ | |||
} | |||
btScalar fudge2 (1.0e-5f); | |||
Q11 += fudge2; | |||
Q12 += fudge2; | |||
Q13 += fudge2; | |||
Q21 += fudge2; | |||
Q22 += fudge2; | |||
Q23 += fudge2; | |||
Q31 += fudge2; | |||
Q32 += fudge2; | |||
Q33 += fudge2; | |||
// separating axis = u1 x (v1,v2,v3) | |||
TST(pp[2]*R21-pp[1]*R31,(A[1]*Q31+A[2]*Q21+B[1]*Q13+B[2]*Q12),0,-R31,R21,7); | |||
TST(pp[2]*R22-pp[1]*R32,(A[1]*Q32+A[2]*Q22+B[0]*Q13+B[2]*Q11),0,-R32,R22,8); | |||
TST(pp[2]*R23-pp[1]*R33,(A[1]*Q33+A[2]*Q23+B[0]*Q12+B[1]*Q11),0,-R33,R23,9); | |||
// separating axis = u2 x (v1,v2,v3) | |||
TST(pp[0]*R31-pp[2]*R11,(A[0]*Q31+A[2]*Q11+B[1]*Q23+B[2]*Q22),R31,0,-R11,10); | |||
TST(pp[0]*R32-pp[2]*R12,(A[0]*Q32+A[2]*Q12+B[0]*Q23+B[2]*Q21),R32,0,-R12,11); | |||
TST(pp[0]*R33-pp[2]*R13,(A[0]*Q33+A[2]*Q13+B[0]*Q22+B[1]*Q21),R33,0,-R13,12); | |||
// separating axis = u3 x (v1,v2,v3) | |||
TST(pp[1]*R11-pp[0]*R21,(A[0]*Q21+A[1]*Q11+B[1]*Q33+B[2]*Q32),-R21,R11,0,13); | |||
TST(pp[1]*R12-pp[0]*R22,(A[0]*Q22+A[1]*Q12+B[0]*Q33+B[2]*Q31),-R22,R12,0,14); | |||
TST(pp[1]*R13-pp[0]*R23,(A[0]*Q23+A[1]*Q13+B[0]*Q32+B[1]*Q31),-R23,R13,0,15); | |||
#undef TST | |||
if (!code) return 0; | |||
// if we get to this point, the boxes interpenetrate. compute the normal | |||
// in global coordinates. | |||
if (normalR) { | |||
normal[0] = normalR[0]; | |||
normal[1] = normalR[4]; | |||
normal[2] = normalR[8]; | |||
} | |||
else { | |||
dMULTIPLY0_331 (normal,R1,normalC); | |||
} | |||
if (invert_normal) { | |||
normal[0] = -normal[0]; | |||
normal[1] = -normal[1]; | |||
normal[2] = -normal[2]; | |||
} | |||
*depth = -s; | |||
// compute contact point(s) | |||
if (code > 6) { | |||
// an edge from box 1 touches an edge from box 2. | |||
// find a point pa on the intersecting edge of box 1 | |||
btVector3 pa; | |||
btScalar sign; | |||
for (i=0; i<3; i++) pa[i] = p1[i]; | |||
for (j=0; j<3; j++) { | |||
sign = (dDOT14(normal,R1+j) > 0) ? btScalar(1.0) : btScalar(-1.0); | |||
for (i=0; i<3; i++) pa[i] += sign * A[j] * R1[i*4+j]; | |||
} | |||
// find a point pb on the intersecting edge of box 2 | |||
btVector3 pb; | |||
for (i=0; i<3; i++) pb[i] = p2[i]; | |||
for (j=0; j<3; j++) { | |||
sign = (dDOT14(normal,R2+j) > 0) ? btScalar(-1.0) : btScalar(1.0); | |||
for (i=0; i<3; i++) pb[i] += sign * B[j] * R2[i*4+j]; | |||
} | |||
btScalar alpha,beta; | |||
btVector3 ua,ub; | |||
for (i=0; i<3; i++) ua[i] = R1[((code)-7)/3 + i*4]; | |||
for (i=0; i<3; i++) ub[i] = R2[((code)-7)%3 + i*4]; | |||
dLineClosestApproach (pa,ua,pb,ub,&alpha,&beta); | |||
for (i=0; i<3; i++) pa[i] += ua[i]*alpha; | |||
for (i=0; i<3; i++) pb[i] += ub[i]*beta; | |||
{ | |||
//contact[0].pos[i] = btScalar(0.5)*(pa[i]+pb[i]); | |||
//contact[0].depth = *depth; | |||
btVector3 pointInWorld; | |||
#ifdef USE_CENTER_POINT | |||
for (i=0; i<3; i++) | |||
pointInWorld[i] = (pa[i]+pb[i])*btScalar(0.5); | |||
output.addContactPoint(-normal,pointInWorld,-*depth); | |||
#else | |||
output.addContactPoint(-normal,pb,-*depth); | |||
#endif // | |||
*return_code = code; | |||
} | |||
return 1; | |||
} | |||
// okay, we have a face-something intersection (because the separating | |||
// axis is perpendicular to a face). define face 'a' to be the reference | |||
// face (i.e. the normal vector is perpendicular to this) and face 'b' to be | |||
// the incident face (the closest face of the other box). | |||
const btScalar *Ra,*Rb,*pa,*pb,*Sa,*Sb; | |||
if (code <= 3) { | |||
Ra = R1; | |||
Rb = R2; | |||
pa = p1; | |||
pb = p2; | |||
Sa = A; | |||
Sb = B; | |||
} | |||
else { | |||
Ra = R2; | |||
Rb = R1; | |||
pa = p2; | |||
pb = p1; | |||
Sa = B; | |||
Sb = A; | |||
} | |||
// nr = normal vector of reference face dotted with axes of incident box. | |||
// anr = absolute values of nr. | |||
btVector3 normal2,nr,anr; | |||
if (code <= 3) { | |||
normal2[0] = normal[0]; | |||
normal2[1] = normal[1]; | |||
normal2[2] = normal[2]; | |||
} | |||
else { | |||
normal2[0] = -normal[0]; | |||
normal2[1] = -normal[1]; | |||
normal2[2] = -normal[2]; | |||
} | |||
dMULTIPLY1_331 (nr,Rb,normal2); | |||
anr[0] = btFabs (nr[0]); | |||
anr[1] = btFabs (nr[1]); | |||
anr[2] = btFabs (nr[2]); | |||
// find the largest compontent of anr: this corresponds to the normal | |||
// for the indident face. the other axis numbers of the indicent face | |||
// are stored in a1,a2. | |||
int lanr,a1,a2; | |||
if (anr[1] > anr[0]) { | |||
if (anr[1] > anr[2]) { | |||
a1 = 0; | |||
lanr = 1; | |||
a2 = 2; | |||
} | |||
else { | |||
a1 = 0; | |||
a2 = 1; | |||
lanr = 2; | |||
} | |||
} | |||
else { | |||
if (anr[0] > anr[2]) { | |||
lanr = 0; | |||
a1 = 1; | |||
a2 = 2; | |||
} | |||
else { | |||
a1 = 0; | |||
a2 = 1; | |||
lanr = 2; | |||
} | |||
} | |||
// compute center point of incident face, in reference-face coordinates | |||
btVector3 center; | |||
if (nr[lanr] < 0) { | |||
for (i=0; i<3; i++) center[i] = pb[i] - pa[i] + Sb[lanr] * Rb[i*4+lanr]; | |||
} | |||
else { | |||
for (i=0; i<3; i++) center[i] = pb[i] - pa[i] - Sb[lanr] * Rb[i*4+lanr]; | |||
} | |||
// find the normal and non-normal axis numbers of the reference box | |||
int codeN,code1,code2; | |||
if (code <= 3) codeN = code-1; else codeN = code-4; | |||
if (codeN==0) { | |||
code1 = 1; | |||
code2 = 2; | |||
} | |||
else if (codeN==1) { | |||
code1 = 0; | |||
code2 = 2; | |||
} | |||
else { | |||
code1 = 0; | |||
code2 = 1; | |||
} | |||
// find the four corners of the incident face, in reference-face coordinates | |||
btScalar quad[8]; // 2D coordinate of incident face (x,y pairs) | |||
btScalar c1,c2,m11,m12,m21,m22; | |||
c1 = dDOT14 (center,Ra+code1); | |||
c2 = dDOT14 (center,Ra+code2); | |||
// optimize this? - we have already computed this data above, but it is not | |||
// stored in an easy-to-index format. for now it's quicker just to recompute | |||
// the four dot products. | |||
m11 = dDOT44 (Ra+code1,Rb+a1); | |||
m12 = dDOT44 (Ra+code1,Rb+a2); | |||
m21 = dDOT44 (Ra+code2,Rb+a1); | |||
m22 = dDOT44 (Ra+code2,Rb+a2); | |||
{ | |||
btScalar k1 = m11*Sb[a1]; | |||
btScalar k2 = m21*Sb[a1]; | |||
btScalar k3 = m12*Sb[a2]; | |||
btScalar k4 = m22*Sb[a2]; | |||
quad[0] = c1 - k1 - k3; | |||
quad[1] = c2 - k2 - k4; | |||
quad[2] = c1 - k1 + k3; | |||
quad[3] = c2 - k2 + k4; | |||
quad[4] = c1 + k1 + k3; | |||
quad[5] = c2 + k2 + k4; | |||
quad[6] = c1 + k1 - k3; | |||
quad[7] = c2 + k2 - k4; | |||
} | |||
// find the size of the reference face | |||
btScalar rect[2]; | |||
rect[0] = Sa[code1]; | |||
rect[1] = Sa[code2]; | |||
// intersect the incident and reference faces | |||
btScalar ret[16]; | |||
int n = intersectRectQuad2 (rect,quad,ret); | |||
if (n < 1) return 0; // this should never happen | |||
// convert the intersection points into reference-face coordinates, | |||
// and compute the contact position and depth for each point. only keep | |||
// those points that have a positive (penetrating) depth. delete points in | |||
// the 'ret' array as necessary so that 'point' and 'ret' correspond. | |||
btScalar point[3*8]; // penetrating contact points | |||
btScalar dep[8]; // depths for those points | |||
btScalar det1 = 1.f/(m11*m22 - m12*m21); | |||
m11 *= det1; | |||
m12 *= det1; | |||
m21 *= det1; | |||
m22 *= det1; | |||
int cnum = 0; // number of penetrating contact points found | |||
for (j=0; j < n; j++) { | |||
btScalar k1 = m22*(ret[j*2]-c1) - m12*(ret[j*2+1]-c2); | |||
btScalar k2 = -m21*(ret[j*2]-c1) + m11*(ret[j*2+1]-c2); | |||
for (i=0; i<3; i++) point[cnum*3+i] = | |||
center[i] + k1*Rb[i*4+a1] + k2*Rb[i*4+a2]; | |||
dep[cnum] = Sa[codeN] - dDOT(normal2,point+cnum*3); | |||
if (dep[cnum] >= 0) { | |||
ret[cnum*2] = ret[j*2]; | |||
ret[cnum*2+1] = ret[j*2+1]; | |||
cnum++; | |||
} | |||
} | |||
if (cnum < 1) return 0; // this should never happen | |||
// we can't generate more contacts than we actually have | |||
if (maxc > cnum) maxc = cnum; | |||
if (maxc < 1) maxc = 1; | |||
if (cnum <= maxc) { | |||
if (code<4) | |||
{ | |||
// we have less contacts than we need, so we use them all | |||
for (j=0; j < cnum; j++) | |||
{ | |||
btVector3 pointInWorld; | |||
for (i=0; i<3; i++) | |||
pointInWorld[i] = point[j*3+i] + pa[i]; | |||
output.addContactPoint(-normal,pointInWorld,-dep[j]); | |||
} | |||
} else | |||
{ | |||
// we have less contacts than we need, so we use them all | |||
for (j=0; j < cnum; j++) | |||
{ | |||
btVector3 pointInWorld; | |||
for (i=0; i<3; i++) | |||
pointInWorld[i] = point[j*3+i] + pa[i]-normal[i]*dep[j]; | |||
//pointInWorld[i] = point[j*3+i] + pa[i]; | |||
output.addContactPoint(-normal,pointInWorld,-dep[j]); | |||
} | |||
} | |||
} | |||
else { | |||
// we have more contacts than are wanted, some of them must be culled. | |||
// find the deepest point, it is always the first contact. | |||
int i1 = 0; | |||
btScalar maxdepth = dep[0]; | |||
for (i=1; i<cnum; i++) { | |||
if (dep[i] > maxdepth) { | |||
maxdepth = dep[i]; | |||
i1 = i; | |||
} | |||
} | |||
int iret[8]; | |||
cullPoints2 (cnum,ret,maxc,i1,iret); | |||
for (j=0; j < maxc; j++) { | |||
// dContactGeom *con = CONTACT(contact,skip*j); | |||
// for (i=0; i<3; i++) con->pos[i] = point[iret[j]*3+i] + pa[i]; | |||
// con->depth = dep[iret[j]]; | |||
btVector3 posInWorld; | |||
for (i=0; i<3; i++) | |||
posInWorld[i] = point[iret[j]*3+i] + pa[i]; | |||
if (code<4) | |||
{ | |||
output.addContactPoint(-normal,posInWorld,-dep[iret[j]]); | |||
} else | |||
{ | |||
output.addContactPoint(-normal,posInWorld-normal*dep[iret[j]],-dep[iret[j]]); | |||
} | |||
} | |||
cnum = maxc; | |||
} | |||
*return_code = code; | |||
return cnum; | |||
} | |||
void btBoxBoxDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* /*debugDraw*/,bool /*swapResults*/) | |||
{ | |||
const btTransform& transformA = input.m_transformA; | |||
const btTransform& transformB = input.m_transformB; | |||
int skip = 0; | |||
dContactGeom *contact = 0; | |||
dMatrix3 R1; | |||
dMatrix3 R2; | |||
for (int j=0;j<3;j++) | |||
{ | |||
R1[0+4*j] = transformA.getBasis()[j].x(); | |||
R2[0+4*j] = transformB.getBasis()[j].x(); | |||
R1[1+4*j] = transformA.getBasis()[j].y(); | |||
R2[1+4*j] = transformB.getBasis()[j].y(); | |||
R1[2+4*j] = transformA.getBasis()[j].z(); | |||
R2[2+4*j] = transformB.getBasis()[j].z(); | |||
} | |||
btVector3 normal; | |||
btScalar depth; | |||
int return_code; | |||
int maxc = 4; | |||
dBoxBox2 (transformA.getOrigin(), | |||
R1, | |||
2.f*m_box1->getHalfExtentsWithMargin(), | |||
transformB.getOrigin(), | |||
R2, | |||
2.f*m_box2->getHalfExtentsWithMargin(), | |||
normal, &depth, &return_code, | |||
maxc, contact, skip, | |||
output | |||
); | |||
} |
@@ -0,0 +1,44 @@ | |||
/* | |||
* Box-Box collision detection re-distributed under the ZLib license with permission from Russell L. Smith | |||
* Original version is from Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. | |||
* All rights reserved. Email: russ@q12.org Web: www.q12.org | |||
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. | |||
*/ | |||
#ifndef BT_BOX_BOX_DETECTOR_H | |||
#define BT_BOX_BOX_DETECTOR_H | |||
class btBoxShape; | |||
#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" | |||
/// btBoxBoxDetector wraps the ODE box-box collision detector | |||
/// re-distributed under the Zlib license with permission from Russell L. Smith | |||
struct btBoxBoxDetector : public btDiscreteCollisionDetectorInterface | |||
{ | |||
btBoxShape* m_box1; | |||
btBoxShape* m_box2; | |||
public: | |||
btBoxBoxDetector(btBoxShape* box1,btBoxShape* box2); | |||
virtual ~btBoxBoxDetector() {}; | |||
virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults=false); | |||
}; | |||
#endif //BT_BOX_BOX_DETECTOR_H |
@@ -0,0 +1,48 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_COLLISION_CONFIGURATION | |||
#define BT_COLLISION_CONFIGURATION | |||
struct btCollisionAlgorithmCreateFunc; | |||
class btStackAlloc; | |||
class btPoolAllocator; | |||
///btCollisionConfiguration allows to configure Bullet collision detection | |||
///stack allocator size, default collision algorithms and persistent manifold pool size | |||
///@todo: describe the meaning | |||
class btCollisionConfiguration | |||
{ | |||
public: | |||
virtual ~btCollisionConfiguration() | |||
{ | |||
} | |||
///memory pools | |||
virtual btPoolAllocator* getPersistentManifoldPool() = 0; | |||
virtual btPoolAllocator* getCollisionAlgorithmPool() = 0; | |||
virtual btStackAlloc* getStackAllocator() = 0; | |||
virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) =0; | |||
}; | |||
#endif //BT_COLLISION_CONFIGURATION | |||
@@ -0,0 +1,45 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_COLLISION_CREATE_FUNC | |||
#define BT_COLLISION_CREATE_FUNC | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
class btCollisionAlgorithm; | |||
class btCollisionObject; | |||
struct btCollisionAlgorithmConstructionInfo; | |||
///Used by the btCollisionDispatcher to register and create instances for btCollisionAlgorithm | |||
struct btCollisionAlgorithmCreateFunc | |||
{ | |||
bool m_swapped; | |||
btCollisionAlgorithmCreateFunc() | |||
:m_swapped(false) | |||
{ | |||
} | |||
virtual ~btCollisionAlgorithmCreateFunc(){}; | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& , btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
(void)body0; | |||
(void)body1; | |||
return 0; | |||
} | |||
}; | |||
#endif //BT_COLLISION_CREATE_FUNC | |||
@@ -0,0 +1,310 @@ | |||
/* | |||
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 "btCollisionDispatcher.h" | |||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionShapes/btCollisionShape.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" | |||
#include "LinearMath/btPoolAllocator.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionConfiguration.h" | |||
int gNumManifold = 0; | |||
#ifdef BT_DEBUG | |||
#include <stdio.h> | |||
#endif | |||
btCollisionDispatcher::btCollisionDispatcher (btCollisionConfiguration* collisionConfiguration): | |||
m_dispatcherFlags(btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD), | |||
m_collisionConfiguration(collisionConfiguration) | |||
{ | |||
int i; | |||
setNearCallback(defaultNearCallback); | |||
m_collisionAlgorithmPoolAllocator = collisionConfiguration->getCollisionAlgorithmPool(); | |||
m_persistentManifoldPoolAllocator = collisionConfiguration->getPersistentManifoldPool(); | |||
for (i=0;i<MAX_BROADPHASE_COLLISION_TYPES;i++) | |||
{ | |||
for (int j=0;j<MAX_BROADPHASE_COLLISION_TYPES;j++) | |||
{ | |||
m_doubleDispatch[i][j] = m_collisionConfiguration->getCollisionAlgorithmCreateFunc(i,j); | |||
btAssert(m_doubleDispatch[i][j]); | |||
} | |||
} | |||
} | |||
void btCollisionDispatcher::registerCollisionCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc) | |||
{ | |||
m_doubleDispatch[proxyType0][proxyType1] = createFunc; | |||
} | |||
btCollisionDispatcher::~btCollisionDispatcher() | |||
{ | |||
} | |||
btPersistentManifold* btCollisionDispatcher::getNewManifold(void* b0,void* b1) | |||
{ | |||
gNumManifold++; | |||
//btAssert(gNumManifold < 65535); | |||
btCollisionObject* body0 = (btCollisionObject*)b0; | |||
btCollisionObject* body1 = (btCollisionObject*)b1; | |||
//optional relative contact breaking threshold, turned on by default (use setDispatcherFlags to switch off feature for improved performance) | |||
btScalar contactBreakingThreshold = (m_dispatcherFlags & btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD) ? | |||
btMin(body0->getCollisionShape()->getContactBreakingThreshold(gContactBreakingThreshold) , body1->getCollisionShape()->getContactBreakingThreshold(gContactBreakingThreshold)) | |||
: gContactBreakingThreshold ; | |||
btScalar contactProcessingThreshold = btMin(body0->getContactProcessingThreshold(),body1->getContactProcessingThreshold()); | |||
void* mem = 0; | |||
if (m_persistentManifoldPoolAllocator->getFreeCount()) | |||
{ | |||
mem = m_persistentManifoldPoolAllocator->allocate(sizeof(btPersistentManifold)); | |||
} else | |||
{ | |||
//we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert. | |||
if ((m_dispatcherFlags&CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION)==0) | |||
{ | |||
mem = btAlignedAlloc(sizeof(btPersistentManifold),16); | |||
} else | |||
{ | |||
btAssert(0); | |||
//make sure to increase the m_defaultMaxPersistentManifoldPoolSize in the btDefaultCollisionConstructionInfo/btDefaultCollisionConfiguration | |||
return 0; | |||
} | |||
} | |||
btPersistentManifold* manifold = new(mem) btPersistentManifold (body0,body1,0,contactBreakingThreshold,contactProcessingThreshold); | |||
manifold->m_index1a = m_manifoldsPtr.size(); | |||
m_manifoldsPtr.push_back(manifold); | |||
return manifold; | |||
} | |||
void btCollisionDispatcher::clearManifold(btPersistentManifold* manifold) | |||
{ | |||
manifold->clearManifold(); | |||
} | |||
void btCollisionDispatcher::releaseManifold(btPersistentManifold* manifold) | |||
{ | |||
gNumManifold--; | |||
//printf("releaseManifold: gNumManifold %d\n",gNumManifold); | |||
clearManifold(manifold); | |||
int findIndex = manifold->m_index1a; | |||
btAssert(findIndex < m_manifoldsPtr.size()); | |||
m_manifoldsPtr.swap(findIndex,m_manifoldsPtr.size()-1); | |||
m_manifoldsPtr[findIndex]->m_index1a = findIndex; | |||
m_manifoldsPtr.pop_back(); | |||
manifold->~btPersistentManifold(); | |||
if (m_persistentManifoldPoolAllocator->validPtr(manifold)) | |||
{ | |||
m_persistentManifoldPoolAllocator->freeMemory(manifold); | |||
} else | |||
{ | |||
btAlignedFree(manifold); | |||
} | |||
} | |||
btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold) | |||
{ | |||
btCollisionAlgorithmConstructionInfo ci; | |||
ci.m_dispatcher1 = this; | |||
ci.m_manifold = sharedManifold; | |||
btCollisionAlgorithm* algo = m_doubleDispatch[body0->getCollisionShape()->getShapeType()][body1->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci,body0,body1); | |||
return algo; | |||
} | |||
bool btCollisionDispatcher::needsResponse(btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
//here you can do filtering | |||
bool hasResponse = | |||
(body0->hasContactResponse() && body1->hasContactResponse()); | |||
//no response between two static/kinematic bodies: | |||
hasResponse = hasResponse && | |||
((!body0->isStaticOrKinematicObject()) ||(! body1->isStaticOrKinematicObject())); | |||
return hasResponse; | |||
} | |||
bool btCollisionDispatcher::needsCollision(btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
btAssert(body0); | |||
btAssert(body1); | |||
bool needsCollision = true; | |||
#ifdef BT_DEBUG | |||
if (!(m_dispatcherFlags & btCollisionDispatcher::CD_STATIC_STATIC_REPORTED)) | |||
{ | |||
//broadphase filtering already deals with this | |||
if (body0->isStaticOrKinematicObject() && body1->isStaticOrKinematicObject()) | |||
{ | |||
m_dispatcherFlags |= btCollisionDispatcher::CD_STATIC_STATIC_REPORTED; | |||
printf("warning btCollisionDispatcher::needsCollision: static-static collision!\n"); | |||
} | |||
} | |||
#endif //BT_DEBUG | |||
if ((!body0->isActive()) && (!body1->isActive())) | |||
needsCollision = false; | |||
else if (!body0->checkCollideWith(body1)) | |||
needsCollision = false; | |||
return needsCollision ; | |||
} | |||
///interface for iterating all overlapping collision pairs, no matter how those pairs are stored (array, set, map etc) | |||
///this is useful for the collision dispatcher. | |||
class btCollisionPairCallback : public btOverlapCallback | |||
{ | |||
const btDispatcherInfo& m_dispatchInfo; | |||
btCollisionDispatcher* m_dispatcher; | |||
public: | |||
btCollisionPairCallback(const btDispatcherInfo& dispatchInfo,btCollisionDispatcher* dispatcher) | |||
:m_dispatchInfo(dispatchInfo), | |||
m_dispatcher(dispatcher) | |||
{ | |||
} | |||
/*btCollisionPairCallback& operator=(btCollisionPairCallback& other) | |||
{ | |||
m_dispatchInfo = other.m_dispatchInfo; | |||
m_dispatcher = other.m_dispatcher; | |||
return *this; | |||
} | |||
*/ | |||
virtual ~btCollisionPairCallback() {} | |||
virtual bool processOverlap(btBroadphasePair& pair) | |||
{ | |||
(*m_dispatcher->getNearCallback())(pair,*m_dispatcher,m_dispatchInfo); | |||
return false; | |||
} | |||
}; | |||
void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) | |||
{ | |||
//m_blockedForChanges = true; | |||
btCollisionPairCallback collisionCallback(dispatchInfo,this); | |||
pairCache->processAllOverlappingPairs(&collisionCallback,dispatcher); | |||
//m_blockedForChanges = false; | |||
} | |||
//by default, Bullet will use this near callback | |||
void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo) | |||
{ | |||
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject; | |||
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject; | |||
if (dispatcher.needsCollision(colObj0,colObj1)) | |||
{ | |||
//dispatcher will keep algorithms persistent in the collision pair | |||
if (!collisionPair.m_algorithm) | |||
{ | |||
collisionPair.m_algorithm = dispatcher.findAlgorithm(colObj0,colObj1); | |||
} | |||
if (collisionPair.m_algorithm) | |||
{ | |||
btManifoldResult contactPointResult(colObj0,colObj1); | |||
if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE) | |||
{ | |||
//discrete collision detection query | |||
collisionPair.m_algorithm->processCollision(colObj0,colObj1,dispatchInfo,&contactPointResult); | |||
} else | |||
{ | |||
//continuous collision detection query, time of impact (toi) | |||
btScalar toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0,colObj1,dispatchInfo,&contactPointResult); | |||
if (dispatchInfo.m_timeOfImpact > toi) | |||
dispatchInfo.m_timeOfImpact = toi; | |||
} | |||
} | |||
} | |||
} | |||
void* btCollisionDispatcher::allocateCollisionAlgorithm(int size) | |||
{ | |||
if (m_collisionAlgorithmPoolAllocator->getFreeCount()) | |||
{ | |||
return m_collisionAlgorithmPoolAllocator->allocate(size); | |||
} | |||
//warn user for overflow? | |||
return btAlignedAlloc(static_cast<size_t>(size), 16); | |||
} | |||
void btCollisionDispatcher::freeCollisionAlgorithm(void* ptr) | |||
{ | |||
if (m_collisionAlgorithmPoolAllocator->validPtr(ptr)) | |||
{ | |||
m_collisionAlgorithmPoolAllocator->freeMemory(ptr); | |||
} else | |||
{ | |||
btAlignedFree(ptr); | |||
} | |||
} |
@@ -0,0 +1,172 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_COLLISION__DISPATCHER_H | |||
#define BT_COLLISION__DISPATCHER_H | |||
#include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
#include "BulletCollision/CollisionDispatch/btManifoldResult.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
class btIDebugDraw; | |||
class btOverlappingPairCache; | |||
class btPoolAllocator; | |||
class btCollisionConfiguration; | |||
#include "btCollisionCreateFunc.h" | |||
#define USE_DISPATCH_REGISTRY_ARRAY 1 | |||
class btCollisionDispatcher; | |||
///user can override this nearcallback for collision filtering and more finegrained control over collision detection | |||
typedef void (*btNearCallback)(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo); | |||
///btCollisionDispatcher supports algorithms that handle ConvexConvex and ConvexConcave collision pairs. | |||
///Time of Impact, Closest Points and Penetration Depth. | |||
class btCollisionDispatcher : public btDispatcher | |||
{ | |||
protected: | |||
int m_dispatcherFlags; | |||
btAlignedObjectArray<btPersistentManifold*> m_manifoldsPtr; | |||
btManifoldResult m_defaultManifoldResult; | |||
btNearCallback m_nearCallback; | |||
btPoolAllocator* m_collisionAlgorithmPoolAllocator; | |||
btPoolAllocator* m_persistentManifoldPoolAllocator; | |||
btCollisionAlgorithmCreateFunc* m_doubleDispatch[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES]; | |||
btCollisionConfiguration* m_collisionConfiguration; | |||
public: | |||
enum DispatcherFlags | |||
{ | |||
CD_STATIC_STATIC_REPORTED = 1, | |||
CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD = 2, | |||
CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION = 4 | |||
}; | |||
int getDispatcherFlags() const | |||
{ | |||
return m_dispatcherFlags; | |||
} | |||
void setDispatcherFlags(int flags) | |||
{ | |||
m_dispatcherFlags = flags; | |||
} | |||
///registerCollisionCreateFunc allows registration of custom/alternative collision create functions | |||
void registerCollisionCreateFunc(int proxyType0,int proxyType1, btCollisionAlgorithmCreateFunc* createFunc); | |||
int getNumManifolds() const | |||
{ | |||
return int( m_manifoldsPtr.size()); | |||
} | |||
btPersistentManifold** getInternalManifoldPointer() | |||
{ | |||
return m_manifoldsPtr.size()? &m_manifoldsPtr[0] : 0; | |||
} | |||
btPersistentManifold* getManifoldByIndexInternal(int index) | |||
{ | |||
return m_manifoldsPtr[index]; | |||
} | |||
const btPersistentManifold* getManifoldByIndexInternal(int index) const | |||
{ | |||
return m_manifoldsPtr[index]; | |||
} | |||
btCollisionDispatcher (btCollisionConfiguration* collisionConfiguration); | |||
virtual ~btCollisionDispatcher(); | |||
virtual btPersistentManifold* getNewManifold(void* b0,void* b1); | |||
virtual void releaseManifold(btPersistentManifold* manifold); | |||
virtual void clearManifold(btPersistentManifold* manifold); | |||
btCollisionAlgorithm* findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold = 0); | |||
virtual bool needsCollision(btCollisionObject* body0,btCollisionObject* body1); | |||
virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1); | |||
virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) ; | |||
void setNearCallback(btNearCallback nearCallback) | |||
{ | |||
m_nearCallback = nearCallback; | |||
} | |||
btNearCallback getNearCallback() const | |||
{ | |||
return m_nearCallback; | |||
} | |||
//by default, Bullet will use this near callback | |||
static void defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo); | |||
virtual void* allocateCollisionAlgorithm(int size); | |||
virtual void freeCollisionAlgorithm(void* ptr); | |||
btCollisionConfiguration* getCollisionConfiguration() | |||
{ | |||
return m_collisionConfiguration; | |||
} | |||
const btCollisionConfiguration* getCollisionConfiguration() const | |||
{ | |||
return m_collisionConfiguration; | |||
} | |||
void setCollisionConfiguration(btCollisionConfiguration* config) | |||
{ | |||
m_collisionConfiguration = config; | |||
} | |||
virtual btPoolAllocator* getInternalManifoldPool() | |||
{ | |||
return m_persistentManifoldPoolAllocator; | |||
} | |||
virtual const btPoolAllocator* getInternalManifoldPool() const | |||
{ | |||
return m_persistentManifoldPoolAllocator; | |||
} | |||
}; | |||
#endif //BT_COLLISION__DISPATCHER_H | |||
@@ -0,0 +1,116 @@ | |||
/* | |||
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 "btCollisionObject.h" | |||
#include "LinearMath/btSerializer.h" | |||
btCollisionObject::btCollisionObject() | |||
: m_anisotropicFriction(1.f,1.f,1.f), | |||
m_hasAnisotropicFriction(false), | |||
m_contactProcessingThreshold(BT_LARGE_FLOAT), | |||
m_broadphaseHandle(0), | |||
m_collisionShape(0), | |||
m_extensionPointer(0), | |||
m_rootCollisionShape(0), | |||
m_collisionFlags(btCollisionObject::CF_STATIC_OBJECT), | |||
m_islandTag1(-1), | |||
m_companionId(-1), | |||
m_activationState1(1), | |||
m_deactivationTime(btScalar(0.)), | |||
m_friction(btScalar(0.5)), | |||
m_restitution(btScalar(0.)), | |||
m_internalType(CO_COLLISION_OBJECT), | |||
m_userObjectPointer(0), | |||
m_hitFraction(btScalar(1.)), | |||
m_ccdSweptSphereRadius(btScalar(0.)), | |||
m_ccdMotionThreshold(btScalar(0.)), | |||
m_checkCollideWith(false) | |||
{ | |||
m_worldTransform.setIdentity(); | |||
} | |||
btCollisionObject::~btCollisionObject() | |||
{ | |||
} | |||
void btCollisionObject::setActivationState(int newState) | |||
{ | |||
if ( (m_activationState1 != DISABLE_DEACTIVATION) && (m_activationState1 != DISABLE_SIMULATION)) | |||
m_activationState1 = newState; | |||
} | |||
void btCollisionObject::forceActivationState(int newState) | |||
{ | |||
m_activationState1 = newState; | |||
} | |||
void btCollisionObject::activate(bool forceActivation) | |||
{ | |||
if (forceActivation || !(m_collisionFlags & (CF_STATIC_OBJECT|CF_KINEMATIC_OBJECT))) | |||
{ | |||
setActivationState(ACTIVE_TAG); | |||
m_deactivationTime = btScalar(0.); | |||
} | |||
} | |||
const char* btCollisionObject::serialize(void* dataBuffer, btSerializer* serializer) const | |||
{ | |||
btCollisionObjectData* dataOut = (btCollisionObjectData*)dataBuffer; | |||
m_worldTransform.serialize(dataOut->m_worldTransform); | |||
m_interpolationWorldTransform.serialize(dataOut->m_interpolationWorldTransform); | |||
m_interpolationLinearVelocity.serialize(dataOut->m_interpolationLinearVelocity); | |||
m_interpolationAngularVelocity.serialize(dataOut->m_interpolationAngularVelocity); | |||
m_anisotropicFriction.serialize(dataOut->m_anisotropicFriction); | |||
dataOut->m_hasAnisotropicFriction = m_hasAnisotropicFriction; | |||
dataOut->m_contactProcessingThreshold = m_contactProcessingThreshold; | |||
dataOut->m_broadphaseHandle = 0; | |||
dataOut->m_collisionShape = serializer->getUniquePointer(m_collisionShape); | |||
dataOut->m_rootCollisionShape = 0;//@todo | |||
dataOut->m_collisionFlags = m_collisionFlags; | |||
dataOut->m_islandTag1 = m_islandTag1; | |||
dataOut->m_companionId = m_companionId; | |||
dataOut->m_activationState1 = m_activationState1; | |||
dataOut->m_activationState1 = m_activationState1; | |||
dataOut->m_deactivationTime = m_deactivationTime; | |||
dataOut->m_friction = m_friction; | |||
dataOut->m_restitution = m_restitution; | |||
dataOut->m_internalType = m_internalType; | |||
char* name = (char*) serializer->findNameForPointer(this); | |||
dataOut->m_name = (char*)serializer->getUniquePointer(name); | |||
if (dataOut->m_name) | |||
{ | |||
serializer->serializeName(name); | |||
} | |||
dataOut->m_hitFraction = m_hitFraction; | |||
dataOut->m_ccdSweptSphereRadius = m_ccdSweptSphereRadius; | |||
dataOut->m_ccdMotionThreshold = m_ccdMotionThreshold; | |||
dataOut->m_ccdMotionThreshold = m_ccdMotionThreshold; | |||
dataOut->m_checkCollideWith = m_checkCollideWith; | |||
return btCollisionObjectDataName; | |||
} | |||
void btCollisionObject::serializeSingleObject(class btSerializer* serializer) const | |||
{ | |||
int len = calculateSerializeBufferSize(); | |||
btChunk* chunk = serializer->allocate(len,1); | |||
const char* structType = serialize(chunk->m_oldPtr, serializer); | |||
serializer->finalizeChunk(chunk,structType,BT_COLLISIONOBJECT_CODE,(void*)this); | |||
} |
@@ -0,0 +1,524 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_COLLISION_OBJECT_H | |||
#define BT_COLLISION_OBJECT_H | |||
#include "LinearMath/btTransform.h" | |||
//island management, m_activationState1 | |||
#define ACTIVE_TAG 1 | |||
#define ISLAND_SLEEPING 2 | |||
#define WANTS_DEACTIVATION 3 | |||
#define DISABLE_DEACTIVATION 4 | |||
#define DISABLE_SIMULATION 5 | |||
struct btBroadphaseProxy; | |||
class btCollisionShape; | |||
struct btCollisionShapeData; | |||
#include "LinearMath/btMotionState.h" | |||
#include "LinearMath/btAlignedAllocator.h" | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
typedef btAlignedObjectArray<class btCollisionObject*> btCollisionObjectArray; | |||
#ifdef BT_USE_DOUBLE_PRECISION | |||
#define btCollisionObjectData btCollisionObjectDoubleData | |||
#define btCollisionObjectDataName "btCollisionObjectDoubleData" | |||
#else | |||
#define btCollisionObjectData btCollisionObjectFloatData | |||
#define btCollisionObjectDataName "btCollisionObjectFloatData" | |||
#endif | |||
/// btCollisionObject can be used to manage collision detection objects. | |||
/// btCollisionObject maintains all information that is needed for a collision detection: Shape, Transform and AABB proxy. | |||
/// They can be added to the btCollisionWorld. | |||
ATTRIBUTE_ALIGNED16(class) btCollisionObject | |||
{ | |||
protected: | |||
btTransform m_worldTransform; | |||
///m_interpolationWorldTransform is used for CCD and interpolation | |||
///it can be either previous or future (predicted) transform | |||
btTransform m_interpolationWorldTransform; | |||
//those two are experimental: just added for bullet time effect, so you can still apply impulses (directly modifying velocities) | |||
//without destroying the continuous interpolated motion (which uses this interpolation velocities) | |||
btVector3 m_interpolationLinearVelocity; | |||
btVector3 m_interpolationAngularVelocity; | |||
btVector3 m_anisotropicFriction; | |||
int m_hasAnisotropicFriction; | |||
btScalar m_contactProcessingThreshold; | |||
btBroadphaseProxy* m_broadphaseHandle; | |||
btCollisionShape* m_collisionShape; | |||
///m_extensionPointer is used by some internal low-level Bullet extensions. | |||
void* m_extensionPointer; | |||
///m_rootCollisionShape is temporarily used to store the original collision shape | |||
///The m_collisionShape might be temporarily replaced by a child collision shape during collision detection purposes | |||
///If it is NULL, the m_collisionShape is not temporarily replaced. | |||
btCollisionShape* m_rootCollisionShape; | |||
int m_collisionFlags; | |||
int m_islandTag1; | |||
int m_companionId; | |||
int m_activationState1; | |||
btScalar m_deactivationTime; | |||
btScalar m_friction; | |||
btScalar m_restitution; | |||
///m_internalType is reserved to distinguish Bullet's btCollisionObject, btRigidBody, btSoftBody, btGhostObject etc. | |||
///do not assign your own m_internalType unless you write a new dynamics object class. | |||
int m_internalType; | |||
///users can point to their objects, m_userPointer is not used by Bullet, see setUserPointer/getUserPointer | |||
void* m_userObjectPointer; | |||
///time of impact calculation | |||
btScalar m_hitFraction; | |||
///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: | |||
btScalar m_ccdSweptSphereRadius; | |||
/// Don't do continuous collision detection if the motion (in one step) is less then m_ccdMotionThreshold | |||
btScalar m_ccdMotionThreshold; | |||
/// If some object should have elaborate collision filtering by sub-classes | |||
int m_checkCollideWith; | |||
virtual bool checkCollideWithOverride(btCollisionObject* /* co */) | |||
{ | |||
return true; | |||
} | |||
public: | |||
BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
enum CollisionFlags | |||
{ | |||
CF_STATIC_OBJECT= 1, | |||
CF_KINEMATIC_OBJECT= 2, | |||
CF_NO_CONTACT_RESPONSE = 4, | |||
CF_CUSTOM_MATERIAL_CALLBACK = 8,//this allows per-triangle material (friction/restitution) | |||
CF_CHARACTER_OBJECT = 16, | |||
CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing | |||
CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing | |||
}; | |||
enum CollisionObjectTypes | |||
{ | |||
CO_COLLISION_OBJECT =1, | |||
CO_RIGID_BODY=2, | |||
///CO_GHOST_OBJECT keeps track of all objects overlapping its AABB and that pass its collision filter | |||
///It is useful for collision sensors, explosion objects, character controller etc. | |||
CO_GHOST_OBJECT=4, | |||
CO_SOFT_BODY=8, | |||
CO_HF_FLUID=16, | |||
CO_USER_TYPE=32 | |||
}; | |||
SIMD_FORCE_INLINE bool mergesSimulationIslands() const | |||
{ | |||
///static objects, kinematic and object without contact response don't merge islands | |||
return ((m_collisionFlags & (CF_STATIC_OBJECT | CF_KINEMATIC_OBJECT | CF_NO_CONTACT_RESPONSE) )==0); | |||
} | |||
const btVector3& getAnisotropicFriction() const | |||
{ | |||
return m_anisotropicFriction; | |||
} | |||
void setAnisotropicFriction(const btVector3& anisotropicFriction) | |||
{ | |||
m_anisotropicFriction = anisotropicFriction; | |||
m_hasAnisotropicFriction = (anisotropicFriction[0]!=1.f) || (anisotropicFriction[1]!=1.f) || (anisotropicFriction[2]!=1.f); | |||
} | |||
bool hasAnisotropicFriction() const | |||
{ | |||
return m_hasAnisotropicFriction!=0; | |||
} | |||
///the constraint solver can discard solving contacts, if the distance is above this threshold. 0 by default. | |||
///Note that using contacts with positive distance can improve stability. It increases, however, the chance of colliding with degerate contacts, such as 'interior' triangle edges | |||
void setContactProcessingThreshold( btScalar contactProcessingThreshold) | |||
{ | |||
m_contactProcessingThreshold = contactProcessingThreshold; | |||
} | |||
btScalar getContactProcessingThreshold() const | |||
{ | |||
return m_contactProcessingThreshold; | |||
} | |||
SIMD_FORCE_INLINE bool isStaticObject() const { | |||
return (m_collisionFlags & CF_STATIC_OBJECT) != 0; | |||
} | |||
SIMD_FORCE_INLINE bool isKinematicObject() const | |||
{ | |||
return (m_collisionFlags & CF_KINEMATIC_OBJECT) != 0; | |||
} | |||
SIMD_FORCE_INLINE bool isStaticOrKinematicObject() const | |||
{ | |||
return (m_collisionFlags & (CF_KINEMATIC_OBJECT | CF_STATIC_OBJECT)) != 0 ; | |||
} | |||
SIMD_FORCE_INLINE bool hasContactResponse() const { | |||
return (m_collisionFlags & CF_NO_CONTACT_RESPONSE)==0; | |||
} | |||
btCollisionObject(); | |||
virtual ~btCollisionObject(); | |||
virtual void setCollisionShape(btCollisionShape* collisionShape) | |||
{ | |||
m_collisionShape = collisionShape; | |||
m_rootCollisionShape = collisionShape; | |||
} | |||
SIMD_FORCE_INLINE const btCollisionShape* getCollisionShape() const | |||
{ | |||
return m_collisionShape; | |||
} | |||
SIMD_FORCE_INLINE btCollisionShape* getCollisionShape() | |||
{ | |||
return m_collisionShape; | |||
} | |||
SIMD_FORCE_INLINE const btCollisionShape* getRootCollisionShape() const | |||
{ | |||
return m_rootCollisionShape; | |||
} | |||
SIMD_FORCE_INLINE btCollisionShape* getRootCollisionShape() | |||
{ | |||
return m_rootCollisionShape; | |||
} | |||
///Avoid using this internal API call | |||
///internalSetTemporaryCollisionShape is used to temporary replace the actual collision shape by a child collision shape. | |||
void internalSetTemporaryCollisionShape(btCollisionShape* collisionShape) | |||
{ | |||
m_collisionShape = collisionShape; | |||
} | |||
///Avoid using this internal API call, the extension pointer is used by some Bullet extensions. | |||
///If you need to store your own user pointer, use 'setUserPointer/getUserPointer' instead. | |||
void* internalGetExtensionPointer() const | |||
{ | |||
return m_extensionPointer; | |||
} | |||
///Avoid using this internal API call, the extension pointer is used by some Bullet extensions | |||
///If you need to store your own user pointer, use 'setUserPointer/getUserPointer' instead. | |||
void internalSetExtensionPointer(void* pointer) | |||
{ | |||
m_extensionPointer = pointer; | |||
} | |||
SIMD_FORCE_INLINE int getActivationState() const { return m_activationState1;} | |||
void setActivationState(int newState); | |||
void setDeactivationTime(btScalar time) | |||
{ | |||
m_deactivationTime = time; | |||
} | |||
btScalar getDeactivationTime() const | |||
{ | |||
return m_deactivationTime; | |||
} | |||
void forceActivationState(int newState); | |||
void activate(bool forceActivation = false); | |||
SIMD_FORCE_INLINE bool isActive() const | |||
{ | |||
return ((getActivationState() != ISLAND_SLEEPING) && (getActivationState() != DISABLE_SIMULATION)); | |||
} | |||
void setRestitution(btScalar rest) | |||
{ | |||
m_restitution = rest; | |||
} | |||
btScalar getRestitution() const | |||
{ | |||
return m_restitution; | |||
} | |||
void setFriction(btScalar frict) | |||
{ | |||
m_friction = frict; | |||
} | |||
btScalar getFriction() const | |||
{ | |||
return m_friction; | |||
} | |||
///reserved for Bullet internal usage | |||
int getInternalType() const | |||
{ | |||
return m_internalType; | |||
} | |||
btTransform& getWorldTransform() | |||
{ | |||
return m_worldTransform; | |||
} | |||
const btTransform& getWorldTransform() const | |||
{ | |||
return m_worldTransform; | |||
} | |||
void setWorldTransform(const btTransform& worldTrans) | |||
{ | |||
m_worldTransform = worldTrans; | |||
} | |||
SIMD_FORCE_INLINE btBroadphaseProxy* getBroadphaseHandle() | |||
{ | |||
return m_broadphaseHandle; | |||
} | |||
SIMD_FORCE_INLINE const btBroadphaseProxy* getBroadphaseHandle() const | |||
{ | |||
return m_broadphaseHandle; | |||
} | |||
void setBroadphaseHandle(btBroadphaseProxy* handle) | |||
{ | |||
m_broadphaseHandle = handle; | |||
} | |||
const btTransform& getInterpolationWorldTransform() const | |||
{ | |||
return m_interpolationWorldTransform; | |||
} | |||
btTransform& getInterpolationWorldTransform() | |||
{ | |||
return m_interpolationWorldTransform; | |||
} | |||
void setInterpolationWorldTransform(const btTransform& trans) | |||
{ | |||
m_interpolationWorldTransform = trans; | |||
} | |||
void setInterpolationLinearVelocity(const btVector3& linvel) | |||
{ | |||
m_interpolationLinearVelocity = linvel; | |||
} | |||
void setInterpolationAngularVelocity(const btVector3& angvel) | |||
{ | |||
m_interpolationAngularVelocity = angvel; | |||
} | |||
const btVector3& getInterpolationLinearVelocity() const | |||
{ | |||
return m_interpolationLinearVelocity; | |||
} | |||
const btVector3& getInterpolationAngularVelocity() const | |||
{ | |||
return m_interpolationAngularVelocity; | |||
} | |||
SIMD_FORCE_INLINE int getIslandTag() const | |||
{ | |||
return m_islandTag1; | |||
} | |||
void setIslandTag(int tag) | |||
{ | |||
m_islandTag1 = tag; | |||
} | |||
SIMD_FORCE_INLINE int getCompanionId() const | |||
{ | |||
return m_companionId; | |||
} | |||
void setCompanionId(int id) | |||
{ | |||
m_companionId = id; | |||
} | |||
SIMD_FORCE_INLINE btScalar getHitFraction() const | |||
{ | |||
return m_hitFraction; | |||
} | |||
void setHitFraction(btScalar hitFraction) | |||
{ | |||
m_hitFraction = hitFraction; | |||
} | |||
SIMD_FORCE_INLINE int getCollisionFlags() const | |||
{ | |||
return m_collisionFlags; | |||
} | |||
void setCollisionFlags(int flags) | |||
{ | |||
m_collisionFlags = flags; | |||
} | |||
///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: | |||
btScalar getCcdSweptSphereRadius() const | |||
{ | |||
return m_ccdSweptSphereRadius; | |||
} | |||
///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: | |||
void setCcdSweptSphereRadius(btScalar radius) | |||
{ | |||
m_ccdSweptSphereRadius = radius; | |||
} | |||
btScalar getCcdMotionThreshold() const | |||
{ | |||
return m_ccdMotionThreshold; | |||
} | |||
btScalar getCcdSquareMotionThreshold() const | |||
{ | |||
return m_ccdMotionThreshold*m_ccdMotionThreshold; | |||
} | |||
/// Don't do continuous collision detection if the motion (in one step) is less then m_ccdMotionThreshold | |||
void setCcdMotionThreshold(btScalar ccdMotionThreshold) | |||
{ | |||
m_ccdMotionThreshold = ccdMotionThreshold; | |||
} | |||
///users can point to their objects, userPointer is not used by Bullet | |||
void* getUserPointer() const | |||
{ | |||
return m_userObjectPointer; | |||
} | |||
///users can point to their objects, userPointer is not used by Bullet | |||
void setUserPointer(void* userPointer) | |||
{ | |||
m_userObjectPointer = userPointer; | |||
} | |||
inline bool checkCollideWith(btCollisionObject* co) | |||
{ | |||
if (m_checkCollideWith) | |||
return checkCollideWithOverride(co); | |||
return true; | |||
} | |||
virtual int calculateSerializeBufferSize() const; | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
virtual const char* serialize(void* dataBuffer, class btSerializer* serializer) const; | |||
virtual void serializeSingleObject(class btSerializer* serializer) const; | |||
}; | |||
///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
struct btCollisionObjectDoubleData | |||
{ | |||
void *m_broadphaseHandle; | |||
void *m_collisionShape; | |||
btCollisionShapeData *m_rootCollisionShape; | |||
char *m_name; | |||
btTransformDoubleData m_worldTransform; | |||
btTransformDoubleData m_interpolationWorldTransform; | |||
btVector3DoubleData m_interpolationLinearVelocity; | |||
btVector3DoubleData m_interpolationAngularVelocity; | |||
btVector3DoubleData m_anisotropicFriction; | |||
double m_contactProcessingThreshold; | |||
double m_deactivationTime; | |||
double m_friction; | |||
double m_restitution; | |||
double m_hitFraction; | |||
double m_ccdSweptSphereRadius; | |||
double m_ccdMotionThreshold; | |||
int m_hasAnisotropicFriction; | |||
int m_collisionFlags; | |||
int m_islandTag1; | |||
int m_companionId; | |||
int m_activationState1; | |||
int m_internalType; | |||
int m_checkCollideWith; | |||
char m_padding[4]; | |||
}; | |||
///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
struct btCollisionObjectFloatData | |||
{ | |||
void *m_broadphaseHandle; | |||
void *m_collisionShape; | |||
btCollisionShapeData *m_rootCollisionShape; | |||
char *m_name; | |||
btTransformFloatData m_worldTransform; | |||
btTransformFloatData m_interpolationWorldTransform; | |||
btVector3FloatData m_interpolationLinearVelocity; | |||
btVector3FloatData m_interpolationAngularVelocity; | |||
btVector3FloatData m_anisotropicFriction; | |||
float m_contactProcessingThreshold; | |||
float m_deactivationTime; | |||
float m_friction; | |||
float m_restitution; | |||
float m_hitFraction; | |||
float m_ccdSweptSphereRadius; | |||
float m_ccdMotionThreshold; | |||
int m_hasAnisotropicFriction; | |||
int m_collisionFlags; | |||
int m_islandTag1; | |||
int m_companionId; | |||
int m_activationState1; | |||
int m_internalType; | |||
int m_checkCollideWith; | |||
}; | |||
SIMD_FORCE_INLINE int btCollisionObject::calculateSerializeBufferSize() const | |||
{ | |||
return sizeof(btCollisionObjectData); | |||
} | |||
#endif //BT_COLLISION_OBJECT_H |
@@ -0,0 +1,509 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2006 Erwin Coumans http://bulletphysics.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. | |||
*/ | |||
/** | |||
* @mainpage Bullet Documentation | |||
* | |||
* @section intro_sec Introduction | |||
* Bullet Collision Detection & Physics SDK | |||
* | |||
* Bullet is a Collision Detection and Rigid Body Dynamics Library. The Library is Open Source and free for commercial use, under the ZLib license ( http://opensource.org/licenses/zlib-license.php ). | |||
* | |||
* The main documentation is Bullet_User_Manual.pdf, included in the source code distribution. | |||
* There is the Physics Forum for feedback and general Collision Detection and Physics discussions. | |||
* Please visit http://www.bulletphysics.com | |||
* | |||
* @section install_sec Installation | |||
* | |||
* @subsection step1 Step 1: Download | |||
* You can download the Bullet Physics Library from the Google Code repository: http://code.google.com/p/bullet/downloads/list | |||
* | |||
* @subsection step2 Step 2: Building | |||
* Bullet main build system for all platforms is cmake, you can download http://www.cmake.org | |||
* cmake can autogenerate projectfiles for Microsoft Visual Studio, Apple Xcode, KDevelop and Unix Makefiles. | |||
* The easiest is to run the CMake cmake-gui graphical user interface and choose the options and generate projectfiles. | |||
* You can also use cmake in the command-line. Here are some examples for various platforms: | |||
* cmake . -G "Visual Studio 9 2008" | |||
* cmake . -G Xcode | |||
* cmake . -G "Unix Makefiles" | |||
* Although cmake is recommended, you can also use autotools for UNIX: ./autogen.sh ./configure to create a Makefile and then run make. | |||
* | |||
* @subsection step3 Step 3: Testing demos | |||
* Try to run and experiment with BasicDemo executable as a starting point. | |||
* Bullet can be used in several ways, as Full Rigid Body simulation, as Collision Detector Library or Low Level / Snippets like the GJK Closest Point calculation. | |||
* The Dependencies can be seen in this documentation under Directories | |||
* | |||
* @subsection step4 Step 4: Integrating in your application, full Rigid Body and Soft Body simulation | |||
* Check out BasicDemo how to create a btDynamicsWorld, btRigidBody and btCollisionShape, Stepping the simulation and synchronizing your graphics object transform. | |||
* Check out SoftDemo how to use soft body dynamics, using btSoftRigidDynamicsWorld. | |||
* @subsection step5 Step 5 : Integrate the Collision Detection Library (without Dynamics and other Extras) | |||
* Bullet Collision Detection can also be used without the Dynamics/Extras. | |||
* Check out btCollisionWorld and btCollisionObject, and the CollisionInterfaceDemo. | |||
* @subsection step6 Step 6 : Use Snippets like the GJK Closest Point calculation. | |||
* Bullet has been designed in a modular way keeping dependencies to a minimum. The ConvexHullDistance demo demonstrates direct use of btGjkPairDetector. | |||
* | |||
* @section copyright Copyright | |||
* For up-to-data information and copyright and contributors list check out the Bullet_User_Manual.pdf | |||
* | |||
*/ | |||
#ifndef BT_COLLISION_WORLD_H | |||
#define BT_COLLISION_WORLD_H | |||
class btStackAlloc; | |||
class btCollisionShape; | |||
class btConvexShape; | |||
class btBroadphaseInterface; | |||
class btSerializer; | |||
#include "LinearMath/btVector3.h" | |||
#include "LinearMath/btTransform.h" | |||
#include "btCollisionObject.h" | |||
#include "btCollisionDispatcher.h" | |||
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
///CollisionWorld is interface and container for the collision detection | |||
class btCollisionWorld | |||
{ | |||
protected: | |||
btAlignedObjectArray<btCollisionObject*> m_collisionObjects; | |||
btDispatcher* m_dispatcher1; | |||
btDispatcherInfo m_dispatchInfo; | |||
btStackAlloc* m_stackAlloc; | |||
btBroadphaseInterface* m_broadphasePairCache; | |||
btIDebugDraw* m_debugDrawer; | |||
///m_forceUpdateAllAabbs can be set to false as an optimization to only update active object AABBs | |||
///it is true by default, because it is error-prone (setting the position of static objects wouldn't update their AABB) | |||
bool m_forceUpdateAllAabbs; | |||
void serializeCollisionObjects(btSerializer* serializer); | |||
public: | |||
//this constructor doesn't own the dispatcher and paircache/broadphase | |||
btCollisionWorld(btDispatcher* dispatcher,btBroadphaseInterface* broadphasePairCache, btCollisionConfiguration* collisionConfiguration); | |||
virtual ~btCollisionWorld(); | |||
void setBroadphase(btBroadphaseInterface* pairCache) | |||
{ | |||
m_broadphasePairCache = pairCache; | |||
} | |||
const btBroadphaseInterface* getBroadphase() const | |||
{ | |||
return m_broadphasePairCache; | |||
} | |||
btBroadphaseInterface* getBroadphase() | |||
{ | |||
return m_broadphasePairCache; | |||
} | |||
btOverlappingPairCache* getPairCache() | |||
{ | |||
return m_broadphasePairCache->getOverlappingPairCache(); | |||
} | |||
btDispatcher* getDispatcher() | |||
{ | |||
return m_dispatcher1; | |||
} | |||
const btDispatcher* getDispatcher() const | |||
{ | |||
return m_dispatcher1; | |||
} | |||
void updateSingleAabb(btCollisionObject* colObj); | |||
virtual void updateAabbs(); | |||
virtual void setDebugDrawer(btIDebugDraw* debugDrawer) | |||
{ | |||
m_debugDrawer = debugDrawer; | |||
} | |||
virtual btIDebugDraw* getDebugDrawer() | |||
{ | |||
return m_debugDrawer; | |||
} | |||
virtual void debugDrawWorld(); | |||
virtual void debugDrawObject(const btTransform& worldTransform, const btCollisionShape* shape, const btVector3& color); | |||
///LocalShapeInfo gives extra information for complex shapes | |||
///Currently, only btTriangleMeshShape is available, so it just contains triangleIndex and subpart | |||
struct LocalShapeInfo | |||
{ | |||
int m_shapePart; | |||
int m_triangleIndex; | |||
//const btCollisionShape* m_shapeTemp; | |||
//const btTransform* m_shapeLocalTransform; | |||
}; | |||
struct LocalRayResult | |||
{ | |||
LocalRayResult(btCollisionObject* collisionObject, | |||
LocalShapeInfo* localShapeInfo, | |||
const btVector3& hitNormalLocal, | |||
btScalar hitFraction) | |||
:m_collisionObject(collisionObject), | |||
m_localShapeInfo(localShapeInfo), | |||
m_hitNormalLocal(hitNormalLocal), | |||
m_hitFraction(hitFraction) | |||
{ | |||
} | |||
btCollisionObject* m_collisionObject; | |||
LocalShapeInfo* m_localShapeInfo; | |||
btVector3 m_hitNormalLocal; | |||
btScalar m_hitFraction; | |||
}; | |||
///RayResultCallback is used to report new raycast results | |||
struct RayResultCallback | |||
{ | |||
btScalar m_closestHitFraction; | |||
btCollisionObject* m_collisionObject; | |||
short int m_collisionFilterGroup; | |||
short int m_collisionFilterMask; | |||
//@BP Mod - Custom flags, currently used to enable backface culling on tri-meshes, see btRaycastCallback | |||
unsigned int m_flags; | |||
virtual ~RayResultCallback() | |||
{ | |||
} | |||
bool hasHit() const | |||
{ | |||
return (m_collisionObject != 0); | |||
} | |||
RayResultCallback() | |||
:m_closestHitFraction(btScalar(1.)), | |||
m_collisionObject(0), | |||
m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), | |||
m_collisionFilterMask(btBroadphaseProxy::AllFilter), | |||
//@BP Mod | |||
m_flags(0) | |||
{ | |||
} | |||
virtual bool needsCollision(btBroadphaseProxy* proxy0) const | |||
{ | |||
bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0; | |||
collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask); | |||
return collides; | |||
} | |||
virtual btScalar addSingleResult(LocalRayResult& rayResult,bool normalInWorldSpace) = 0; | |||
}; | |||
struct ClosestRayResultCallback : public RayResultCallback | |||
{ | |||
ClosestRayResultCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld) | |||
:m_rayFromWorld(rayFromWorld), | |||
m_rayToWorld(rayToWorld) | |||
{ | |||
} | |||
btVector3 m_rayFromWorld;//used to calculate hitPointWorld from hitFraction | |||
btVector3 m_rayToWorld; | |||
btVector3 m_hitNormalWorld; | |||
btVector3 m_hitPointWorld; | |||
virtual btScalar addSingleResult(LocalRayResult& rayResult,bool normalInWorldSpace) | |||
{ | |||
//caller already does the filter on the m_closestHitFraction | |||
btAssert(rayResult.m_hitFraction <= m_closestHitFraction); | |||
m_closestHitFraction = rayResult.m_hitFraction; | |||
m_collisionObject = rayResult.m_collisionObject; | |||
if (normalInWorldSpace) | |||
{ | |||
m_hitNormalWorld = rayResult.m_hitNormalLocal; | |||
} else | |||
{ | |||
///need to transform normal into worldspace | |||
m_hitNormalWorld = m_collisionObject->getWorldTransform().getBasis()*rayResult.m_hitNormalLocal; | |||
} | |||
m_hitPointWorld.setInterpolate3(m_rayFromWorld,m_rayToWorld,rayResult.m_hitFraction); | |||
return rayResult.m_hitFraction; | |||
} | |||
}; | |||
struct AllHitsRayResultCallback : public RayResultCallback | |||
{ | |||
AllHitsRayResultCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld) | |||
:m_rayFromWorld(rayFromWorld), | |||
m_rayToWorld(rayToWorld) | |||
{ | |||
} | |||
btAlignedObjectArray<btCollisionObject*> m_collisionObjects; | |||
btVector3 m_rayFromWorld;//used to calculate hitPointWorld from hitFraction | |||
btVector3 m_rayToWorld; | |||
btAlignedObjectArray<btVector3> m_hitNormalWorld; | |||
btAlignedObjectArray<btVector3> m_hitPointWorld; | |||
btAlignedObjectArray<btScalar> m_hitFractions; | |||
virtual btScalar addSingleResult(LocalRayResult& rayResult,bool normalInWorldSpace) | |||
{ | |||
m_collisionObject = rayResult.m_collisionObject; | |||
m_collisionObjects.push_back(rayResult.m_collisionObject); | |||
btVector3 hitNormalWorld; | |||
if (normalInWorldSpace) | |||
{ | |||
hitNormalWorld = rayResult.m_hitNormalLocal; | |||
} else | |||
{ | |||
///need to transform normal into worldspace | |||
hitNormalWorld = m_collisionObject->getWorldTransform().getBasis()*rayResult.m_hitNormalLocal; | |||
} | |||
m_hitNormalWorld.push_back(hitNormalWorld); | |||
btVector3 hitPointWorld; | |||
hitPointWorld.setInterpolate3(m_rayFromWorld,m_rayToWorld,rayResult.m_hitFraction); | |||
m_hitPointWorld.push_back(hitPointWorld); | |||
m_hitFractions.push_back(rayResult.m_hitFraction); | |||
return m_closestHitFraction; | |||
} | |||
}; | |||
struct LocalConvexResult | |||
{ | |||
LocalConvexResult(btCollisionObject* hitCollisionObject, | |||
LocalShapeInfo* localShapeInfo, | |||
const btVector3& hitNormalLocal, | |||
const btVector3& hitPointLocal, | |||
btScalar hitFraction | |||
) | |||
:m_hitCollisionObject(hitCollisionObject), | |||
m_localShapeInfo(localShapeInfo), | |||
m_hitNormalLocal(hitNormalLocal), | |||
m_hitPointLocal(hitPointLocal), | |||
m_hitFraction(hitFraction) | |||
{ | |||
} | |||
btCollisionObject* m_hitCollisionObject; | |||
LocalShapeInfo* m_localShapeInfo; | |||
btVector3 m_hitNormalLocal; | |||
btVector3 m_hitPointLocal; | |||
btScalar m_hitFraction; | |||
}; | |||
///RayResultCallback is used to report new raycast results | |||
struct ConvexResultCallback | |||
{ | |||
btScalar m_closestHitFraction; | |||
short int m_collisionFilterGroup; | |||
short int m_collisionFilterMask; | |||
ConvexResultCallback() | |||
:m_closestHitFraction(btScalar(1.)), | |||
m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), | |||
m_collisionFilterMask(btBroadphaseProxy::AllFilter) | |||
{ | |||
} | |||
virtual ~ConvexResultCallback() | |||
{ | |||
} | |||
bool hasHit() const | |||
{ | |||
return (m_closestHitFraction < btScalar(1.)); | |||
} | |||
virtual bool needsCollision(btBroadphaseProxy* proxy0) const | |||
{ | |||
bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0; | |||
collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask); | |||
return collides; | |||
} | |||
virtual btScalar addSingleResult(LocalConvexResult& convexResult,bool normalInWorldSpace) = 0; | |||
}; | |||
struct ClosestConvexResultCallback : public ConvexResultCallback | |||
{ | |||
ClosestConvexResultCallback(const btVector3& convexFromWorld,const btVector3& convexToWorld) | |||
:m_convexFromWorld(convexFromWorld), | |||
m_convexToWorld(convexToWorld), | |||
m_hitCollisionObject(0) | |||
{ | |||
} | |||
btVector3 m_convexFromWorld;//used to calculate hitPointWorld from hitFraction | |||
btVector3 m_convexToWorld; | |||
btVector3 m_hitNormalWorld; | |||
btVector3 m_hitPointWorld; | |||
btCollisionObject* m_hitCollisionObject; | |||
virtual btScalar addSingleResult(LocalConvexResult& convexResult,bool normalInWorldSpace) | |||
{ | |||
//caller already does the filter on the m_closestHitFraction | |||
btAssert(convexResult.m_hitFraction <= m_closestHitFraction); | |||
m_closestHitFraction = convexResult.m_hitFraction; | |||
m_hitCollisionObject = convexResult.m_hitCollisionObject; | |||
if (normalInWorldSpace) | |||
{ | |||
m_hitNormalWorld = convexResult.m_hitNormalLocal; | |||
} else | |||
{ | |||
///need to transform normal into worldspace | |||
m_hitNormalWorld = m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; | |||
} | |||
m_hitPointWorld = convexResult.m_hitPointLocal; | |||
return convexResult.m_hitFraction; | |||
} | |||
}; | |||
///ContactResultCallback is used to report contact points | |||
struct ContactResultCallback | |||
{ | |||
short int m_collisionFilterGroup; | |||
short int m_collisionFilterMask; | |||
ContactResultCallback() | |||
:m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), | |||
m_collisionFilterMask(btBroadphaseProxy::AllFilter) | |||
{ | |||
} | |||
virtual ~ContactResultCallback() | |||
{ | |||
} | |||
virtual bool needsCollision(btBroadphaseProxy* proxy0) const | |||
{ | |||
bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0; | |||
collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask); | |||
return collides; | |||
} | |||
virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1) = 0; | |||
}; | |||
int getNumCollisionObjects() const | |||
{ | |||
return int(m_collisionObjects.size()); | |||
} | |||
/// rayTest performs a raycast on all objects in the btCollisionWorld, and calls the resultCallback | |||
/// This allows for several queries: first hit, all hits, any hit, dependent on the value returned by the callback. | |||
virtual void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const; | |||
/// convexTest performs a swept convex cast on all objects in the btCollisionWorld, and calls the resultCallback | |||
/// This allows for several queries: first hit, all hits, any hit, dependent on the value return by the callback. | |||
void convexSweepTest (const btConvexShape* castShape, const btTransform& from, const btTransform& to, ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration = btScalar(0.)) const; | |||
///contactTest performs a discrete collision test between colObj 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 contactTest(btCollisionObject* colObj, ContactResultCallback& resultCallback); | |||
///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 contactPairTest(btCollisionObject* colObjA, btCollisionObject* colObjB, ContactResultCallback& resultCallback); | |||
/// rayTestSingle performs a raycast call and calls the resultCallback. It is used internally by rayTest. | |||
/// In a future implementation, we consider moving the ray test as a virtual method in btCollisionShape. | |||
/// This allows more customization. | |||
static void rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans, | |||
btCollisionObject* collisionObject, | |||
const btCollisionShape* collisionShape, | |||
const btTransform& colObjWorldTransform, | |||
RayResultCallback& resultCallback); | |||
/// objectQuerySingle performs a collision detection query and calls the resultCallback. It is used internally by rayTest. | |||
static void objectQuerySingle(const btConvexShape* castShape, const btTransform& rayFromTrans,const btTransform& rayToTrans, | |||
btCollisionObject* collisionObject, | |||
const btCollisionShape* collisionShape, | |||
const btTransform& colObjWorldTransform, | |||
ConvexResultCallback& resultCallback, btScalar allowedPenetration); | |||
virtual void addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup=btBroadphaseProxy::DefaultFilter,short int collisionFilterMask=btBroadphaseProxy::AllFilter); | |||
btCollisionObjectArray& getCollisionObjectArray() | |||
{ | |||
return m_collisionObjects; | |||
} | |||
const btCollisionObjectArray& getCollisionObjectArray() const | |||
{ | |||
return m_collisionObjects; | |||
} | |||
virtual void removeCollisionObject(btCollisionObject* collisionObject); | |||
virtual void performDiscreteCollisionDetection(); | |||
btDispatcherInfo& getDispatchInfo() | |||
{ | |||
return m_dispatchInfo; | |||
} | |||
const btDispatcherInfo& getDispatchInfo() const | |||
{ | |||
return m_dispatchInfo; | |||
} | |||
bool getForceUpdateAllAabbs() const | |||
{ | |||
return m_forceUpdateAllAabbs; | |||
} | |||
void setForceUpdateAllAabbs( bool forceUpdateAllAabbs) | |||
{ | |||
m_forceUpdateAllAabbs = forceUpdateAllAabbs; | |||
} | |||
///Preliminary serialization test for Bullet 2.76. Loading those files requires a separate parser (Bullet/Demos/SerializeDemo) | |||
virtual void serialize(btSerializer* serializer); | |||
}; | |||
#endif //BT_COLLISION_WORLD_H |
@@ -0,0 +1,353 @@ | |||
/* | |||
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 "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
#include "BulletCollision/CollisionShapes/btCompoundShape.h" | |||
#include "BulletCollision/BroadphaseCollision/btDbvt.h" | |||
#include "LinearMath/btIDebugDraw.h" | |||
#include "LinearMath/btAabbUtil2.h" | |||
#include "btManifoldResult.h" | |||
btCompoundCollisionAlgorithm::btCompoundCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped) | |||
:btActivatingCollisionAlgorithm(ci,body0,body1), | |||
m_isSwapped(isSwapped), | |||
m_sharedManifold(ci.m_manifold) | |||
{ | |||
m_ownsManifold = false; | |||
btCollisionObject* colObj = m_isSwapped? body1 : body0; | |||
btAssert (colObj->getCollisionShape()->isCompound()); | |||
btCompoundShape* compoundShape = static_cast<btCompoundShape*>(colObj->getCollisionShape()); | |||
m_compoundShapeRevision = compoundShape->getUpdateRevision(); | |||
preallocateChildAlgorithms(body0,body1); | |||
} | |||
void btCompoundCollisionAlgorithm::preallocateChildAlgorithms(btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
btCollisionObject* colObj = m_isSwapped? body1 : body0; | |||
btCollisionObject* otherObj = m_isSwapped? body0 : body1; | |||
btAssert (colObj->getCollisionShape()->isCompound()); | |||
btCompoundShape* compoundShape = static_cast<btCompoundShape*>(colObj->getCollisionShape()); | |||
int numChildren = compoundShape->getNumChildShapes(); | |||
int i; | |||
m_childCollisionAlgorithms.resize(numChildren); | |||
for (i=0;i<numChildren;i++) | |||
{ | |||
if (compoundShape->getDynamicAabbTree()) | |||
{ | |||
m_childCollisionAlgorithms[i] = 0; | |||
} else | |||
{ | |||
btCollisionShape* tmpShape = colObj->getCollisionShape(); | |||
btCollisionShape* childShape = compoundShape->getChildShape(i); | |||
colObj->internalSetTemporaryCollisionShape( childShape ); | |||
m_childCollisionAlgorithms[i] = m_dispatcher->findAlgorithm(colObj,otherObj,m_sharedManifold); | |||
colObj->internalSetTemporaryCollisionShape( tmpShape ); | |||
} | |||
} | |||
} | |||
void btCompoundCollisionAlgorithm::removeChildAlgorithms() | |||
{ | |||
int numChildren = m_childCollisionAlgorithms.size(); | |||
int i; | |||
for (i=0;i<numChildren;i++) | |||
{ | |||
if (m_childCollisionAlgorithms[i]) | |||
{ | |||
m_childCollisionAlgorithms[i]->~btCollisionAlgorithm(); | |||
m_dispatcher->freeCollisionAlgorithm(m_childCollisionAlgorithms[i]); | |||
} | |||
} | |||
} | |||
btCompoundCollisionAlgorithm::~btCompoundCollisionAlgorithm() | |||
{ | |||
removeChildAlgorithms(); | |||
} | |||
struct btCompoundLeafCallback : btDbvt::ICollide | |||
{ | |||
public: | |||
btCollisionObject* m_compoundColObj; | |||
btCollisionObject* m_otherObj; | |||
btDispatcher* m_dispatcher; | |||
const btDispatcherInfo& m_dispatchInfo; | |||
btManifoldResult* m_resultOut; | |||
btCollisionAlgorithm** m_childCollisionAlgorithms; | |||
btPersistentManifold* m_sharedManifold; | |||
btCompoundLeafCallback (btCollisionObject* compoundObj,btCollisionObject* otherObj,btDispatcher* dispatcher,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut,btCollisionAlgorithm** childCollisionAlgorithms,btPersistentManifold* sharedManifold) | |||
:m_compoundColObj(compoundObj),m_otherObj(otherObj),m_dispatcher(dispatcher),m_dispatchInfo(dispatchInfo),m_resultOut(resultOut), | |||
m_childCollisionAlgorithms(childCollisionAlgorithms), | |||
m_sharedManifold(sharedManifold) | |||
{ | |||
} | |||
void ProcessChildShape(btCollisionShape* childShape,int index) | |||
{ | |||
btAssert(index>=0); | |||
btCompoundShape* compoundShape = static_cast<btCompoundShape*>(m_compoundColObj->getCollisionShape()); | |||
btAssert(index<compoundShape->getNumChildShapes()); | |||
//backup | |||
btTransform orgTrans = m_compoundColObj->getWorldTransform(); | |||
btTransform orgInterpolationTrans = m_compoundColObj->getInterpolationWorldTransform(); | |||
const btTransform& childTrans = compoundShape->getChildTransform(index); | |||
btTransform newChildWorldTrans = orgTrans*childTrans ; | |||
//perform an AABB check first | |||
btVector3 aabbMin0,aabbMax0,aabbMin1,aabbMax1; | |||
childShape->getAabb(newChildWorldTrans,aabbMin0,aabbMax0); | |||
m_otherObj->getCollisionShape()->getAabb(m_otherObj->getWorldTransform(),aabbMin1,aabbMax1); | |||
if (TestAabbAgainstAabb2(aabbMin0,aabbMax0,aabbMin1,aabbMax1)) | |||
{ | |||
m_compoundColObj->setWorldTransform( newChildWorldTrans); | |||
m_compoundColObj->setInterpolationWorldTransform(newChildWorldTrans); | |||
//the contactpoint is still projected back using the original inverted worldtrans | |||
btCollisionShape* tmpShape = m_compoundColObj->getCollisionShape(); | |||
m_compoundColObj->internalSetTemporaryCollisionShape( childShape ); | |||
if (!m_childCollisionAlgorithms[index]) | |||
m_childCollisionAlgorithms[index] = m_dispatcher->findAlgorithm(m_compoundColObj,m_otherObj,m_sharedManifold); | |||
///detect swapping case | |||
if (m_resultOut->getBody0Internal() == m_compoundColObj) | |||
{ | |||
m_resultOut->setShapeIdentifiersA(-1,index); | |||
} else | |||
{ | |||
m_resultOut->setShapeIdentifiersB(-1,index); | |||
} | |||
m_childCollisionAlgorithms[index]->processCollision(m_compoundColObj,m_otherObj,m_dispatchInfo,m_resultOut); | |||
if (m_dispatchInfo.m_debugDraw && (m_dispatchInfo.m_debugDraw->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) | |||
{ | |||
btVector3 worldAabbMin,worldAabbMax; | |||
m_dispatchInfo.m_debugDraw->drawAabb(aabbMin0,aabbMax0,btVector3(1,1,1)); | |||
m_dispatchInfo.m_debugDraw->drawAabb(aabbMin1,aabbMax1,btVector3(1,1,1)); | |||
} | |||
//revert back transform | |||
m_compoundColObj->internalSetTemporaryCollisionShape( tmpShape); | |||
m_compoundColObj->setWorldTransform( orgTrans ); | |||
m_compoundColObj->setInterpolationWorldTransform(orgInterpolationTrans); | |||
} | |||
} | |||
void Process(const btDbvtNode* leaf) | |||
{ | |||
int index = leaf->dataAsInt; | |||
btCompoundShape* compoundShape = static_cast<btCompoundShape*>(m_compoundColObj->getCollisionShape()); | |||
btCollisionShape* childShape = compoundShape->getChildShape(index); | |||
if (m_dispatchInfo.m_debugDraw && (m_dispatchInfo.m_debugDraw->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) | |||
{ | |||
btVector3 worldAabbMin,worldAabbMax; | |||
btTransform orgTrans = m_compoundColObj->getWorldTransform(); | |||
btTransformAabb(leaf->volume.Mins(),leaf->volume.Maxs(),0.,orgTrans,worldAabbMin,worldAabbMax); | |||
m_dispatchInfo.m_debugDraw->drawAabb(worldAabbMin,worldAabbMax,btVector3(1,0,0)); | |||
} | |||
ProcessChildShape(childShape,index); | |||
} | |||
}; | |||
void btCompoundCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
btCollisionObject* colObj = m_isSwapped? body1 : body0; | |||
btCollisionObject* otherObj = m_isSwapped? body0 : body1; | |||
btAssert (colObj->getCollisionShape()->isCompound()); | |||
btCompoundShape* compoundShape = static_cast<btCompoundShape*>(colObj->getCollisionShape()); | |||
///btCompoundShape might have changed: | |||
////make sure the internal child collision algorithm caches are still valid | |||
if (compoundShape->getUpdateRevision() != m_compoundShapeRevision) | |||
{ | |||
///clear and update all | |||
removeChildAlgorithms(); | |||
preallocateChildAlgorithms(body0,body1); | |||
} | |||
btDbvt* tree = compoundShape->getDynamicAabbTree(); | |||
//use a dynamic aabb tree to cull potential child-overlaps | |||
btCompoundLeafCallback callback(colObj,otherObj,m_dispatcher,dispatchInfo,resultOut,&m_childCollisionAlgorithms[0],m_sharedManifold); | |||
///we need to refresh all contact manifolds | |||
///note that we should actually recursively traverse all children, btCompoundShape can nested more then 1 level deep | |||
///so we should add a 'refreshManifolds' in the btCollisionAlgorithm | |||
{ | |||
int i; | |||
btManifoldArray manifoldArray; | |||
for (i=0;i<m_childCollisionAlgorithms.size();i++) | |||
{ | |||
if (m_childCollisionAlgorithms[i]) | |||
{ | |||
m_childCollisionAlgorithms[i]->getAllContactManifolds(manifoldArray); | |||
for (int m=0;m<manifoldArray.size();m++) | |||
{ | |||
if (manifoldArray[m]->getNumContacts()) | |||
{ | |||
resultOut->setPersistentManifold(manifoldArray[m]); | |||
resultOut->refreshContactPoints(); | |||
resultOut->setPersistentManifold(0);//??necessary? | |||
} | |||
} | |||
manifoldArray.resize(0); | |||
} | |||
} | |||
} | |||
if (tree) | |||
{ | |||
btVector3 localAabbMin,localAabbMax; | |||
btTransform otherInCompoundSpace; | |||
otherInCompoundSpace = colObj->getWorldTransform().inverse() * otherObj->getWorldTransform(); | |||
otherObj->getCollisionShape()->getAabb(otherInCompoundSpace,localAabbMin,localAabbMax); | |||
const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); | |||
//process all children, that overlap with the given AABB bounds | |||
tree->collideTV(tree->m_root,bounds,callback); | |||
} else | |||
{ | |||
//iterate over all children, perform an AABB check inside ProcessChildShape | |||
int numChildren = m_childCollisionAlgorithms.size(); | |||
int i; | |||
for (i=0;i<numChildren;i++) | |||
{ | |||
callback.ProcessChildShape(compoundShape->getChildShape(i),i); | |||
} | |||
} | |||
{ | |||
//iterate over all children, perform an AABB check inside ProcessChildShape | |||
int numChildren = m_childCollisionAlgorithms.size(); | |||
int i; | |||
btManifoldArray manifoldArray; | |||
btCollisionShape* childShape = 0; | |||
btTransform orgTrans; | |||
btTransform orgInterpolationTrans; | |||
btTransform newChildWorldTrans; | |||
btVector3 aabbMin0,aabbMax0,aabbMin1,aabbMax1; | |||
for (i=0;i<numChildren;i++) | |||
{ | |||
if (m_childCollisionAlgorithms[i]) | |||
{ | |||
childShape = compoundShape->getChildShape(i); | |||
//if not longer overlapping, remove the algorithm | |||
orgTrans = colObj->getWorldTransform(); | |||
orgInterpolationTrans = colObj->getInterpolationWorldTransform(); | |||
const btTransform& childTrans = compoundShape->getChildTransform(i); | |||
newChildWorldTrans = orgTrans*childTrans ; | |||
//perform an AABB check first | |||
childShape->getAabb(newChildWorldTrans,aabbMin0,aabbMax0); | |||
otherObj->getCollisionShape()->getAabb(otherObj->getWorldTransform(),aabbMin1,aabbMax1); | |||
if (!TestAabbAgainstAabb2(aabbMin0,aabbMax0,aabbMin1,aabbMax1)) | |||
{ | |||
m_childCollisionAlgorithms[i]->~btCollisionAlgorithm(); | |||
m_dispatcher->freeCollisionAlgorithm(m_childCollisionAlgorithms[i]); | |||
m_childCollisionAlgorithms[i] = 0; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
btScalar btCompoundCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
btCollisionObject* colObj = m_isSwapped? body1 : body0; | |||
btCollisionObject* otherObj = m_isSwapped? body0 : body1; | |||
btAssert (colObj->getCollisionShape()->isCompound()); | |||
btCompoundShape* compoundShape = static_cast<btCompoundShape*>(colObj->getCollisionShape()); | |||
//We will use the OptimizedBVH, AABB tree to cull potential child-overlaps | |||
//If both proxies are Compound, we will deal with that directly, by performing sequential/parallel tree traversals | |||
//given Proxy0 and Proxy1, if both have a tree, Tree0 and Tree1, this means: | |||
//determine overlapping nodes of Proxy1 using Proxy0 AABB against Tree1 | |||
//then use each overlapping node AABB against Tree0 | |||
//and vise versa. | |||
btScalar hitFraction = btScalar(1.); | |||
int numChildren = m_childCollisionAlgorithms.size(); | |||
int i; | |||
btTransform orgTrans; | |||
btScalar frac; | |||
for (i=0;i<numChildren;i++) | |||
{ | |||
//temporarily exchange parent btCollisionShape with childShape, and recurse | |||
btCollisionShape* childShape = compoundShape->getChildShape(i); | |||
//backup | |||
orgTrans = colObj->getWorldTransform(); | |||
const btTransform& childTrans = compoundShape->getChildTransform(i); | |||
//btTransform newChildWorldTrans = orgTrans*childTrans ; | |||
colObj->setWorldTransform( orgTrans*childTrans ); | |||
btCollisionShape* tmpShape = colObj->getCollisionShape(); | |||
colObj->internalSetTemporaryCollisionShape( childShape ); | |||
frac = m_childCollisionAlgorithms[i]->calculateTimeOfImpact(colObj,otherObj,dispatchInfo,resultOut); | |||
if (frac<hitFraction) | |||
{ | |||
hitFraction = frac; | |||
} | |||
//revert back | |||
colObj->internalSetTemporaryCollisionShape( tmpShape); | |||
colObj->setWorldTransform( orgTrans); | |||
} | |||
return hitFraction; | |||
} | |||
@@ -0,0 +1,86 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_COMPOUND_COLLISION_ALGORITHM_H | |||
#define BT_COMPOUND_COLLISION_ALGORITHM_H | |||
#include "btActivatingCollisionAlgorithm.h" | |||
#include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
class btDispatcher; | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "btCollisionCreateFunc.h" | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
class btDispatcher; | |||
class btCollisionObject; | |||
/// btCompoundCollisionAlgorithm supports collision between CompoundCollisionShapes and other collision shapes | |||
class btCompoundCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
{ | |||
btAlignedObjectArray<btCollisionAlgorithm*> m_childCollisionAlgorithms; | |||
bool m_isSwapped; | |||
class btPersistentManifold* m_sharedManifold; | |||
bool m_ownsManifold; | |||
int m_compoundShapeRevision;//to keep track of changes, so that childAlgorithm array can be updated | |||
void removeChildAlgorithms(); | |||
void preallocateChildAlgorithms(btCollisionObject* body0,btCollisionObject* body1); | |||
public: | |||
btCompoundCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); | |||
virtual ~btCompoundCollisionAlgorithm(); | |||
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
{ | |||
int i; | |||
for (i=0;i<m_childCollisionAlgorithms.size();i++) | |||
{ | |||
if (m_childCollisionAlgorithms[i]) | |||
m_childCollisionAlgorithms[i]->getAllContactManifolds(manifoldArray); | |||
} | |||
} | |||
struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btCompoundCollisionAlgorithm)); | |||
return new(mem) btCompoundCollisionAlgorithm(ci,body0,body1,false); | |||
} | |||
}; | |||
struct SwappedCreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btCompoundCollisionAlgorithm)); | |||
return new(mem) btCompoundCollisionAlgorithm(ci,body0,body1,true); | |||
} | |||
}; | |||
}; | |||
#endif //BT_COMPOUND_COLLISION_ALGORITHM_H |
@@ -0,0 +1,247 @@ | |||
/* | |||
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 "btConvex2dConvex2dAlgorithm.h" | |||
//#include <stdio.h> | |||
#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
#include "BulletCollision/CollisionShapes/btConvexShape.h" | |||
#include "BulletCollision/CollisionShapes/btCapsuleShape.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
#include "BulletCollision/CollisionShapes/btBoxShape.h" | |||
#include "BulletCollision/CollisionDispatch/btManifoldResult.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" | |||
#include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" | |||
btConvex2dConvex2dAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) | |||
{ | |||
m_numPerturbationIterations = 0; | |||
m_minimumPointsPerturbationThreshold = 3; | |||
m_simplexSolver = simplexSolver; | |||
m_pdSolver = pdSolver; | |||
} | |||
btConvex2dConvex2dAlgorithm::CreateFunc::~CreateFunc() | |||
{ | |||
} | |||
btConvex2dConvex2dAlgorithm::btConvex2dConvex2dAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold) | |||
: btActivatingCollisionAlgorithm(ci,body0,body1), | |||
m_simplexSolver(simplexSolver), | |||
m_pdSolver(pdSolver), | |||
m_ownManifold (false), | |||
m_manifoldPtr(mf), | |||
m_lowLevelOfDetail(false), | |||
m_numPerturbationIterations(numPerturbationIterations), | |||
m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold) | |||
{ | |||
(void)body0; | |||
(void)body1; | |||
} | |||
btConvex2dConvex2dAlgorithm::~btConvex2dConvex2dAlgorithm() | |||
{ | |||
if (m_ownManifold) | |||
{ | |||
if (m_manifoldPtr) | |||
m_dispatcher->releaseManifold(m_manifoldPtr); | |||
} | |||
} | |||
void btConvex2dConvex2dAlgorithm ::setLowLevelOfDetail(bool useLowLevel) | |||
{ | |||
m_lowLevelOfDetail = useLowLevel; | |||
} | |||
extern btScalar gContactBreakingThreshold; | |||
// | |||
// Convex-Convex collision algorithm | |||
// | |||
void btConvex2dConvex2dAlgorithm ::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
if (!m_manifoldPtr) | |||
{ | |||
//swapped? | |||
m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1); | |||
m_ownManifold = true; | |||
} | |||
resultOut->setPersistentManifold(m_manifoldPtr); | |||
//comment-out next line to test multi-contact generation | |||
//resultOut->getPersistentManifold()->clearManifold(); | |||
btConvexShape* min0 = static_cast<btConvexShape*>(body0->getCollisionShape()); | |||
btConvexShape* min1 = static_cast<btConvexShape*>(body1->getCollisionShape()); | |||
btVector3 normalOnB; | |||
btVector3 pointOnBWorld; | |||
{ | |||
btGjkPairDetector::ClosestPointInput input; | |||
btGjkPairDetector gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver); | |||
//TODO: if (dispatchInfo.m_useContinuous) | |||
gjkPairDetector.setMinkowskiA(min0); | |||
gjkPairDetector.setMinkowskiB(min1); | |||
{ | |||
input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold(); | |||
input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared; | |||
} | |||
input.m_stackAlloc = dispatchInfo.m_stackAllocator; | |||
input.m_transformA = body0->getWorldTransform(); | |||
input.m_transformB = body1->getWorldTransform(); | |||
gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); | |||
btVector3 v0,v1; | |||
btVector3 sepNormalWorldSpace; | |||
} | |||
if (m_ownManifold) | |||
{ | |||
resultOut->refreshContactPoints(); | |||
} | |||
} | |||
btScalar btConvex2dConvex2dAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
(void)resultOut; | |||
(void)dispatchInfo; | |||
///Rather then checking ALL pairs, only calculate TOI when motion exceeds threshold | |||
///Linear motion for one of objects needs to exceed m_ccdSquareMotionThreshold | |||
///col0->m_worldTransform, | |||
btScalar resultFraction = btScalar(1.); | |||
btScalar squareMot0 = (col0->getInterpolationWorldTransform().getOrigin() - col0->getWorldTransform().getOrigin()).length2(); | |||
btScalar squareMot1 = (col1->getInterpolationWorldTransform().getOrigin() - col1->getWorldTransform().getOrigin()).length2(); | |||
if (squareMot0 < col0->getCcdSquareMotionThreshold() && | |||
squareMot1 < col1->getCcdSquareMotionThreshold()) | |||
return resultFraction; | |||
//An adhoc way of testing the Continuous Collision Detection algorithms | |||
//One object is approximated as a sphere, to simplify things | |||
//Starting in penetration should report no time of impact | |||
//For proper CCD, better accuracy and handling of 'allowed' penetration should be added | |||
//also the mainloop of the physics should have a kind of toi queue (something like Brian Mirtich's application of Timewarp for Rigidbodies) | |||
/// Convex0 against sphere for Convex1 | |||
{ | |||
btConvexShape* convex0 = static_cast<btConvexShape*>(col0->getCollisionShape()); | |||
btSphereShape sphere1(col1->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation | |||
btConvexCast::CastResult result; | |||
btVoronoiSimplexSolver voronoiSimplex; | |||
//SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); | |||
///Simplification, one object is simplified as a sphere | |||
btGjkConvexCast ccd1( convex0 ,&sphere1,&voronoiSimplex); | |||
//ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); | |||
if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), | |||
col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) | |||
{ | |||
//store result.m_fraction in both bodies | |||
if (col0->getHitFraction()> result.m_fraction) | |||
col0->setHitFraction( result.m_fraction ); | |||
if (col1->getHitFraction() > result.m_fraction) | |||
col1->setHitFraction( result.m_fraction); | |||
if (resultFraction > result.m_fraction) | |||
resultFraction = result.m_fraction; | |||
} | |||
} | |||
/// Sphere (for convex0) against Convex1 | |||
{ | |||
btConvexShape* convex1 = static_cast<btConvexShape*>(col1->getCollisionShape()); | |||
btSphereShape sphere0(col0->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation | |||
btConvexCast::CastResult result; | |||
btVoronoiSimplexSolver voronoiSimplex; | |||
//SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); | |||
///Simplification, one object is simplified as a sphere | |||
btGjkConvexCast ccd1(&sphere0,convex1,&voronoiSimplex); | |||
//ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); | |||
if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), | |||
col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) | |||
{ | |||
//store result.m_fraction in both bodies | |||
if (col0->getHitFraction() > result.m_fraction) | |||
col0->setHitFraction( result.m_fraction); | |||
if (col1->getHitFraction() > result.m_fraction) | |||
col1->setHitFraction( result.m_fraction); | |||
if (resultFraction > result.m_fraction) | |||
resultFraction = result.m_fraction; | |||
} | |||
} | |||
return resultFraction; | |||
} | |||
@@ -0,0 +1,95 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_CONVEX_2D_CONVEX_2D_ALGORITHM_H | |||
#define BT_CONVEX_2D_CONVEX_2D_ALGORITHM_H | |||
#include "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
#include "LinearMath/btTransformUtil.h" //for btConvexSeparatingDistanceUtil | |||
class btConvexPenetrationDepthSolver; | |||
///The convex2dConvex2dAlgorithm collision algorithm support 2d collision detection for btConvex2dShape | |||
///Currently it requires the btMinkowskiPenetrationDepthSolver, it has support for 2d penetration depth computation | |||
class btConvex2dConvex2dAlgorithm : public btActivatingCollisionAlgorithm | |||
{ | |||
btSimplexSolverInterface* m_simplexSolver; | |||
btConvexPenetrationDepthSolver* m_pdSolver; | |||
bool m_ownManifold; | |||
btPersistentManifold* m_manifoldPtr; | |||
bool m_lowLevelOfDetail; | |||
int m_numPerturbationIterations; | |||
int m_minimumPointsPerturbationThreshold; | |||
public: | |||
btConvex2dConvex2dAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold); | |||
virtual ~btConvex2dConvex2dAlgorithm(); | |||
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
{ | |||
///should we use m_ownManifold to avoid adding duplicates? | |||
if (m_manifoldPtr && m_ownManifold) | |||
manifoldArray.push_back(m_manifoldPtr); | |||
} | |||
void setLowLevelOfDetail(bool useLowLevel); | |||
const btPersistentManifold* getManifold() | |||
{ | |||
return m_manifoldPtr; | |||
} | |||
struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
btConvexPenetrationDepthSolver* m_pdSolver; | |||
btSimplexSolverInterface* m_simplexSolver; | |||
int m_numPerturbationIterations; | |||
int m_minimumPointsPerturbationThreshold; | |||
CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver); | |||
virtual ~CreateFunc(); | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvex2dConvex2dAlgorithm)); | |||
return new(mem) btConvex2dConvex2dAlgorithm(ci.m_manifold,ci,body0,body1,m_simplexSolver,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); | |||
} | |||
}; | |||
}; | |||
#endif //BT_CONVEX_2D_CONVEX_2D_ALGORITHM_H |
@@ -0,0 +1,312 @@ | |||
/* | |||
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 "btConvexConcaveCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
#include "BulletCollision/CollisionShapes/btMultiSphereShape.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "BulletCollision/CollisionShapes/btConcaveShape.h" | |||
#include "BulletCollision/CollisionDispatch/btManifoldResult.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" | |||
#include "BulletCollision/CollisionShapes/btTriangleShape.h" | |||
#include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
#include "LinearMath/btIDebugDraw.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" | |||
btConvexConcaveCollisionAlgorithm::btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1,bool isSwapped) | |||
: btActivatingCollisionAlgorithm(ci,body0,body1), | |||
m_isSwapped(isSwapped), | |||
m_btConvexTriangleCallback(ci.m_dispatcher1,body0,body1,isSwapped) | |||
{ | |||
} | |||
btConvexConcaveCollisionAlgorithm::~btConvexConcaveCollisionAlgorithm() | |||
{ | |||
} | |||
void btConvexConcaveCollisionAlgorithm::getAllContactManifolds(btManifoldArray& manifoldArray) | |||
{ | |||
if (m_btConvexTriangleCallback.m_manifoldPtr) | |||
{ | |||
manifoldArray.push_back(m_btConvexTriangleCallback.m_manifoldPtr); | |||
} | |||
} | |||
btConvexTriangleCallback::btConvexTriangleCallback(btDispatcher* dispatcher,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped): | |||
m_dispatcher(dispatcher), | |||
m_dispatchInfoPtr(0) | |||
{ | |||
m_convexBody = isSwapped? body1:body0; | |||
m_triBody = isSwapped? body0:body1; | |||
// | |||
// create the manifold from the dispatcher 'manifold pool' | |||
// | |||
m_manifoldPtr = m_dispatcher->getNewManifold(m_convexBody,m_triBody); | |||
clearCache(); | |||
} | |||
btConvexTriangleCallback::~btConvexTriangleCallback() | |||
{ | |||
clearCache(); | |||
m_dispatcher->releaseManifold( m_manifoldPtr ); | |||
} | |||
void btConvexTriangleCallback::clearCache() | |||
{ | |||
m_dispatcher->clearManifold(m_manifoldPtr); | |||
} | |||
void btConvexTriangleCallback::processTriangle(btVector3* triangle,int partId, int triangleIndex) | |||
{ | |||
//just for debugging purposes | |||
//printf("triangle %d",m_triangleCount++); | |||
//aabb filter is already applied! | |||
btCollisionAlgorithmConstructionInfo ci; | |||
ci.m_dispatcher1 = m_dispatcher; | |||
btCollisionObject* ob = static_cast<btCollisionObject*>(m_triBody); | |||
#if 0 | |||
///debug drawing of the overlapping triangles | |||
if (m_dispatchInfoPtr && m_dispatchInfoPtr->m_debugDraw && (m_dispatchInfoPtr->m_debugDraw->getDebugMode() &btIDebugDraw::DBG_DrawWireframe )) | |||
{ | |||
btVector3 color(1,1,0); | |||
btTransform& tr = ob->getWorldTransform(); | |||
m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[0]),tr(triangle[1]),color); | |||
m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[1]),tr(triangle[2]),color); | |||
m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[2]),tr(triangle[0]),color); | |||
} | |||
#endif | |||
if (m_convexBody->getCollisionShape()->isConvex()) | |||
{ | |||
btTriangleShape tm(triangle[0],triangle[1],triangle[2]); | |||
tm.setMargin(m_collisionMarginTriangle); | |||
btCollisionShape* tmpShape = ob->getCollisionShape(); | |||
ob->internalSetTemporaryCollisionShape( &tm ); | |||
btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBody,m_triBody,m_manifoldPtr); | |||
if (m_resultOut->getBody0Internal() == m_triBody) | |||
{ | |||
m_resultOut->setShapeIdentifiersA(partId,triangleIndex); | |||
} | |||
else | |||
{ | |||
m_resultOut->setShapeIdentifiersB(partId,triangleIndex); | |||
} | |||
colAlgo->processCollision(m_convexBody,m_triBody,*m_dispatchInfoPtr,m_resultOut); | |||
colAlgo->~btCollisionAlgorithm(); | |||
ci.m_dispatcher1->freeCollisionAlgorithm(colAlgo); | |||
ob->internalSetTemporaryCollisionShape( tmpShape); | |||
} | |||
} | |||
void btConvexTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTriangle,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
m_dispatchInfoPtr = &dispatchInfo; | |||
m_collisionMarginTriangle = collisionMarginTriangle; | |||
m_resultOut = resultOut; | |||
//recalc aabbs | |||
btTransform convexInTriangleSpace; | |||
convexInTriangleSpace = m_triBody->getWorldTransform().inverse() * m_convexBody->getWorldTransform(); | |||
btCollisionShape* convexShape = static_cast<btCollisionShape*>(m_convexBody->getCollisionShape()); | |||
//CollisionShape* triangleShape = static_cast<btCollisionShape*>(triBody->m_collisionShape); | |||
convexShape->getAabb(convexInTriangleSpace,m_aabbMin,m_aabbMax); | |||
btScalar extraMargin = collisionMarginTriangle; | |||
btVector3 extra(extraMargin,extraMargin,extraMargin); | |||
m_aabbMax += extra; | |||
m_aabbMin -= extra; | |||
} | |||
void btConvexConcaveCollisionAlgorithm::clearCache() | |||
{ | |||
m_btConvexTriangleCallback.clearCache(); | |||
} | |||
void btConvexConcaveCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
btCollisionObject* convexBody = m_isSwapped ? body1 : body0; | |||
btCollisionObject* triBody = m_isSwapped ? body0 : body1; | |||
if (triBody->getCollisionShape()->isConcave()) | |||
{ | |||
btCollisionObject* triOb = triBody; | |||
btConcaveShape* concaveShape = static_cast<btConcaveShape*>( triOb->getCollisionShape()); | |||
if (convexBody->getCollisionShape()->isConvex()) | |||
{ | |||
btScalar collisionMarginTriangle = concaveShape->getMargin(); | |||
resultOut->setPersistentManifold(m_btConvexTriangleCallback.m_manifoldPtr); | |||
m_btConvexTriangleCallback.setTimeStepAndCounters(collisionMarginTriangle,dispatchInfo,resultOut); | |||
//Disable persistency. previously, some older algorithm calculated all contacts in one go, so you can clear it here. | |||
//m_dispatcher->clearManifold(m_btConvexTriangleCallback.m_manifoldPtr); | |||
m_btConvexTriangleCallback.m_manifoldPtr->setBodies(convexBody,triBody); | |||
concaveShape->processAllTriangles( &m_btConvexTriangleCallback,m_btConvexTriangleCallback.getAabbMin(),m_btConvexTriangleCallback.getAabbMax()); | |||
resultOut->refreshContactPoints(); | |||
} | |||
} | |||
} | |||
btScalar btConvexConcaveCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
(void)resultOut; | |||
(void)dispatchInfo; | |||
btCollisionObject* convexbody = m_isSwapped ? body1 : body0; | |||
btCollisionObject* triBody = m_isSwapped ? body0 : body1; | |||
//quick approximation using raycast, todo: hook up to the continuous collision detection (one of the btConvexCast) | |||
//only perform CCD above a certain threshold, this prevents blocking on the long run | |||
//because object in a blocked ccd state (hitfraction<1) get their linear velocity halved each frame... | |||
btScalar squareMot0 = (convexbody->getInterpolationWorldTransform().getOrigin() - convexbody->getWorldTransform().getOrigin()).length2(); | |||
if (squareMot0 < convexbody->getCcdSquareMotionThreshold()) | |||
{ | |||
return btScalar(1.); | |||
} | |||
//const btVector3& from = convexbody->m_worldTransform.getOrigin(); | |||
//btVector3 to = convexbody->m_interpolationWorldTransform.getOrigin(); | |||
//todo: only do if the motion exceeds the 'radius' | |||
btTransform triInv = triBody->getWorldTransform().inverse(); | |||
btTransform convexFromLocal = triInv * convexbody->getWorldTransform(); | |||
btTransform convexToLocal = triInv * convexbody->getInterpolationWorldTransform(); | |||
struct LocalTriangleSphereCastCallback : public btTriangleCallback | |||
{ | |||
btTransform m_ccdSphereFromTrans; | |||
btTransform m_ccdSphereToTrans; | |||
btTransform m_meshTransform; | |||
btScalar m_ccdSphereRadius; | |||
btScalar m_hitFraction; | |||
LocalTriangleSphereCastCallback(const btTransform& from,const btTransform& to,btScalar ccdSphereRadius,btScalar hitFraction) | |||
:m_ccdSphereFromTrans(from), | |||
m_ccdSphereToTrans(to), | |||
m_ccdSphereRadius(ccdSphereRadius), | |||
m_hitFraction(hitFraction) | |||
{ | |||
} | |||
virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) | |||
{ | |||
(void)partId; | |||
(void)triangleIndex; | |||
//do a swept sphere for now | |||
btTransform ident; | |||
ident.setIdentity(); | |||
btConvexCast::CastResult castResult; | |||
castResult.m_fraction = m_hitFraction; | |||
btSphereShape pointShape(m_ccdSphereRadius); | |||
btTriangleShape triShape(triangle[0],triangle[1],triangle[2]); | |||
btVoronoiSimplexSolver simplexSolver; | |||
btSubsimplexConvexCast convexCaster(&pointShape,&triShape,&simplexSolver); | |||
//GjkConvexCast convexCaster(&pointShape,convexShape,&simplexSolver); | |||
//ContinuousConvexCollision convexCaster(&pointShape,convexShape,&simplexSolver,0); | |||
//local space? | |||
if (convexCaster.calcTimeOfImpact(m_ccdSphereFromTrans,m_ccdSphereToTrans, | |||
ident,ident,castResult)) | |||
{ | |||
if (m_hitFraction > castResult.m_fraction) | |||
m_hitFraction = castResult.m_fraction; | |||
} | |||
} | |||
}; | |||
if (triBody->getCollisionShape()->isConcave()) | |||
{ | |||
btVector3 rayAabbMin = convexFromLocal.getOrigin(); | |||
rayAabbMin.setMin(convexToLocal.getOrigin()); | |||
btVector3 rayAabbMax = convexFromLocal.getOrigin(); | |||
rayAabbMax.setMax(convexToLocal.getOrigin()); | |||
btScalar ccdRadius0 = convexbody->getCcdSweptSphereRadius(); | |||
rayAabbMin -= btVector3(ccdRadius0,ccdRadius0,ccdRadius0); | |||
rayAabbMax += btVector3(ccdRadius0,ccdRadius0,ccdRadius0); | |||
btScalar curHitFraction = btScalar(1.); //is this available? | |||
LocalTriangleSphereCastCallback raycastCallback(convexFromLocal,convexToLocal, | |||
convexbody->getCcdSweptSphereRadius(),curHitFraction); | |||
raycastCallback.m_hitFraction = convexbody->getHitFraction(); | |||
btCollisionObject* concavebody = triBody; | |||
btConcaveShape* triangleMesh = (btConcaveShape*) concavebody->getCollisionShape(); | |||
if (triangleMesh) | |||
{ | |||
triangleMesh->processAllTriangles(&raycastCallback,rayAabbMin,rayAabbMax); | |||
} | |||
if (raycastCallback.m_hitFraction < convexbody->getHitFraction()) | |||
{ | |||
convexbody->setHitFraction( raycastCallback.m_hitFraction); | |||
return raycastCallback.m_hitFraction; | |||
} | |||
} | |||
return btScalar(1.); | |||
} |
@@ -0,0 +1,116 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_CONVEX_CONCAVE_COLLISION_ALGORITHM_H | |||
#define BT_CONVEX_CONCAVE_COLLISION_ALGORITHM_H | |||
#include "btActivatingCollisionAlgorithm.h" | |||
#include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" | |||
#include "BulletCollision/CollisionShapes/btTriangleCallback.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
class btDispatcher; | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "btCollisionCreateFunc.h" | |||
///For each triangle in the concave mesh that overlaps with the AABB of a convex (m_convexProxy), processTriangle is called. | |||
class btConvexTriangleCallback : public btTriangleCallback | |||
{ | |||
btCollisionObject* m_convexBody; | |||
btCollisionObject* m_triBody; | |||
btVector3 m_aabbMin; | |||
btVector3 m_aabbMax ; | |||
btManifoldResult* m_resultOut; | |||
btDispatcher* m_dispatcher; | |||
const btDispatcherInfo* m_dispatchInfoPtr; | |||
btScalar m_collisionMarginTriangle; | |||
public: | |||
int m_triangleCount; | |||
btPersistentManifold* m_manifoldPtr; | |||
btConvexTriangleCallback(btDispatcher* dispatcher,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); | |||
void setTimeStepAndCounters(btScalar collisionMarginTriangle,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual ~btConvexTriangleCallback(); | |||
virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex); | |||
void clearCache(); | |||
SIMD_FORCE_INLINE const btVector3& getAabbMin() const | |||
{ | |||
return m_aabbMin; | |||
} | |||
SIMD_FORCE_INLINE const btVector3& getAabbMax() const | |||
{ | |||
return m_aabbMax; | |||
} | |||
}; | |||
/// btConvexConcaveCollisionAlgorithm supports collision between convex shapes and (concave) trianges meshes. | |||
class btConvexConcaveCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
{ | |||
bool m_isSwapped; | |||
btConvexTriangleCallback m_btConvexTriangleCallback; | |||
public: | |||
btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); | |||
virtual ~btConvexConcaveCollisionAlgorithm(); | |||
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual void getAllContactManifolds(btManifoldArray& manifoldArray); | |||
void clearCache(); | |||
struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConcaveCollisionAlgorithm)); | |||
return new(mem) btConvexConcaveCollisionAlgorithm(ci,body0,body1,false); | |||
} | |||
}; | |||
struct SwappedCreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConcaveCollisionAlgorithm)); | |||
return new(mem) btConvexConcaveCollisionAlgorithm(ci,body0,body1,true); | |||
} | |||
}; | |||
}; | |||
#endif //BT_CONVEX_CONCAVE_COLLISION_ALGORITHM_H |
@@ -0,0 +1,739 @@ | |||
/* | |||
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. | |||
*/ | |||
///Specialized capsule-capsule collision algorithm has been added for Bullet 2.75 release to increase ragdoll performance | |||
///If you experience problems with capsule-capsule collision, try to define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER and report it in the Bullet forums | |||
///with reproduction case | |||
//define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER 1 | |||
//#define ZERO_MARGIN | |||
#include "btConvexConvexAlgorithm.h" | |||
//#include <stdio.h> | |||
#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
#include "BulletCollision/CollisionShapes/btConvexShape.h" | |||
#include "BulletCollision/CollisionShapes/btCapsuleShape.h" | |||
#include "BulletCollision/CollisionShapes/btTriangleShape.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
#include "BulletCollision/CollisionShapes/btBoxShape.h" | |||
#include "BulletCollision/CollisionDispatch/btManifoldResult.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" | |||
#include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h" | |||
/////////// | |||
static SIMD_FORCE_INLINE void segmentsClosestPoints( | |||
btVector3& ptsVector, | |||
btVector3& offsetA, | |||
btVector3& offsetB, | |||
btScalar& tA, btScalar& tB, | |||
const btVector3& translation, | |||
const btVector3& dirA, btScalar hlenA, | |||
const btVector3& dirB, btScalar hlenB ) | |||
{ | |||
// compute the parameters of the closest points on each line segment | |||
btScalar dirA_dot_dirB = btDot(dirA,dirB); | |||
btScalar dirA_dot_trans = btDot(dirA,translation); | |||
btScalar dirB_dot_trans = btDot(dirB,translation); | |||
btScalar denom = 1.0f - dirA_dot_dirB * dirA_dot_dirB; | |||
if ( denom == 0.0f ) { | |||
tA = 0.0f; | |||
} else { | |||
tA = ( dirA_dot_trans - dirB_dot_trans * dirA_dot_dirB ) / denom; | |||
if ( tA < -hlenA ) | |||
tA = -hlenA; | |||
else if ( tA > hlenA ) | |||
tA = hlenA; | |||
} | |||
tB = tA * dirA_dot_dirB - dirB_dot_trans; | |||
if ( tB < -hlenB ) { | |||
tB = -hlenB; | |||
tA = tB * dirA_dot_dirB + dirA_dot_trans; | |||
if ( tA < -hlenA ) | |||
tA = -hlenA; | |||
else if ( tA > hlenA ) | |||
tA = hlenA; | |||
} else if ( tB > hlenB ) { | |||
tB = hlenB; | |||
tA = tB * dirA_dot_dirB + dirA_dot_trans; | |||
if ( tA < -hlenA ) | |||
tA = -hlenA; | |||
else if ( tA > hlenA ) | |||
tA = hlenA; | |||
} | |||
// compute the closest points relative to segment centers. | |||
offsetA = dirA * tA; | |||
offsetB = dirB * tB; | |||
ptsVector = translation - offsetA + offsetB; | |||
} | |||
static SIMD_FORCE_INLINE btScalar capsuleCapsuleDistance( | |||
btVector3& normalOnB, | |||
btVector3& pointOnB, | |||
btScalar capsuleLengthA, | |||
btScalar capsuleRadiusA, | |||
btScalar capsuleLengthB, | |||
btScalar capsuleRadiusB, | |||
int capsuleAxisA, | |||
int capsuleAxisB, | |||
const btTransform& transformA, | |||
const btTransform& transformB, | |||
btScalar distanceThreshold ) | |||
{ | |||
btVector3 directionA = transformA.getBasis().getColumn(capsuleAxisA); | |||
btVector3 translationA = transformA.getOrigin(); | |||
btVector3 directionB = transformB.getBasis().getColumn(capsuleAxisB); | |||
btVector3 translationB = transformB.getOrigin(); | |||
// translation between centers | |||
btVector3 translation = translationB - translationA; | |||
// compute the closest points of the capsule line segments | |||
btVector3 ptsVector; // the vector between the closest points | |||
btVector3 offsetA, offsetB; // offsets from segment centers to their closest points | |||
btScalar tA, tB; // parameters on line segment | |||
segmentsClosestPoints( ptsVector, offsetA, offsetB, tA, tB, translation, | |||
directionA, capsuleLengthA, directionB, capsuleLengthB ); | |||
btScalar distance = ptsVector.length() - capsuleRadiusA - capsuleRadiusB; | |||
if ( distance > distanceThreshold ) | |||
return distance; | |||
btScalar lenSqr = ptsVector.length2(); | |||
if (lenSqr<= (SIMD_EPSILON*SIMD_EPSILON)) | |||
{ | |||
//degenerate case where 2 capsules are likely at the same location: take a vector tangential to 'directionA' | |||
btVector3 q; | |||
btPlaneSpace1(directionA,normalOnB,q); | |||
} else | |||
{ | |||
// compute the contact normal | |||
normalOnB = ptsVector*-btRecipSqrt(lenSqr); | |||
} | |||
pointOnB = transformB.getOrigin()+offsetB + normalOnB * capsuleRadiusB; | |||
return distance; | |||
} | |||
////////// | |||
btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) | |||
{ | |||
m_numPerturbationIterations = 0; | |||
m_minimumPointsPerturbationThreshold = 3; | |||
m_simplexSolver = simplexSolver; | |||
m_pdSolver = pdSolver; | |||
} | |||
btConvexConvexAlgorithm::CreateFunc::~CreateFunc() | |||
{ | |||
} | |||
btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold) | |||
: btActivatingCollisionAlgorithm(ci,body0,body1), | |||
m_simplexSolver(simplexSolver), | |||
m_pdSolver(pdSolver), | |||
m_ownManifold (false), | |||
m_manifoldPtr(mf), | |||
m_lowLevelOfDetail(false), | |||
#ifdef USE_SEPDISTANCE_UTIL2 | |||
m_sepDistance((static_cast<btConvexShape*>(body0->getCollisionShape()))->getAngularMotionDisc(), | |||
(static_cast<btConvexShape*>(body1->getCollisionShape()))->getAngularMotionDisc()), | |||
#endif | |||
m_numPerturbationIterations(numPerturbationIterations), | |||
m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold) | |||
{ | |||
(void)body0; | |||
(void)body1; | |||
} | |||
btConvexConvexAlgorithm::~btConvexConvexAlgorithm() | |||
{ | |||
if (m_ownManifold) | |||
{ | |||
if (m_manifoldPtr) | |||
m_dispatcher->releaseManifold(m_manifoldPtr); | |||
} | |||
} | |||
void btConvexConvexAlgorithm ::setLowLevelOfDetail(bool useLowLevel) | |||
{ | |||
m_lowLevelOfDetail = useLowLevel; | |||
} | |||
struct btPerturbedContactResult : public btManifoldResult | |||
{ | |||
btManifoldResult* m_originalManifoldResult; | |||
btTransform m_transformA; | |||
btTransform m_transformB; | |||
btTransform m_unPerturbedTransform; | |||
bool m_perturbA; | |||
btIDebugDraw* m_debugDrawer; | |||
btPerturbedContactResult(btManifoldResult* originalResult,const btTransform& transformA,const btTransform& transformB,const btTransform& unPerturbedTransform,bool perturbA,btIDebugDraw* debugDrawer) | |||
:m_originalManifoldResult(originalResult), | |||
m_transformA(transformA), | |||
m_transformB(transformB), | |||
m_unPerturbedTransform(unPerturbedTransform), | |||
m_perturbA(perturbA), | |||
m_debugDrawer(debugDrawer) | |||
{ | |||
} | |||
virtual ~ btPerturbedContactResult() | |||
{ | |||
} | |||
virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar orgDepth) | |||
{ | |||
btVector3 endPt,startPt; | |||
btScalar newDepth; | |||
btVector3 newNormal; | |||
if (m_perturbA) | |||
{ | |||
btVector3 endPtOrg = pointInWorld + normalOnBInWorld*orgDepth; | |||
endPt = (m_unPerturbedTransform*m_transformA.inverse())(endPtOrg); | |||
newDepth = (endPt - pointInWorld).dot(normalOnBInWorld); | |||
startPt = endPt+normalOnBInWorld*newDepth; | |||
} else | |||
{ | |||
endPt = pointInWorld + normalOnBInWorld*orgDepth; | |||
startPt = (m_unPerturbedTransform*m_transformB.inverse())(pointInWorld); | |||
newDepth = (endPt - startPt).dot(normalOnBInWorld); | |||
} | |||
//#define DEBUG_CONTACTS 1 | |||
#ifdef DEBUG_CONTACTS | |||
m_debugDrawer->drawLine(startPt,endPt,btVector3(1,0,0)); | |||
m_debugDrawer->drawSphere(startPt,0.05,btVector3(0,1,0)); | |||
m_debugDrawer->drawSphere(endPt,0.05,btVector3(0,0,1)); | |||
#endif //DEBUG_CONTACTS | |||
m_originalManifoldResult->addContactPoint(normalOnBInWorld,startPt,newDepth); | |||
} | |||
}; | |||
extern btScalar gContactBreakingThreshold; | |||
// | |||
// Convex-Convex collision algorithm | |||
// | |||
void btConvexConvexAlgorithm ::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
if (!m_manifoldPtr) | |||
{ | |||
//swapped? | |||
m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1); | |||
m_ownManifold = true; | |||
} | |||
resultOut->setPersistentManifold(m_manifoldPtr); | |||
//comment-out next line to test multi-contact generation | |||
//resultOut->getPersistentManifold()->clearManifold(); | |||
btConvexShape* min0 = static_cast<btConvexShape*>(body0->getCollisionShape()); | |||
btConvexShape* min1 = static_cast<btConvexShape*>(body1->getCollisionShape()); | |||
btVector3 normalOnB; | |||
btVector3 pointOnBWorld; | |||
#ifndef BT_DISABLE_CAPSULE_CAPSULE_COLLIDER | |||
if ((min0->getShapeType() == CAPSULE_SHAPE_PROXYTYPE) && (min1->getShapeType() == CAPSULE_SHAPE_PROXYTYPE)) | |||
{ | |||
btCapsuleShape* capsuleA = (btCapsuleShape*) min0; | |||
btCapsuleShape* capsuleB = (btCapsuleShape*) min1; | |||
btVector3 localScalingA = capsuleA->getLocalScaling(); | |||
btVector3 localScalingB = capsuleB->getLocalScaling(); | |||
btScalar threshold = m_manifoldPtr->getContactBreakingThreshold(); | |||
btScalar dist = capsuleCapsuleDistance(normalOnB, pointOnBWorld,capsuleA->getHalfHeight(),capsuleA->getRadius(), | |||
capsuleB->getHalfHeight(),capsuleB->getRadius(),capsuleA->getUpAxis(),capsuleB->getUpAxis(), | |||
body0->getWorldTransform(),body1->getWorldTransform(),threshold); | |||
if (dist<threshold) | |||
{ | |||
btAssert(normalOnB.length2()>=(SIMD_EPSILON*SIMD_EPSILON)); | |||
resultOut->addContactPoint(normalOnB,pointOnBWorld,dist); | |||
} | |||
resultOut->refreshContactPoints(); | |||
return; | |||
} | |||
#endif //BT_DISABLE_CAPSULE_CAPSULE_COLLIDER | |||
#ifdef USE_SEPDISTANCE_UTIL2 | |||
if (dispatchInfo.m_useConvexConservativeDistanceUtil) | |||
{ | |||
m_sepDistance.updateSeparatingDistance(body0->getWorldTransform(),body1->getWorldTransform()); | |||
} | |||
if (!dispatchInfo.m_useConvexConservativeDistanceUtil || m_sepDistance.getConservativeSeparatingDistance()<=0.f) | |||
#endif //USE_SEPDISTANCE_UTIL2 | |||
{ | |||
btGjkPairDetector::ClosestPointInput input; | |||
btGjkPairDetector gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver); | |||
//TODO: if (dispatchInfo.m_useContinuous) | |||
gjkPairDetector.setMinkowskiA(min0); | |||
gjkPairDetector.setMinkowskiB(min1); | |||
#ifdef USE_SEPDISTANCE_UTIL2 | |||
if (dispatchInfo.m_useConvexConservativeDistanceUtil) | |||
{ | |||
input.m_maximumDistanceSquared = BT_LARGE_FLOAT; | |||
} else | |||
#endif //USE_SEPDISTANCE_UTIL2 | |||
{ | |||
//if (dispatchInfo.m_convexMaxDistanceUseCPT) | |||
//{ | |||
// input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactProcessingThreshold(); | |||
//} else | |||
//{ | |||
input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold(); | |||
// } | |||
input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared; | |||
} | |||
input.m_stackAlloc = dispatchInfo.m_stackAllocator; | |||
input.m_transformA = body0->getWorldTransform(); | |||
input.m_transformB = body1->getWorldTransform(); | |||
#ifdef USE_SEPDISTANCE_UTIL2 | |||
btScalar sepDist = 0.f; | |||
if (dispatchInfo.m_useConvexConservativeDistanceUtil) | |||
{ | |||
sepDist = gjkPairDetector.getCachedSeparatingDistance(); | |||
if (sepDist>SIMD_EPSILON) | |||
{ | |||
sepDist += dispatchInfo.m_convexConservativeDistanceThreshold; | |||
//now perturbe directions to get multiple contact points | |||
} | |||
} | |||
#endif //USE_SEPDISTANCE_UTIL2 | |||
if (min0->isPolyhedral() && min1->isPolyhedral()) | |||
{ | |||
struct btDummyResult : public btDiscreteCollisionDetectorInterface::Result | |||
{ | |||
virtual void setShapeIdentifiersA(int partId0,int index0){} | |||
virtual void setShapeIdentifiersB(int partId1,int index1){} | |||
virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) | |||
{ | |||
} | |||
}; | |||
btDummyResult dummy; | |||
btPolyhedralConvexShape* polyhedronA = (btPolyhedralConvexShape*) min0; | |||
btPolyhedralConvexShape* polyhedronB = (btPolyhedralConvexShape*) min1; | |||
if (polyhedronA->getConvexPolyhedron() && polyhedronB->getConvexPolyhedron()) | |||
{ | |||
btScalar threshold = m_manifoldPtr->getContactBreakingThreshold(); | |||
btScalar minDist = -1e30f; | |||
btVector3 sepNormalWorldSpace; | |||
bool foundSepAxis = true; | |||
if (dispatchInfo.m_enableSatConvex) | |||
{ | |||
foundSepAxis = btPolyhedralContactClipping::findSeparatingAxis( | |||
*polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(), | |||
body0->getWorldTransform(), | |||
body1->getWorldTransform(), | |||
sepNormalWorldSpace); | |||
} else | |||
{ | |||
#ifdef ZERO_MARGIN | |||
gjkPairDetector.setIgnoreMargin(true); | |||
gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); | |||
#else | |||
//gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); | |||
gjkPairDetector.getClosestPoints(input,dummy,dispatchInfo.m_debugDraw); | |||
#endif //ZERO_MARGIN | |||
btScalar l2 = gjkPairDetector.getCachedSeparatingAxis().length2(); | |||
if (l2>SIMD_EPSILON) | |||
{ | |||
sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis()*(1.f/l2); | |||
//minDist = -1e30f;//gjkPairDetector.getCachedSeparatingDistance(); | |||
minDist = gjkPairDetector.getCachedSeparatingDistance()-min0->getMargin()-min1->getMargin(); | |||
#ifdef ZERO_MARGIN | |||
foundSepAxis = true;//gjkPairDetector.getCachedSeparatingDistance()<0.f; | |||
#else | |||
foundSepAxis = gjkPairDetector.getCachedSeparatingDistance()<(min0->getMargin()+min1->getMargin()); | |||
#endif | |||
} | |||
} | |||
if (foundSepAxis) | |||
{ | |||
// printf("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.getX(),sepNormalWorldSpace.getY(),sepNormalWorldSpace.getZ()); | |||
btPolyhedralContactClipping::clipHullAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(), | |||
body0->getWorldTransform(), | |||
body1->getWorldTransform(), minDist-threshold, threshold, *resultOut); | |||
} | |||
if (m_ownManifold) | |||
{ | |||
resultOut->refreshContactPoints(); | |||
} | |||
return; | |||
} else | |||
{ | |||
//we can also deal with convex versus triangle (without connectivity data) | |||
if (polyhedronA->getConvexPolyhedron() && polyhedronB->getShapeType()==TRIANGLE_SHAPE_PROXYTYPE) | |||
{ | |||
btVertexArray vertices; | |||
btTriangleShape* tri = (btTriangleShape*)polyhedronB; | |||
vertices.push_back( body1->getWorldTransform()*tri->m_vertices1[0]); | |||
vertices.push_back( body1->getWorldTransform()*tri->m_vertices1[1]); | |||
vertices.push_back( body1->getWorldTransform()*tri->m_vertices1[2]); | |||
//tri->initializePolyhedralFeatures(); | |||
btScalar threshold = m_manifoldPtr->getContactBreakingThreshold(); | |||
btVector3 sepNormalWorldSpace; | |||
btScalar minDist =-1e30f; | |||
btScalar maxDist = threshold; | |||
bool foundSepAxis = false; | |||
if (0) | |||
{ | |||
polyhedronB->initializePolyhedralFeatures(); | |||
foundSepAxis = btPolyhedralContactClipping::findSeparatingAxis( | |||
*polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(), | |||
body0->getWorldTransform(), | |||
body1->getWorldTransform(), | |||
sepNormalWorldSpace); | |||
// printf("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.getX(),sepNormalWorldSpace.getY(),sepNormalWorldSpace.getZ()); | |||
} else | |||
{ | |||
#ifdef ZERO_MARGIN | |||
gjkPairDetector.setIgnoreMargin(true); | |||
gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); | |||
#else | |||
gjkPairDetector.getClosestPoints(input,dummy,dispatchInfo.m_debugDraw); | |||
#endif//ZERO_MARGIN | |||
btScalar l2 = gjkPairDetector.getCachedSeparatingAxis().length2(); | |||
if (l2>SIMD_EPSILON) | |||
{ | |||
sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis()*(1.f/l2); | |||
//minDist = gjkPairDetector.getCachedSeparatingDistance(); | |||
//maxDist = threshold; | |||
minDist = gjkPairDetector.getCachedSeparatingDistance()-min0->getMargin()-min1->getMargin(); | |||
foundSepAxis = true; | |||
} | |||
} | |||
if (foundSepAxis) | |||
{ | |||
btPolyhedralContactClipping::clipFaceAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(), | |||
body0->getWorldTransform(), vertices, minDist-threshold, maxDist, *resultOut); | |||
} | |||
if (m_ownManifold) | |||
{ | |||
resultOut->refreshContactPoints(); | |||
} | |||
return; | |||
} | |||
} | |||
} | |||
gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); | |||
//now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects | |||
//perform perturbation when more then 'm_minimumPointsPerturbationThreshold' points | |||
if (m_numPerturbationIterations && resultOut->getPersistentManifold()->getNumContacts() < m_minimumPointsPerturbationThreshold) | |||
{ | |||
int i; | |||
btVector3 v0,v1; | |||
btVector3 sepNormalWorldSpace; | |||
btScalar l2 = gjkPairDetector.getCachedSeparatingAxis().length2(); | |||
if (l2>SIMD_EPSILON) | |||
{ | |||
sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis()*(1.f/l2); | |||
btPlaneSpace1(sepNormalWorldSpace,v0,v1); | |||
bool perturbeA = true; | |||
const btScalar angleLimit = 0.125f * SIMD_PI; | |||
btScalar perturbeAngle; | |||
btScalar radiusA = min0->getAngularMotionDisc(); | |||
btScalar radiusB = min1->getAngularMotionDisc(); | |||
if (radiusA < radiusB) | |||
{ | |||
perturbeAngle = gContactBreakingThreshold /radiusA; | |||
perturbeA = true; | |||
} else | |||
{ | |||
perturbeAngle = gContactBreakingThreshold / radiusB; | |||
perturbeA = false; | |||
} | |||
if ( perturbeAngle > angleLimit ) | |||
perturbeAngle = angleLimit; | |||
btTransform unPerturbedTransform; | |||
if (perturbeA) | |||
{ | |||
unPerturbedTransform = input.m_transformA; | |||
} else | |||
{ | |||
unPerturbedTransform = input.m_transformB; | |||
} | |||
for ( i=0;i<m_numPerturbationIterations;i++) | |||
{ | |||
if (v0.length2()>SIMD_EPSILON) | |||
{ | |||
btQuaternion perturbeRot(v0,perturbeAngle); | |||
btScalar iterationAngle = i*(SIMD_2_PI/btScalar(m_numPerturbationIterations)); | |||
btQuaternion rotq(sepNormalWorldSpace,iterationAngle); | |||
if (perturbeA) | |||
{ | |||
input.m_transformA.setBasis( btMatrix3x3(rotq.inverse()*perturbeRot*rotq)*body0->getWorldTransform().getBasis()); | |||
input.m_transformB = body1->getWorldTransform(); | |||
#ifdef DEBUG_CONTACTS | |||
dispatchInfo.m_debugDraw->drawTransform(input.m_transformA,10.0); | |||
#endif //DEBUG_CONTACTS | |||
} else | |||
{ | |||
input.m_transformA = body0->getWorldTransform(); | |||
input.m_transformB.setBasis( btMatrix3x3(rotq.inverse()*perturbeRot*rotq)*body1->getWorldTransform().getBasis()); | |||
#ifdef DEBUG_CONTACTS | |||
dispatchInfo.m_debugDraw->drawTransform(input.m_transformB,10.0); | |||
#endif | |||
} | |||
btPerturbedContactResult perturbedResultOut(resultOut,input.m_transformA,input.m_transformB,unPerturbedTransform,perturbeA,dispatchInfo.m_debugDraw); | |||
gjkPairDetector.getClosestPoints(input,perturbedResultOut,dispatchInfo.m_debugDraw); | |||
} | |||
} | |||
} | |||
} | |||
#ifdef USE_SEPDISTANCE_UTIL2 | |||
if (dispatchInfo.m_useConvexConservativeDistanceUtil && (sepDist>SIMD_EPSILON)) | |||
{ | |||
m_sepDistance.initSeparatingDistance(gjkPairDetector.getCachedSeparatingAxis(),sepDist,body0->getWorldTransform(),body1->getWorldTransform()); | |||
} | |||
#endif //USE_SEPDISTANCE_UTIL2 | |||
} | |||
if (m_ownManifold) | |||
{ | |||
resultOut->refreshContactPoints(); | |||
} | |||
} | |||
bool disableCcd = false; | |||
btScalar btConvexConvexAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
(void)resultOut; | |||
(void)dispatchInfo; | |||
///Rather then checking ALL pairs, only calculate TOI when motion exceeds threshold | |||
///Linear motion for one of objects needs to exceed m_ccdSquareMotionThreshold | |||
///col0->m_worldTransform, | |||
btScalar resultFraction = btScalar(1.); | |||
btScalar squareMot0 = (col0->getInterpolationWorldTransform().getOrigin() - col0->getWorldTransform().getOrigin()).length2(); | |||
btScalar squareMot1 = (col1->getInterpolationWorldTransform().getOrigin() - col1->getWorldTransform().getOrigin()).length2(); | |||
if (squareMot0 < col0->getCcdSquareMotionThreshold() && | |||
squareMot1 < col1->getCcdSquareMotionThreshold()) | |||
return resultFraction; | |||
if (disableCcd) | |||
return btScalar(1.); | |||
//An adhoc way of testing the Continuous Collision Detection algorithms | |||
//One object is approximated as a sphere, to simplify things | |||
//Starting in penetration should report no time of impact | |||
//For proper CCD, better accuracy and handling of 'allowed' penetration should be added | |||
//also the mainloop of the physics should have a kind of toi queue (something like Brian Mirtich's application of Timewarp for Rigidbodies) | |||
/// Convex0 against sphere for Convex1 | |||
{ | |||
btConvexShape* convex0 = static_cast<btConvexShape*>(col0->getCollisionShape()); | |||
btSphereShape sphere1(col1->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation | |||
btConvexCast::CastResult result; | |||
btVoronoiSimplexSolver voronoiSimplex; | |||
//SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); | |||
///Simplification, one object is simplified as a sphere | |||
btGjkConvexCast ccd1( convex0 ,&sphere1,&voronoiSimplex); | |||
//ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); | |||
if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), | |||
col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) | |||
{ | |||
//store result.m_fraction in both bodies | |||
if (col0->getHitFraction()> result.m_fraction) | |||
col0->setHitFraction( result.m_fraction ); | |||
if (col1->getHitFraction() > result.m_fraction) | |||
col1->setHitFraction( result.m_fraction); | |||
if (resultFraction > result.m_fraction) | |||
resultFraction = result.m_fraction; | |||
} | |||
} | |||
/// Sphere (for convex0) against Convex1 | |||
{ | |||
btConvexShape* convex1 = static_cast<btConvexShape*>(col1->getCollisionShape()); | |||
btSphereShape sphere0(col0->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation | |||
btConvexCast::CastResult result; | |||
btVoronoiSimplexSolver voronoiSimplex; | |||
//SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); | |||
///Simplification, one object is simplified as a sphere | |||
btGjkConvexCast ccd1(&sphere0,convex1,&voronoiSimplex); | |||
//ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); | |||
if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), | |||
col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) | |||
{ | |||
//store result.m_fraction in both bodies | |||
if (col0->getHitFraction() > result.m_fraction) | |||
col0->setHitFraction( result.m_fraction); | |||
if (col1->getHitFraction() > result.m_fraction) | |||
col1->setHitFraction( result.m_fraction); | |||
if (resultFraction > result.m_fraction) | |||
resultFraction = result.m_fraction; | |||
} | |||
} | |||
return resultFraction; | |||
} | |||
@@ -0,0 +1,109 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_CONVEX_CONVEX_ALGORITHM_H | |||
#define BT_CONVEX_CONVEX_ALGORITHM_H | |||
#include "btActivatingCollisionAlgorithm.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" | |||
#include "btCollisionCreateFunc.h" | |||
#include "btCollisionDispatcher.h" | |||
#include "LinearMath/btTransformUtil.h" //for btConvexSeparatingDistanceUtil | |||
class btConvexPenetrationDepthSolver; | |||
///Enabling USE_SEPDISTANCE_UTIL2 requires 100% reliable distance computation. However, when using large size ratios GJK can be imprecise | |||
///so the distance is not conservative. In that case, enabling this USE_SEPDISTANCE_UTIL2 would result in failing/missing collisions. | |||
///Either improve GJK for large size ratios (testing a 100 units versus a 0.1 unit object) or only enable the util | |||
///for certain pairs that have a small size ratio | |||
//#define USE_SEPDISTANCE_UTIL2 1 | |||
///The convexConvexAlgorithm collision algorithm implements time of impact, convex closest points and penetration depth calculations between two convex objects. | |||
///Multiple contact points are calculated by perturbing the orientation of the smallest object orthogonal to the separating normal. | |||
///This idea was described by Gino van den Bergen in this forum topic http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=4&t=288&p=888#p888 | |||
class btConvexConvexAlgorithm : public btActivatingCollisionAlgorithm | |||
{ | |||
#ifdef USE_SEPDISTANCE_UTIL2 | |||
btConvexSeparatingDistanceUtil m_sepDistance; | |||
#endif | |||
btSimplexSolverInterface* m_simplexSolver; | |||
btConvexPenetrationDepthSolver* m_pdSolver; | |||
bool m_ownManifold; | |||
btPersistentManifold* m_manifoldPtr; | |||
bool m_lowLevelOfDetail; | |||
int m_numPerturbationIterations; | |||
int m_minimumPointsPerturbationThreshold; | |||
///cache separating vector to speedup collision detection | |||
public: | |||
btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold); | |||
virtual ~btConvexConvexAlgorithm(); | |||
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
{ | |||
///should we use m_ownManifold to avoid adding duplicates? | |||
if (m_manifoldPtr && m_ownManifold) | |||
manifoldArray.push_back(m_manifoldPtr); | |||
} | |||
void setLowLevelOfDetail(bool useLowLevel); | |||
const btPersistentManifold* getManifold() | |||
{ | |||
return m_manifoldPtr; | |||
} | |||
struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
btConvexPenetrationDepthSolver* m_pdSolver; | |||
btSimplexSolverInterface* m_simplexSolver; | |||
int m_numPerturbationIterations; | |||
int m_minimumPointsPerturbationThreshold; | |||
CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver); | |||
virtual ~CreateFunc(); | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConvexAlgorithm)); | |||
return new(mem) btConvexConvexAlgorithm(ci.m_manifold,ci,body0,body1,m_simplexSolver,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); | |||
} | |||
}; | |||
}; | |||
#endif //BT_CONVEX_CONVEX_ALGORITHM_H |
@@ -0,0 +1,173 @@ | |||
/* | |||
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 "btConvexPlaneCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
#include "BulletCollision/CollisionShapes/btConvexShape.h" | |||
#include "BulletCollision/CollisionShapes/btStaticPlaneShape.h" | |||
//#include <stdio.h> | |||
btConvexPlaneCollisionAlgorithm::btConvexPlaneCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped, int numPerturbationIterations,int minimumPointsPerturbationThreshold) | |||
: btCollisionAlgorithm(ci), | |||
m_ownManifold(false), | |||
m_manifoldPtr(mf), | |||
m_isSwapped(isSwapped), | |||
m_numPerturbationIterations(numPerturbationIterations), | |||
m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold) | |||
{ | |||
btCollisionObject* convexObj = m_isSwapped? col1 : col0; | |||
btCollisionObject* planeObj = m_isSwapped? col0 : col1; | |||
if (!m_manifoldPtr && m_dispatcher->needsCollision(convexObj,planeObj)) | |||
{ | |||
m_manifoldPtr = m_dispatcher->getNewManifold(convexObj,planeObj); | |||
m_ownManifold = true; | |||
} | |||
} | |||
btConvexPlaneCollisionAlgorithm::~btConvexPlaneCollisionAlgorithm() | |||
{ | |||
if (m_ownManifold) | |||
{ | |||
if (m_manifoldPtr) | |||
m_dispatcher->releaseManifold(m_manifoldPtr); | |||
} | |||
} | |||
void btConvexPlaneCollisionAlgorithm::collideSingleContact (const btQuaternion& perturbeRot, btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
btCollisionObject* convexObj = m_isSwapped? body1 : body0; | |||
btCollisionObject* planeObj = m_isSwapped? body0: body1; | |||
btConvexShape* convexShape = (btConvexShape*) convexObj->getCollisionShape(); | |||
btStaticPlaneShape* planeShape = (btStaticPlaneShape*) planeObj->getCollisionShape(); | |||
bool hasCollision = false; | |||
const btVector3& planeNormal = planeShape->getPlaneNormal(); | |||
const btScalar& planeConstant = planeShape->getPlaneConstant(); | |||
btTransform convexWorldTransform = convexObj->getWorldTransform(); | |||
btTransform convexInPlaneTrans; | |||
convexInPlaneTrans= planeObj->getWorldTransform().inverse() * convexWorldTransform; | |||
//now perturbe the convex-world transform | |||
convexWorldTransform.getBasis()*=btMatrix3x3(perturbeRot); | |||
btTransform planeInConvex; | |||
planeInConvex= convexWorldTransform.inverse() * planeObj->getWorldTransform(); | |||
btVector3 vtx = convexShape->localGetSupportingVertex(planeInConvex.getBasis()*-planeNormal); | |||
btVector3 vtxInPlane = convexInPlaneTrans(vtx); | |||
btScalar distance = (planeNormal.dot(vtxInPlane) - planeConstant); | |||
btVector3 vtxInPlaneProjected = vtxInPlane - distance*planeNormal; | |||
btVector3 vtxInPlaneWorld = planeObj->getWorldTransform() * vtxInPlaneProjected; | |||
hasCollision = distance < m_manifoldPtr->getContactBreakingThreshold(); | |||
resultOut->setPersistentManifold(m_manifoldPtr); | |||
if (hasCollision) | |||
{ | |||
/// report a contact. internally this will be kept persistent, and contact reduction is done | |||
btVector3 normalOnSurfaceB = planeObj->getWorldTransform().getBasis() * planeNormal; | |||
btVector3 pOnB = vtxInPlaneWorld; | |||
resultOut->addContactPoint(normalOnSurfaceB,pOnB,distance); | |||
} | |||
} | |||
void btConvexPlaneCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
(void)dispatchInfo; | |||
if (!m_manifoldPtr) | |||
return; | |||
btCollisionObject* convexObj = m_isSwapped? body1 : body0; | |||
btCollisionObject* planeObj = m_isSwapped? body0: body1; | |||
btConvexShape* convexShape = (btConvexShape*) convexObj->getCollisionShape(); | |||
btStaticPlaneShape* planeShape = (btStaticPlaneShape*) planeObj->getCollisionShape(); | |||
bool hasCollision = false; | |||
const btVector3& planeNormal = planeShape->getPlaneNormal(); | |||
const btScalar& planeConstant = planeShape->getPlaneConstant(); | |||
btTransform planeInConvex; | |||
planeInConvex= convexObj->getWorldTransform().inverse() * planeObj->getWorldTransform(); | |||
btTransform convexInPlaneTrans; | |||
convexInPlaneTrans= planeObj->getWorldTransform().inverse() * convexObj->getWorldTransform(); | |||
btVector3 vtx = convexShape->localGetSupportingVertex(planeInConvex.getBasis()*-planeNormal); | |||
btVector3 vtxInPlane = convexInPlaneTrans(vtx); | |||
btScalar distance = (planeNormal.dot(vtxInPlane) - planeConstant); | |||
btVector3 vtxInPlaneProjected = vtxInPlane - distance*planeNormal; | |||
btVector3 vtxInPlaneWorld = planeObj->getWorldTransform() * vtxInPlaneProjected; | |||
hasCollision = distance < m_manifoldPtr->getContactBreakingThreshold(); | |||
resultOut->setPersistentManifold(m_manifoldPtr); | |||
if (hasCollision) | |||
{ | |||
/// report a contact. internally this will be kept persistent, and contact reduction is done | |||
btVector3 normalOnSurfaceB = planeObj->getWorldTransform().getBasis() * planeNormal; | |||
btVector3 pOnB = vtxInPlaneWorld; | |||
resultOut->addContactPoint(normalOnSurfaceB,pOnB,distance); | |||
} | |||
//the perturbation algorithm doesn't work well with implicit surfaces such as spheres, cylinder and cones: | |||
//they keep on rolling forever because of the additional off-center contact points | |||
//so only enable the feature for polyhedral shapes (btBoxShape, btConvexHullShape etc) | |||
if (convexShape->isPolyhedral() && resultOut->getPersistentManifold()->getNumContacts()<m_minimumPointsPerturbationThreshold) | |||
{ | |||
btVector3 v0,v1; | |||
btPlaneSpace1(planeNormal,v0,v1); | |||
//now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects | |||
const btScalar angleLimit = 0.125f * SIMD_PI; | |||
btScalar perturbeAngle; | |||
btScalar radius = convexShape->getAngularMotionDisc(); | |||
perturbeAngle = gContactBreakingThreshold / radius; | |||
if ( perturbeAngle > angleLimit ) | |||
perturbeAngle = angleLimit; | |||
btQuaternion perturbeRot(v0,perturbeAngle); | |||
for (int i=0;i<m_numPerturbationIterations;i++) | |||
{ | |||
btScalar iterationAngle = i*(SIMD_2_PI/btScalar(m_numPerturbationIterations)); | |||
btQuaternion rotq(planeNormal,iterationAngle); | |||
collideSingleContact(rotq.inverse()*perturbeRot*rotq,body0,body1,dispatchInfo,resultOut); | |||
} | |||
} | |||
if (m_ownManifold) | |||
{ | |||
if (m_manifoldPtr->getNumContacts()) | |||
{ | |||
resultOut->refreshContactPoints(); | |||
} | |||
} | |||
} | |||
btScalar btConvexPlaneCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
(void)resultOut; | |||
(void)dispatchInfo; | |||
(void)col0; | |||
(void)col1; | |||
//not yet | |||
return btScalar(1.); | |||
} |
@@ -0,0 +1,84 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_CONVEX_PLANE_COLLISION_ALGORITHM_H | |||
#define BT_CONVEX_PLANE_COLLISION_ALGORITHM_H | |||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
class btPersistentManifold; | |||
#include "btCollisionDispatcher.h" | |||
#include "LinearMath/btVector3.h" | |||
/// btSphereBoxCollisionAlgorithm provides sphere-box collision detection. | |||
/// Other features are frame-coherency (persistent data) and collision response. | |||
class btConvexPlaneCollisionAlgorithm : public btCollisionAlgorithm | |||
{ | |||
bool m_ownManifold; | |||
btPersistentManifold* m_manifoldPtr; | |||
bool m_isSwapped; | |||
int m_numPerturbationIterations; | |||
int m_minimumPointsPerturbationThreshold; | |||
public: | |||
btConvexPlaneCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped, int numPerturbationIterations,int minimumPointsPerturbationThreshold); | |||
virtual ~btConvexPlaneCollisionAlgorithm(); | |||
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
void collideSingleContact (const btQuaternion& perturbeRot, btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
{ | |||
if (m_manifoldPtr && m_ownManifold) | |||
{ | |||
manifoldArray.push_back(m_manifoldPtr); | |||
} | |||
} | |||
struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
int m_numPerturbationIterations; | |||
int m_minimumPointsPerturbationThreshold; | |||
CreateFunc() | |||
: m_numPerturbationIterations(1), | |||
m_minimumPointsPerturbationThreshold(0) | |||
{ | |||
} | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexPlaneCollisionAlgorithm)); | |||
if (!m_swapped) | |||
{ | |||
return new(mem) btConvexPlaneCollisionAlgorithm(0,ci,body0,body1,false,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); | |||
} else | |||
{ | |||
return new(mem) btConvexPlaneCollisionAlgorithm(0,ci,body0,body1,true,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); | |||
} | |||
} | |||
}; | |||
}; | |||
#endif //BT_CONVEX_PLANE_COLLISION_ALGORITHM_H | |||
@@ -0,0 +1,309 @@ | |||
/* | |||
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 "btDefaultCollisionConfiguration.h" | |||
#include "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h" | |||
#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
#include "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h" | |||
#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
#include "BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" | |||
#include "LinearMath/btStackAlloc.h" | |||
#include "LinearMath/btPoolAllocator.h" | |||
btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefaultCollisionConstructionInfo& constructionInfo) | |||
//btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(btStackAlloc* stackAlloc,btPoolAllocator* persistentManifoldPool,btPoolAllocator* collisionAlgorithmPool) | |||
{ | |||
void* mem = btAlignedAlloc(sizeof(btVoronoiSimplexSolver),16); | |||
m_simplexSolver = new (mem)btVoronoiSimplexSolver(); | |||
if (constructionInfo.m_useEpaPenetrationAlgorithm) | |||
{ | |||
mem = btAlignedAlloc(sizeof(btGjkEpaPenetrationDepthSolver),16); | |||
m_pdSolver = new (mem)btGjkEpaPenetrationDepthSolver; | |||
}else | |||
{ | |||
mem = btAlignedAlloc(sizeof(btMinkowskiPenetrationDepthSolver),16); | |||
m_pdSolver = new (mem)btMinkowskiPenetrationDepthSolver; | |||
} | |||
//default CreationFunctions, filling the m_doubleDispatch table | |||
mem = btAlignedAlloc(sizeof(btConvexConvexAlgorithm::CreateFunc),16); | |||
m_convexConvexCreateFunc = new(mem) btConvexConvexAlgorithm::CreateFunc(m_simplexSolver,m_pdSolver); | |||
mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16); | |||
m_convexConcaveCreateFunc = new (mem)btConvexConcaveCollisionAlgorithm::CreateFunc; | |||
mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16); | |||
m_swappedConvexConcaveCreateFunc = new (mem)btConvexConcaveCollisionAlgorithm::SwappedCreateFunc; | |||
mem = btAlignedAlloc(sizeof(btCompoundCollisionAlgorithm::CreateFunc),16); | |||
m_compoundCreateFunc = new (mem)btCompoundCollisionAlgorithm::CreateFunc; | |||
mem = btAlignedAlloc(sizeof(btCompoundCollisionAlgorithm::SwappedCreateFunc),16); | |||
m_swappedCompoundCreateFunc = new (mem)btCompoundCollisionAlgorithm::SwappedCreateFunc; | |||
mem = btAlignedAlloc(sizeof(btEmptyAlgorithm::CreateFunc),16); | |||
m_emptyCreateFunc = new(mem) btEmptyAlgorithm::CreateFunc; | |||
mem = btAlignedAlloc(sizeof(btSphereSphereCollisionAlgorithm::CreateFunc),16); | |||
m_sphereSphereCF = new(mem) btSphereSphereCollisionAlgorithm::CreateFunc; | |||
#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
mem = btAlignedAlloc(sizeof(btSphereBoxCollisionAlgorithm::CreateFunc),16); | |||
m_sphereBoxCF = new(mem) btSphereBoxCollisionAlgorithm::CreateFunc; | |||
mem = btAlignedAlloc(sizeof(btSphereBoxCollisionAlgorithm::CreateFunc),16); | |||
m_boxSphereCF = new (mem)btSphereBoxCollisionAlgorithm::CreateFunc; | |||
m_boxSphereCF->m_swapped = true; | |||
#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
mem = btAlignedAlloc(sizeof(btSphereTriangleCollisionAlgorithm::CreateFunc),16); | |||
m_sphereTriangleCF = new (mem)btSphereTriangleCollisionAlgorithm::CreateFunc; | |||
mem = btAlignedAlloc(sizeof(btSphereTriangleCollisionAlgorithm::CreateFunc),16); | |||
m_triangleSphereCF = new (mem)btSphereTriangleCollisionAlgorithm::CreateFunc; | |||
m_triangleSphereCF->m_swapped = true; | |||
mem = btAlignedAlloc(sizeof(btBoxBoxCollisionAlgorithm::CreateFunc),16); | |||
m_boxBoxCF = new(mem)btBoxBoxCollisionAlgorithm::CreateFunc; | |||
//convex versus plane | |||
mem = btAlignedAlloc (sizeof(btConvexPlaneCollisionAlgorithm::CreateFunc),16); | |||
m_convexPlaneCF = new (mem) btConvexPlaneCollisionAlgorithm::CreateFunc; | |||
mem = btAlignedAlloc (sizeof(btConvexPlaneCollisionAlgorithm::CreateFunc),16); | |||
m_planeConvexCF = new (mem) btConvexPlaneCollisionAlgorithm::CreateFunc; | |||
m_planeConvexCF->m_swapped = true; | |||
///calculate maximum element size, big enough to fit any collision algorithm in the memory pool | |||
int maxSize = sizeof(btConvexConvexAlgorithm); | |||
int maxSize2 = sizeof(btConvexConcaveCollisionAlgorithm); | |||
int maxSize3 = sizeof(btCompoundCollisionAlgorithm); | |||
int sl = sizeof(btConvexSeparatingDistanceUtil); | |||
sl = sizeof(btGjkPairDetector); | |||
int collisionAlgorithmMaxElementSize = btMax(maxSize,constructionInfo.m_customCollisionAlgorithmMaxElementSize); | |||
collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize2); | |||
collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize3); | |||
if (constructionInfo.m_stackAlloc) | |||
{ | |||
m_ownsStackAllocator = false; | |||
this->m_stackAlloc = constructionInfo.m_stackAlloc; | |||
} else | |||
{ | |||
m_ownsStackAllocator = true; | |||
void* mem = btAlignedAlloc(sizeof(btStackAlloc),16); | |||
m_stackAlloc = new(mem)btStackAlloc(constructionInfo.m_defaultStackAllocatorSize); | |||
} | |||
if (constructionInfo.m_persistentManifoldPool) | |||
{ | |||
m_ownsPersistentManifoldPool = false; | |||
m_persistentManifoldPool = constructionInfo.m_persistentManifoldPool; | |||
} else | |||
{ | |||
m_ownsPersistentManifoldPool = true; | |||
void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16); | |||
m_persistentManifoldPool = new (mem) btPoolAllocator(sizeof(btPersistentManifold),constructionInfo.m_defaultMaxPersistentManifoldPoolSize); | |||
} | |||
if (constructionInfo.m_collisionAlgorithmPool) | |||
{ | |||
m_ownsCollisionAlgorithmPool = false; | |||
m_collisionAlgorithmPool = constructionInfo.m_collisionAlgorithmPool; | |||
} else | |||
{ | |||
m_ownsCollisionAlgorithmPool = true; | |||
void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16); | |||
m_collisionAlgorithmPool = new(mem) btPoolAllocator(collisionAlgorithmMaxElementSize,constructionInfo.m_defaultMaxCollisionAlgorithmPoolSize); | |||
} | |||
} | |||
btDefaultCollisionConfiguration::~btDefaultCollisionConfiguration() | |||
{ | |||
if (m_ownsStackAllocator) | |||
{ | |||
m_stackAlloc->destroy(); | |||
m_stackAlloc->~btStackAlloc(); | |||
btAlignedFree(m_stackAlloc); | |||
} | |||
if (m_ownsCollisionAlgorithmPool) | |||
{ | |||
m_collisionAlgorithmPool->~btPoolAllocator(); | |||
btAlignedFree(m_collisionAlgorithmPool); | |||
} | |||
if (m_ownsPersistentManifoldPool) | |||
{ | |||
m_persistentManifoldPool->~btPoolAllocator(); | |||
btAlignedFree(m_persistentManifoldPool); | |||
} | |||
m_convexConvexCreateFunc->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_convexConvexCreateFunc); | |||
m_convexConcaveCreateFunc->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_convexConcaveCreateFunc); | |||
m_swappedConvexConcaveCreateFunc->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_swappedConvexConcaveCreateFunc); | |||
m_compoundCreateFunc->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_compoundCreateFunc); | |||
m_swappedCompoundCreateFunc->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_swappedCompoundCreateFunc); | |||
m_emptyCreateFunc->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_emptyCreateFunc); | |||
m_sphereSphereCF->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_sphereSphereCF); | |||
#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
m_sphereBoxCF->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_sphereBoxCF); | |||
m_boxSphereCF->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_boxSphereCF); | |||
#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
m_sphereTriangleCF->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_sphereTriangleCF); | |||
m_triangleSphereCF->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_triangleSphereCF); | |||
m_boxBoxCF->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_boxBoxCF); | |||
m_convexPlaneCF->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_convexPlaneCF); | |||
m_planeConvexCF->~btCollisionAlgorithmCreateFunc(); | |||
btAlignedFree( m_planeConvexCF); | |||
m_simplexSolver->~btVoronoiSimplexSolver(); | |||
btAlignedFree(m_simplexSolver); | |||
m_pdSolver->~btConvexPenetrationDepthSolver(); | |||
btAlignedFree(m_pdSolver); | |||
} | |||
btCollisionAlgorithmCreateFunc* btDefaultCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) | |||
{ | |||
if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1==SPHERE_SHAPE_PROXYTYPE)) | |||
{ | |||
return m_sphereSphereCF; | |||
} | |||
#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1==BOX_SHAPE_PROXYTYPE)) | |||
{ | |||
return m_sphereBoxCF; | |||
} | |||
if ((proxyType0 == BOX_SHAPE_PROXYTYPE ) && (proxyType1==SPHERE_SHAPE_PROXYTYPE)) | |||
{ | |||
return m_boxSphereCF; | |||
} | |||
#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE ) && (proxyType1==TRIANGLE_SHAPE_PROXYTYPE)) | |||
{ | |||
return m_sphereTriangleCF; | |||
} | |||
if ((proxyType0 == TRIANGLE_SHAPE_PROXYTYPE ) && (proxyType1==SPHERE_SHAPE_PROXYTYPE)) | |||
{ | |||
return m_triangleSphereCF; | |||
} | |||
if ((proxyType0 == BOX_SHAPE_PROXYTYPE) && (proxyType1 == BOX_SHAPE_PROXYTYPE)) | |||
{ | |||
return m_boxBoxCF; | |||
} | |||
if (btBroadphaseProxy::isConvex(proxyType0) && (proxyType1 == STATIC_PLANE_PROXYTYPE)) | |||
{ | |||
return m_convexPlaneCF; | |||
} | |||
if (btBroadphaseProxy::isConvex(proxyType1) && (proxyType0 == STATIC_PLANE_PROXYTYPE)) | |||
{ | |||
return m_planeConvexCF; | |||
} | |||
if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConvex(proxyType1)) | |||
{ | |||
return m_convexConvexCreateFunc; | |||
} | |||
if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConcave(proxyType1)) | |||
{ | |||
return m_convexConcaveCreateFunc; | |||
} | |||
if (btBroadphaseProxy::isConvex(proxyType1) && btBroadphaseProxy::isConcave(proxyType0)) | |||
{ | |||
return m_swappedConvexConcaveCreateFunc; | |||
} | |||
if (btBroadphaseProxy::isCompound(proxyType0)) | |||
{ | |||
return m_compoundCreateFunc; | |||
} else | |||
{ | |||
if (btBroadphaseProxy::isCompound(proxyType1)) | |||
{ | |||
return m_swappedCompoundCreateFunc; | |||
} | |||
} | |||
//failed to find an algorithm | |||
return m_emptyCreateFunc; | |||
} | |||
void btDefaultCollisionConfiguration::setConvexConvexMultipointIterations(int numPerturbationIterations, int minimumPointsPerturbationThreshold) | |||
{ | |||
btConvexConvexAlgorithm::CreateFunc* convexConvex = (btConvexConvexAlgorithm::CreateFunc*) m_convexConvexCreateFunc; | |||
convexConvex->m_numPerturbationIterations = numPerturbationIterations; | |||
convexConvex->m_minimumPointsPerturbationThreshold = minimumPointsPerturbationThreshold; | |||
} | |||
void btDefaultCollisionConfiguration::setPlaneConvexMultipointIterations(int numPerturbationIterations, int minimumPointsPerturbationThreshold) | |||
{ | |||
btConvexPlaneCollisionAlgorithm::CreateFunc* cpCF = (btConvexPlaneCollisionAlgorithm::CreateFunc*)m_convexPlaneCF; | |||
cpCF->m_numPerturbationIterations = numPerturbationIterations; | |||
cpCF->m_minimumPointsPerturbationThreshold = minimumPointsPerturbationThreshold; | |||
btConvexPlaneCollisionAlgorithm::CreateFunc* pcCF = (btConvexPlaneCollisionAlgorithm::CreateFunc*)m_planeConvexCF; | |||
pcCF->m_numPerturbationIterations = numPerturbationIterations; | |||
pcCF->m_minimumPointsPerturbationThreshold = minimumPointsPerturbationThreshold; | |||
} |
@@ -0,0 +1,137 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_DEFAULT_COLLISION_CONFIGURATION | |||
#define BT_DEFAULT_COLLISION_CONFIGURATION | |||
#include "btCollisionConfiguration.h" | |||
class btVoronoiSimplexSolver; | |||
class btConvexPenetrationDepthSolver; | |||
struct btDefaultCollisionConstructionInfo | |||
{ | |||
btStackAlloc* m_stackAlloc; | |||
btPoolAllocator* m_persistentManifoldPool; | |||
btPoolAllocator* m_collisionAlgorithmPool; | |||
int m_defaultMaxPersistentManifoldPoolSize; | |||
int m_defaultMaxCollisionAlgorithmPoolSize; | |||
int m_customCollisionAlgorithmMaxElementSize; | |||
int m_defaultStackAllocatorSize; | |||
int m_useEpaPenetrationAlgorithm; | |||
btDefaultCollisionConstructionInfo() | |||
:m_stackAlloc(0), | |||
m_persistentManifoldPool(0), | |||
m_collisionAlgorithmPool(0), | |||
m_defaultMaxPersistentManifoldPoolSize(4096), | |||
m_defaultMaxCollisionAlgorithmPoolSize(4096), | |||
m_customCollisionAlgorithmMaxElementSize(0), | |||
m_defaultStackAllocatorSize(0), | |||
m_useEpaPenetrationAlgorithm(true) | |||
{ | |||
} | |||
}; | |||
///btCollisionConfiguration allows to configure Bullet collision detection | |||
///stack allocator, pool memory allocators | |||
///@todo: describe the meaning | |||
class btDefaultCollisionConfiguration : public btCollisionConfiguration | |||
{ | |||
protected: | |||
int m_persistentManifoldPoolSize; | |||
btStackAlloc* m_stackAlloc; | |||
bool m_ownsStackAllocator; | |||
btPoolAllocator* m_persistentManifoldPool; | |||
bool m_ownsPersistentManifoldPool; | |||
btPoolAllocator* m_collisionAlgorithmPool; | |||
bool m_ownsCollisionAlgorithmPool; | |||
//default simplex/penetration depth solvers | |||
btVoronoiSimplexSolver* m_simplexSolver; | |||
btConvexPenetrationDepthSolver* m_pdSolver; | |||
//default CreationFunctions, filling the m_doubleDispatch table | |||
btCollisionAlgorithmCreateFunc* m_convexConvexCreateFunc; | |||
btCollisionAlgorithmCreateFunc* m_convexConcaveCreateFunc; | |||
btCollisionAlgorithmCreateFunc* m_swappedConvexConcaveCreateFunc; | |||
btCollisionAlgorithmCreateFunc* m_compoundCreateFunc; | |||
btCollisionAlgorithmCreateFunc* m_swappedCompoundCreateFunc; | |||
btCollisionAlgorithmCreateFunc* m_emptyCreateFunc; | |||
btCollisionAlgorithmCreateFunc* m_sphereSphereCF; | |||
#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
btCollisionAlgorithmCreateFunc* m_sphereBoxCF; | |||
btCollisionAlgorithmCreateFunc* m_boxSphereCF; | |||
#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
btCollisionAlgorithmCreateFunc* m_boxBoxCF; | |||
btCollisionAlgorithmCreateFunc* m_sphereTriangleCF; | |||
btCollisionAlgorithmCreateFunc* m_triangleSphereCF; | |||
btCollisionAlgorithmCreateFunc* m_planeConvexCF; | |||
btCollisionAlgorithmCreateFunc* m_convexPlaneCF; | |||
public: | |||
btDefaultCollisionConfiguration(const btDefaultCollisionConstructionInfo& constructionInfo = btDefaultCollisionConstructionInfo()); | |||
virtual ~btDefaultCollisionConfiguration(); | |||
///memory pools | |||
virtual btPoolAllocator* getPersistentManifoldPool() | |||
{ | |||
return m_persistentManifoldPool; | |||
} | |||
virtual btPoolAllocator* getCollisionAlgorithmPool() | |||
{ | |||
return m_collisionAlgorithmPool; | |||
} | |||
virtual btStackAlloc* getStackAllocator() | |||
{ | |||
return m_stackAlloc; | |||
} | |||
virtual btVoronoiSimplexSolver* getSimplexSolver() | |||
{ | |||
return m_simplexSolver; | |||
} | |||
virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1); | |||
///Use this method to allow to generate multiple contact points between at once, between two objects using the generic convex-convex algorithm. | |||
///By default, this feature is disabled for best performance. | |||
///@param numPerturbationIterations controls the number of collision queries. Set it to zero to disable the feature. | |||
///@param minimumPointsPerturbationThreshold is the minimum number of points in the contact cache, above which the feature is disabled | |||
///3 is a good value for both params, if you want to enable the feature. This is because the default contact cache contains a maximum of 4 points, and one collision query at the unperturbed orientation is performed first. | |||
///See Bullet/Demos/CollisionDemo for an example how this feature gathers multiple points. | |||
///@todo we could add a per-object setting of those parameters, for level-of-detail collision detection. | |||
void setConvexConvexMultipointIterations(int numPerturbationIterations=3, int minimumPointsPerturbationThreshold = 3); | |||
void setPlaneConvexMultipointIterations(int numPerturbationIterations=3, int minimumPointsPerturbationThreshold = 3); | |||
}; | |||
#endif //BT_DEFAULT_COLLISION_CONFIGURATION | |||
@@ -0,0 +1,34 @@ | |||
/* | |||
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 "btEmptyCollisionAlgorithm.h" | |||
btEmptyAlgorithm::btEmptyAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) | |||
: btCollisionAlgorithm(ci) | |||
{ | |||
} | |||
void btEmptyAlgorithm::processCollision (btCollisionObject* ,btCollisionObject* ,const btDispatcherInfo& ,btManifoldResult* ) | |||
{ | |||
} | |||
btScalar btEmptyAlgorithm::calculateTimeOfImpact(btCollisionObject* ,btCollisionObject* ,const btDispatcherInfo& ,btManifoldResult* ) | |||
{ | |||
return btScalar(1.); | |||
} | |||
@@ -0,0 +1,54 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_EMPTY_ALGORITH | |||
#define BT_EMPTY_ALGORITH | |||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" | |||
#include "btCollisionCreateFunc.h" | |||
#include "btCollisionDispatcher.h" | |||
#define ATTRIBUTE_ALIGNED(a) | |||
///EmptyAlgorithm is a stub for unsupported collision pairs. | |||
///The dispatcher can dispatch a persistent btEmptyAlgorithm to avoid a search every frame. | |||
class btEmptyAlgorithm : public btCollisionAlgorithm | |||
{ | |||
public: | |||
btEmptyAlgorithm(const btCollisionAlgorithmConstructionInfo& ci); | |||
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
{ | |||
} | |||
struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
(void)body0; | |||
(void)body1; | |||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btEmptyAlgorithm)); | |||
return new(mem) btEmptyAlgorithm(ci); | |||
} | |||
}; | |||
} ATTRIBUTE_ALIGNED(16); | |||
#endif //BT_EMPTY_ALGORITH |
@@ -0,0 +1,171 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com | |||
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 "btGhostObject.h" | |||
#include "btCollisionWorld.h" | |||
#include "BulletCollision/CollisionShapes/btConvexShape.h" | |||
#include "LinearMath/btAabbUtil2.h" | |||
btGhostObject::btGhostObject() | |||
{ | |||
m_internalType = CO_GHOST_OBJECT; | |||
} | |||
btGhostObject::~btGhostObject() | |||
{ | |||
///btGhostObject should have been removed from the world, so no overlapping objects | |||
btAssert(!m_overlappingObjects.size()); | |||
} | |||
void btGhostObject::addOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btBroadphaseProxy* thisProxy) | |||
{ | |||
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject; | |||
btAssert(otherObject); | |||
///if this linearSearch becomes too slow (too many overlapping objects) we should add a more appropriate data structure | |||
int index = m_overlappingObjects.findLinearSearch(otherObject); | |||
if (index==m_overlappingObjects.size()) | |||
{ | |||
//not found | |||
m_overlappingObjects.push_back(otherObject); | |||
} | |||
} | |||
void btGhostObject::removeOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher,btBroadphaseProxy* thisProxy) | |||
{ | |||
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject; | |||
btAssert(otherObject); | |||
int index = m_overlappingObjects.findLinearSearch(otherObject); | |||
if (index<m_overlappingObjects.size()) | |||
{ | |||
m_overlappingObjects[index] = m_overlappingObjects[m_overlappingObjects.size()-1]; | |||
m_overlappingObjects.pop_back(); | |||
} | |||
} | |||
btPairCachingGhostObject::btPairCachingGhostObject() | |||
{ | |||
m_hashPairCache = new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache(); | |||
} | |||
btPairCachingGhostObject::~btPairCachingGhostObject() | |||
{ | |||
m_hashPairCache->~btHashedOverlappingPairCache(); | |||
btAlignedFree( m_hashPairCache ); | |||
} | |||
void btPairCachingGhostObject::addOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btBroadphaseProxy* thisProxy) | |||
{ | |||
btBroadphaseProxy*actualThisProxy = thisProxy ? thisProxy : getBroadphaseHandle(); | |||
btAssert(actualThisProxy); | |||
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject; | |||
btAssert(otherObject); | |||
int index = m_overlappingObjects.findLinearSearch(otherObject); | |||
if (index==m_overlappingObjects.size()) | |||
{ | |||
m_overlappingObjects.push_back(otherObject); | |||
m_hashPairCache->addOverlappingPair(actualThisProxy,otherProxy); | |||
} | |||
} | |||
void btPairCachingGhostObject::removeOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher,btBroadphaseProxy* thisProxy1) | |||
{ | |||
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject; | |||
btBroadphaseProxy* actualThisProxy = thisProxy1 ? thisProxy1 : getBroadphaseHandle(); | |||
btAssert(actualThisProxy); | |||
btAssert(otherObject); | |||
int index = m_overlappingObjects.findLinearSearch(otherObject); | |||
if (index<m_overlappingObjects.size()) | |||
{ | |||
m_overlappingObjects[index] = m_overlappingObjects[m_overlappingObjects.size()-1]; | |||
m_overlappingObjects.pop_back(); | |||
m_hashPairCache->removeOverlappingPair(actualThisProxy,otherProxy,dispatcher); | |||
} | |||
} | |||
void btGhostObject::convexSweepTest(const btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, btCollisionWorld::ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration) const | |||
{ | |||
btTransform convexFromTrans,convexToTrans; | |||
convexFromTrans = convexFromWorld; | |||
convexToTrans = convexToWorld; | |||
btVector3 castShapeAabbMin, castShapeAabbMax; | |||
/* Compute AABB that encompasses angular movement */ | |||
{ | |||
btVector3 linVel, angVel; | |||
btTransformUtil::calculateVelocity (convexFromTrans, convexToTrans, 1.0, linVel, angVel); | |||
btTransform R; | |||
R.setIdentity (); | |||
R.setRotation (convexFromTrans.getRotation()); | |||
castShape->calculateTemporalAabb (R, linVel, angVel, 1.0, castShapeAabbMin, castShapeAabbMax); | |||
} | |||
/// 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_overlappingObjects.size();i++) | |||
{ | |||
btCollisionObject* collisionObject= m_overlappingObjects[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)) | |||
{ | |||
btCollisionWorld::objectQuerySingle(castShape, convexFromTrans,convexToTrans, | |||
collisionObject, | |||
collisionObject->getCollisionShape(), | |||
collisionObject->getWorldTransform(), | |||
resultCallback, | |||
allowedCcdPenetration); | |||
} | |||
} | |||
} | |||
} | |||
void btGhostObject::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const | |||
{ | |||
btTransform rayFromTrans; | |||
rayFromTrans.setIdentity(); | |||
rayFromTrans.setOrigin(rayFromWorld); | |||
btTransform rayToTrans; | |||
rayToTrans.setIdentity(); | |||
rayToTrans.setOrigin(rayToWorld); | |||
int i; | |||
for (i=0;i<m_overlappingObjects.size();i++) | |||
{ | |||
btCollisionObject* collisionObject= m_overlappingObjects[i]; | |||
//only perform raycast if filterMask matches | |||
if(resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) | |||
{ | |||
btCollisionWorld::rayTestSingle(rayFromTrans,rayToTrans, | |||
collisionObject, | |||
collisionObject->getCollisionShape(), | |||
collisionObject->getWorldTransform(), | |||
resultCallback); | |||
} | |||
} | |||
} | |||
@@ -0,0 +1,175 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com | |||
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. | |||
*/ | |||
#ifndef BT_GHOST_OBJECT_H | |||
#define BT_GHOST_OBJECT_H | |||
#include "btCollisionObject.h" | |||
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h" | |||
#include "LinearMath/btAlignedAllocator.h" | |||
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" | |||
#include "btCollisionWorld.h" | |||
class btConvexShape; | |||
class btDispatcher; | |||
///The btGhostObject can keep track of all objects that are overlapping | |||
///By default, this overlap is based on the AABB | |||
///This is useful for creating a character controller, collision sensors/triggers, explosions etc. | |||
///We plan on adding rayTest and other queries for the btGhostObject | |||
ATTRIBUTE_ALIGNED16(class) btGhostObject : public btCollisionObject | |||
{ | |||
protected: | |||
btAlignedObjectArray<btCollisionObject*> m_overlappingObjects; | |||
public: | |||
btGhostObject(); | |||
virtual ~btGhostObject(); | |||
void convexSweepTest(const class btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, btCollisionWorld::ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration = 0.f) const; | |||
void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const; | |||
///this method is mainly for expert/internal use only. | |||
virtual void addOverlappingObjectInternal(btBroadphaseProxy* otherProxy, btBroadphaseProxy* thisProxy=0); | |||
///this method is mainly for expert/internal use only. | |||
virtual void removeOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher,btBroadphaseProxy* thisProxy=0); | |||
int getNumOverlappingObjects() const | |||
{ | |||
return m_overlappingObjects.size(); | |||
} | |||
btCollisionObject* getOverlappingObject(int index) | |||
{ | |||
return m_overlappingObjects[index]; | |||
} | |||
const btCollisionObject* getOverlappingObject(int index) const | |||
{ | |||
return m_overlappingObjects[index]; | |||
} | |||
btAlignedObjectArray<btCollisionObject*>& getOverlappingPairs() | |||
{ | |||
return m_overlappingObjects; | |||
} | |||
const btAlignedObjectArray<btCollisionObject*> getOverlappingPairs() const | |||
{ | |||
return m_overlappingObjects; | |||
} | |||
// | |||
// internal cast | |||
// | |||
static const btGhostObject* upcast(const btCollisionObject* colObj) | |||
{ | |||
if (colObj->getInternalType()==CO_GHOST_OBJECT) | |||
return (const btGhostObject*)colObj; | |||
return 0; | |||
} | |||
static btGhostObject* upcast(btCollisionObject* colObj) | |||
{ | |||
if (colObj->getInternalType()==CO_GHOST_OBJECT) | |||
return (btGhostObject*)colObj; | |||
return 0; | |||
} | |||
}; | |||
class btPairCachingGhostObject : public btGhostObject | |||
{ | |||
btHashedOverlappingPairCache* m_hashPairCache; | |||
public: | |||
btPairCachingGhostObject(); | |||
virtual ~btPairCachingGhostObject(); | |||
///this method is mainly for expert/internal use only. | |||
virtual void addOverlappingObjectInternal(btBroadphaseProxy* otherProxy, btBroadphaseProxy* thisProxy=0); | |||
virtual void removeOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher,btBroadphaseProxy* thisProxy=0); | |||
btHashedOverlappingPairCache* getOverlappingPairCache() | |||
{ | |||
return m_hashPairCache; | |||
} | |||
}; | |||
///The btGhostPairCallback interfaces and forwards adding and removal of overlapping pairs from the btBroadphaseInterface to btGhostObject. | |||
class btGhostPairCallback : public btOverlappingPairCallback | |||
{ | |||
public: | |||
btGhostPairCallback() | |||
{ | |||
} | |||
virtual ~btGhostPairCallback() | |||
{ | |||
} | |||
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) | |||
{ | |||
btCollisionObject* colObj0 = (btCollisionObject*) proxy0->m_clientObject; | |||
btCollisionObject* colObj1 = (btCollisionObject*) proxy1->m_clientObject; | |||
btGhostObject* ghost0 = btGhostObject::upcast(colObj0); | |||
btGhostObject* ghost1 = btGhostObject::upcast(colObj1); | |||
if (ghost0) | |||
ghost0->addOverlappingObjectInternal(proxy1, proxy0); | |||
if (ghost1) | |||
ghost1->addOverlappingObjectInternal(proxy0, proxy1); | |||
return 0; | |||
} | |||
virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher) | |||
{ | |||
btCollisionObject* colObj0 = (btCollisionObject*) proxy0->m_clientObject; | |||
btCollisionObject* colObj1 = (btCollisionObject*) proxy1->m_clientObject; | |||
btGhostObject* ghost0 = btGhostObject::upcast(colObj0); | |||
btGhostObject* ghost1 = btGhostObject::upcast(colObj1); | |||
if (ghost0) | |||
ghost0->removeOverlappingObjectInternal(proxy1,dispatcher,proxy0); | |||
if (ghost1) | |||
ghost1->removeOverlappingObjectInternal(proxy0,dispatcher,proxy1); | |||
return 0; | |||
} | |||
virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* /*proxy0*/,btDispatcher* /*dispatcher*/) | |||
{ | |||
btAssert(0); | |||
//need to keep track of all ghost objects and call them here | |||
//m_hashPairCache->removeOverlappingPairsContainingProxy(proxy0,dispatcher); | |||
} | |||
}; | |||
#endif | |||
@@ -0,0 +1,842 @@ | |||
#include "btInternalEdgeUtility.h" | |||
#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" | |||
#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" | |||
#include "BulletCollision/CollisionShapes/btTriangleShape.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h" | |||
#include "LinearMath/btIDebugDraw.h" | |||
//#define DEBUG_INTERNAL_EDGE | |||
#ifdef DEBUG_INTERNAL_EDGE | |||
#include <stdio.h> | |||
#endif //DEBUG_INTERNAL_EDGE | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
static btIDebugDraw* gDebugDrawer = 0; | |||
void btSetDebugDrawer(btIDebugDraw* debugDrawer) | |||
{ | |||
gDebugDrawer = debugDrawer; | |||
} | |||
static void btDebugDrawLine(const btVector3& from,const btVector3& to, const btVector3& color) | |||
{ | |||
if (gDebugDrawer) | |||
gDebugDrawer->drawLine(from,to,color); | |||
} | |||
#endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
static int btGetHash(int partId, int triangleIndex) | |||
{ | |||
int hash = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | triangleIndex; | |||
return hash; | |||
} | |||
static btScalar btGetAngle(const btVector3& edgeA, const btVector3& normalA,const btVector3& normalB) | |||
{ | |||
const btVector3 refAxis0 = edgeA; | |||
const btVector3 refAxis1 = normalA; | |||
const btVector3 swingAxis = normalB; | |||
btScalar angle = btAtan2(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1)); | |||
return angle; | |||
} | |||
struct btConnectivityProcessor : public btTriangleCallback | |||
{ | |||
int m_partIdA; | |||
int m_triangleIndexA; | |||
btVector3* m_triangleVerticesA; | |||
btTriangleInfoMap* m_triangleInfoMap; | |||
virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) | |||
{ | |||
//skip self-collisions | |||
if ((m_partIdA == partId) && (m_triangleIndexA == triangleIndex)) | |||
return; | |||
//skip duplicates (disabled for now) | |||
//if ((m_partIdA <= partId) && (m_triangleIndexA <= triangleIndex)) | |||
// return; | |||
//search for shared vertices and edges | |||
int numshared = 0; | |||
int sharedVertsA[3]={-1,-1,-1}; | |||
int sharedVertsB[3]={-1,-1,-1}; | |||
///skip degenerate triangles | |||
btScalar crossBSqr = ((triangle[1]-triangle[0]).cross(triangle[2]-triangle[0])).length2(); | |||
if (crossBSqr < m_triangleInfoMap->m_equalVertexThreshold) | |||
return; | |||
btScalar crossASqr = ((m_triangleVerticesA[1]-m_triangleVerticesA[0]).cross(m_triangleVerticesA[2]-m_triangleVerticesA[0])).length2(); | |||
///skip degenerate triangles | |||
if (crossASqr< m_triangleInfoMap->m_equalVertexThreshold) | |||
return; | |||
#if 0 | |||
printf("triangle A[0] = (%f,%f,%f)\ntriangle A[1] = (%f,%f,%f)\ntriangle A[2] = (%f,%f,%f)\n", | |||
m_triangleVerticesA[0].getX(),m_triangleVerticesA[0].getY(),m_triangleVerticesA[0].getZ(), | |||
m_triangleVerticesA[1].getX(),m_triangleVerticesA[1].getY(),m_triangleVerticesA[1].getZ(), | |||
m_triangleVerticesA[2].getX(),m_triangleVerticesA[2].getY(),m_triangleVerticesA[2].getZ()); | |||
printf("partId=%d, triangleIndex=%d\n",partId,triangleIndex); | |||
printf("triangle B[0] = (%f,%f,%f)\ntriangle B[1] = (%f,%f,%f)\ntriangle B[2] = (%f,%f,%f)\n", | |||
triangle[0].getX(),triangle[0].getY(),triangle[0].getZ(), | |||
triangle[1].getX(),triangle[1].getY(),triangle[1].getZ(), | |||
triangle[2].getX(),triangle[2].getY(),triangle[2].getZ()); | |||
#endif | |||
for (int i=0;i<3;i++) | |||
{ | |||
for (int j=0;j<3;j++) | |||
{ | |||
if ( (m_triangleVerticesA[i]-triangle[j]).length2() < m_triangleInfoMap->m_equalVertexThreshold) | |||
{ | |||
sharedVertsA[numshared] = i; | |||
sharedVertsB[numshared] = j; | |||
numshared++; | |||
///degenerate case | |||
if(numshared >= 3) | |||
return; | |||
} | |||
} | |||
///degenerate case | |||
if(numshared >= 3) | |||
return; | |||
} | |||
switch (numshared) | |||
{ | |||
case 0: | |||
{ | |||
break; | |||
} | |||
case 1: | |||
{ | |||
//shared vertex | |||
break; | |||
} | |||
case 2: | |||
{ | |||
//shared edge | |||
//we need to make sure the edge is in the order V2V0 and not V0V2 so that the signs are correct | |||
if (sharedVertsA[0] == 0 && sharedVertsA[1] == 2) | |||
{ | |||
sharedVertsA[0] = 2; | |||
sharedVertsA[1] = 0; | |||
int tmp = sharedVertsB[1]; | |||
sharedVertsB[1] = sharedVertsB[0]; | |||
sharedVertsB[0] = tmp; | |||
} | |||
int hash = btGetHash(m_partIdA,m_triangleIndexA); | |||
btTriangleInfo* info = m_triangleInfoMap->find(hash); | |||
if (!info) | |||
{ | |||
btTriangleInfo tmp; | |||
m_triangleInfoMap->insert(hash,tmp); | |||
info = m_triangleInfoMap->find(hash); | |||
} | |||
int sumvertsA = sharedVertsA[0]+sharedVertsA[1]; | |||
int otherIndexA = 3-sumvertsA; | |||
btVector3 edge(m_triangleVerticesA[sharedVertsA[1]]-m_triangleVerticesA[sharedVertsA[0]]); | |||
btTriangleShape tA(m_triangleVerticesA[0],m_triangleVerticesA[1],m_triangleVerticesA[2]); | |||
int otherIndexB = 3-(sharedVertsB[0]+sharedVertsB[1]); | |||
btTriangleShape tB(triangle[sharedVertsB[1]],triangle[sharedVertsB[0]],triangle[otherIndexB]); | |||
//btTriangleShape tB(triangle[0],triangle[1],triangle[2]); | |||
btVector3 normalA; | |||
btVector3 normalB; | |||
tA.calcNormal(normalA); | |||
tB.calcNormal(normalB); | |||
edge.normalize(); | |||
btVector3 edgeCrossA = edge.cross(normalA).normalize(); | |||
{ | |||
btVector3 tmp = m_triangleVerticesA[otherIndexA]-m_triangleVerticesA[sharedVertsA[0]]; | |||
if (edgeCrossA.dot(tmp) < 0) | |||
{ | |||
edgeCrossA*=-1; | |||
} | |||
} | |||
btVector3 edgeCrossB = edge.cross(normalB).normalize(); | |||
{ | |||
btVector3 tmp = triangle[otherIndexB]-triangle[sharedVertsB[0]]; | |||
if (edgeCrossB.dot(tmp) < 0) | |||
{ | |||
edgeCrossB*=-1; | |||
} | |||
} | |||
btScalar angle2 = 0; | |||
btScalar ang4 = 0.f; | |||
btVector3 calculatedEdge = edgeCrossA.cross(edgeCrossB); | |||
btScalar len2 = calculatedEdge.length2(); | |||
btScalar correctedAngle(0); | |||
btVector3 calculatedNormalB = normalA; | |||
bool isConvex = false; | |||
if (len2<m_triangleInfoMap->m_planarEpsilon) | |||
{ | |||
angle2 = 0.f; | |||
ang4 = 0.f; | |||
} else | |||
{ | |||
calculatedEdge.normalize(); | |||
btVector3 calculatedNormalA = calculatedEdge.cross(edgeCrossA); | |||
calculatedNormalA.normalize(); | |||
angle2 = btGetAngle(calculatedNormalA,edgeCrossA,edgeCrossB); | |||
ang4 = SIMD_PI-angle2; | |||
btScalar dotA = normalA.dot(edgeCrossB); | |||
///@todo: check if we need some epsilon, due to floating point imprecision | |||
isConvex = (dotA<0.); | |||
correctedAngle = isConvex ? ang4 : -ang4; | |||
btQuaternion orn2(calculatedEdge,-correctedAngle); | |||
calculatedNormalB = btMatrix3x3(orn2)*normalA; | |||
} | |||
//alternatively use | |||
//btVector3 calculatedNormalB2 = quatRotate(orn,normalA); | |||
switch (sumvertsA) | |||
{ | |||
case 1: | |||
{ | |||
btVector3 edge = m_triangleVerticesA[0]-m_triangleVerticesA[1]; | |||
btQuaternion orn(edge,-correctedAngle); | |||
btVector3 computedNormalB = quatRotate(orn,normalA); | |||
btScalar bla = computedNormalB.dot(normalB); | |||
if (bla<0) | |||
{ | |||
computedNormalB*=-1; | |||
info->m_flags |= TRI_INFO_V0V1_SWAP_NORMALB; | |||
} | |||
#ifdef DEBUG_INTERNAL_EDGE | |||
if ((computedNormalB-normalB).length()>0.0001) | |||
{ | |||
printf("warning: normals not identical\n"); | |||
} | |||
#endif//DEBUG_INTERNAL_EDGE | |||
info->m_edgeV0V1Angle = -correctedAngle; | |||
if (isConvex) | |||
info->m_flags |= TRI_INFO_V0V1_CONVEX; | |||
break; | |||
} | |||
case 2: | |||
{ | |||
btVector3 edge = m_triangleVerticesA[2]-m_triangleVerticesA[0]; | |||
btQuaternion orn(edge,-correctedAngle); | |||
btVector3 computedNormalB = quatRotate(orn,normalA); | |||
if (computedNormalB.dot(normalB)<0) | |||
{ | |||
computedNormalB*=-1; | |||
info->m_flags |= TRI_INFO_V2V0_SWAP_NORMALB; | |||
} | |||
#ifdef DEBUG_INTERNAL_EDGE | |||
if ((computedNormalB-normalB).length()>0.0001) | |||
{ | |||
printf("warning: normals not identical\n"); | |||
} | |||
#endif //DEBUG_INTERNAL_EDGE | |||
info->m_edgeV2V0Angle = -correctedAngle; | |||
if (isConvex) | |||
info->m_flags |= TRI_INFO_V2V0_CONVEX; | |||
break; | |||
} | |||
case 3: | |||
{ | |||
btVector3 edge = m_triangleVerticesA[1]-m_triangleVerticesA[2]; | |||
btQuaternion orn(edge,-correctedAngle); | |||
btVector3 computedNormalB = quatRotate(orn,normalA); | |||
if (computedNormalB.dot(normalB)<0) | |||
{ | |||
info->m_flags |= TRI_INFO_V1V2_SWAP_NORMALB; | |||
computedNormalB*=-1; | |||
} | |||
#ifdef DEBUG_INTERNAL_EDGE | |||
if ((computedNormalB-normalB).length()>0.0001) | |||
{ | |||
printf("warning: normals not identical\n"); | |||
} | |||
#endif //DEBUG_INTERNAL_EDGE | |||
info->m_edgeV1V2Angle = -correctedAngle; | |||
if (isConvex) | |||
info->m_flags |= TRI_INFO_V1V2_CONVEX; | |||
break; | |||
} | |||
} | |||
break; | |||
} | |||
default: | |||
{ | |||
// printf("warning: duplicate triangle\n"); | |||
} | |||
} | |||
} | |||
}; | |||
///////////////////////////////////////////////////////// | |||
///////////////////////////////////////////////////////// | |||
void btGenerateInternalEdgeInfo (btBvhTriangleMeshShape*trimeshShape, btTriangleInfoMap* triangleInfoMap) | |||
{ | |||
//the user pointer shouldn't already be used for other purposes, we intend to store connectivity info there! | |||
if (trimeshShape->getTriangleInfoMap()) | |||
return; | |||
trimeshShape->setTriangleInfoMap(triangleInfoMap); | |||
btStridingMeshInterface* meshInterface = trimeshShape->getMeshInterface(); | |||
const btVector3& meshScaling = meshInterface->getScaling(); | |||
for (int partId = 0; partId< meshInterface->getNumSubParts();partId++) | |||
{ | |||
const unsigned char *vertexbase = 0; | |||
int numverts = 0; | |||
PHY_ScalarType type = PHY_INTEGER; | |||
int stride = 0; | |||
const unsigned char *indexbase = 0; | |||
int indexstride = 0; | |||
int numfaces = 0; | |||
PHY_ScalarType indicestype = PHY_INTEGER; | |||
//PHY_ScalarType indexType=0; | |||
btVector3 triangleVerts[3]; | |||
meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase,numverts, type,stride,&indexbase,indexstride,numfaces,indicestype,partId); | |||
btVector3 aabbMin,aabbMax; | |||
for (int triangleIndex = 0 ; triangleIndex < numfaces;triangleIndex++) | |||
{ | |||
unsigned int* gfxbase = (unsigned int*)(indexbase+triangleIndex*indexstride); | |||
for (int j=2;j>=0;j--) | |||
{ | |||
int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; | |||
if (type == PHY_FLOAT) | |||
{ | |||
float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); | |||
triangleVerts[j] = btVector3( | |||
graphicsbase[0]*meshScaling.getX(), | |||
graphicsbase[1]*meshScaling.getY(), | |||
graphicsbase[2]*meshScaling.getZ()); | |||
} | |||
else | |||
{ | |||
double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); | |||
triangleVerts[j] = btVector3( btScalar(graphicsbase[0]*meshScaling.getX()), btScalar(graphicsbase[1]*meshScaling.getY()), btScalar(graphicsbase[2]*meshScaling.getZ())); | |||
} | |||
} | |||
aabbMin.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); | |||
aabbMax.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); | |||
aabbMin.setMin(triangleVerts[0]); | |||
aabbMax.setMax(triangleVerts[0]); | |||
aabbMin.setMin(triangleVerts[1]); | |||
aabbMax.setMax(triangleVerts[1]); | |||
aabbMin.setMin(triangleVerts[2]); | |||
aabbMax.setMax(triangleVerts[2]); | |||
btConnectivityProcessor connectivityProcessor; | |||
connectivityProcessor.m_partIdA = partId; | |||
connectivityProcessor.m_triangleIndexA = triangleIndex; | |||
connectivityProcessor.m_triangleVerticesA = &triangleVerts[0]; | |||
connectivityProcessor.m_triangleInfoMap = triangleInfoMap; | |||
trimeshShape->processAllTriangles(&connectivityProcessor,aabbMin,aabbMax); | |||
} | |||
} | |||
} | |||
// Given a point and a line segment (defined by two points), compute the closest point | |||
// in the line. Cap the point at the endpoints of the line segment. | |||
void btNearestPointInLineSegment(const btVector3 &point, const btVector3& line0, const btVector3& line1, btVector3& nearestPoint) | |||
{ | |||
btVector3 lineDelta = line1 - line0; | |||
// Handle degenerate lines | |||
if ( lineDelta.fuzzyZero()) | |||
{ | |||
nearestPoint = line0; | |||
} | |||
else | |||
{ | |||
btScalar delta = (point-line0).dot(lineDelta) / (lineDelta).dot(lineDelta); | |||
// Clamp the point to conform to the segment's endpoints | |||
if ( delta < 0 ) | |||
delta = 0; | |||
else if ( delta > 1 ) | |||
delta = 1; | |||
nearestPoint = line0 + lineDelta*delta; | |||
} | |||
} | |||
bool btClampNormal(const btVector3& edge,const btVector3& tri_normal_org,const btVector3& localContactNormalOnB, btScalar correctedEdgeAngle, btVector3 & clampedLocalNormal) | |||
{ | |||
btVector3 tri_normal = tri_normal_org; | |||
//we only have a local triangle normal, not a local contact normal -> only normal in world space... | |||
//either compute the current angle all in local space, or all in world space | |||
btVector3 edgeCross = edge.cross(tri_normal).normalize(); | |||
btScalar curAngle = btGetAngle(edgeCross,tri_normal,localContactNormalOnB); | |||
if (correctedEdgeAngle<0) | |||
{ | |||
if (curAngle < correctedEdgeAngle) | |||
{ | |||
btScalar diffAngle = correctedEdgeAngle-curAngle; | |||
btQuaternion rotation(edge,diffAngle ); | |||
clampedLocalNormal = btMatrix3x3(rotation)*localContactNormalOnB; | |||
return true; | |||
} | |||
} | |||
if (correctedEdgeAngle>=0) | |||
{ | |||
if (curAngle > correctedEdgeAngle) | |||
{ | |||
btScalar diffAngle = correctedEdgeAngle-curAngle; | |||
btQuaternion rotation(edge,diffAngle ); | |||
clampedLocalNormal = btMatrix3x3(rotation)*localContactNormalOnB; | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
/// Changes a btManifoldPoint collision normal to the normal from the mesh. | |||
void btAdjustInternalEdgeContacts(btManifoldPoint& cp, const btCollisionObject* colObj0,const btCollisionObject* colObj1, int partId0, int index0, int normalAdjustFlags) | |||
{ | |||
//btAssert(colObj0->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE); | |||
if (colObj0->getCollisionShape()->getShapeType() != TRIANGLE_SHAPE_PROXYTYPE) | |||
return; | |||
btBvhTriangleMeshShape* trimesh = 0; | |||
if( colObj0->getRootCollisionShape()->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE ) | |||
trimesh = ((btScaledBvhTriangleMeshShape*)colObj0->getRootCollisionShape())->getChildShape(); | |||
else | |||
trimesh = (btBvhTriangleMeshShape*)colObj0->getRootCollisionShape(); | |||
btTriangleInfoMap* triangleInfoMapPtr = (btTriangleInfoMap*) trimesh->getTriangleInfoMap(); | |||
if (!triangleInfoMapPtr) | |||
return; | |||
int hash = btGetHash(partId0,index0); | |||
btTriangleInfo* info = triangleInfoMapPtr->find(hash); | |||
if (!info) | |||
return; | |||
btScalar frontFacing = (normalAdjustFlags & BT_TRIANGLE_CONVEX_BACKFACE_MODE)==0? 1.f : -1.f; | |||
const btTriangleShape* tri_shape = static_cast<const btTriangleShape*>(colObj0->getCollisionShape()); | |||
btVector3 v0,v1,v2; | |||
tri_shape->getVertex(0,v0); | |||
tri_shape->getVertex(1,v1); | |||
tri_shape->getVertex(2,v2); | |||
btVector3 center = (v0+v1+v2)*btScalar(1./3.); | |||
btVector3 red(1,0,0), green(0,1,0),blue(0,0,1),white(1,1,1),black(0,0,0); | |||
btVector3 tri_normal; | |||
tri_shape->calcNormal(tri_normal); | |||
//btScalar dot = tri_normal.dot(cp.m_normalWorldOnB); | |||
btVector3 nearest; | |||
btNearestPointInLineSegment(cp.m_localPointB,v0,v1,nearest); | |||
btVector3 contact = cp.m_localPointB; | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
const btTransform& tr = colObj0->getWorldTransform(); | |||
btDebugDrawLine(tr*nearest,tr*cp.m_localPointB,red); | |||
#endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
bool isNearEdge = false; | |||
int numConcaveEdgeHits = 0; | |||
int numConvexEdgeHits = 0; | |||
btVector3 localContactNormalOnB = colObj0->getWorldTransform().getBasis().transpose() * cp.m_normalWorldOnB; | |||
localContactNormalOnB.normalize();//is this necessary? | |||
// Get closest edge | |||
int bestedge=-1; | |||
btScalar disttobestedge=BT_LARGE_FLOAT; | |||
// | |||
// Edge 0 -> 1 | |||
if (btFabs(info->m_edgeV0V1Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) | |||
{ | |||
btVector3 nearest; | |||
btNearestPointInLineSegment( cp.m_localPointB, v0, v1, nearest ); | |||
btScalar len=(contact-nearest).length(); | |||
// | |||
if( len < disttobestedge ) | |||
{ | |||
bestedge=0; | |||
disttobestedge=len; | |||
} | |||
} | |||
// Edge 1 -> 2 | |||
if (btFabs(info->m_edgeV1V2Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) | |||
{ | |||
btVector3 nearest; | |||
btNearestPointInLineSegment( cp.m_localPointB, v1, v2, nearest ); | |||
btScalar len=(contact-nearest).length(); | |||
// | |||
if( len < disttobestedge ) | |||
{ | |||
bestedge=1; | |||
disttobestedge=len; | |||
} | |||
} | |||
// Edge 2 -> 0 | |||
if (btFabs(info->m_edgeV2V0Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) | |||
{ | |||
btVector3 nearest; | |||
btNearestPointInLineSegment( cp.m_localPointB, v2, v0, nearest ); | |||
btScalar len=(contact-nearest).length(); | |||
// | |||
if( len < disttobestedge ) | |||
{ | |||
bestedge=2; | |||
disttobestedge=len; | |||
} | |||
} | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btVector3 upfix=tri_normal * btVector3(0.1f,0.1f,0.1f); | |||
btDebugDrawLine(tr * v0 + upfix, tr * v1 + upfix, red ); | |||
#endif | |||
if (btFabs(info->m_edgeV0V1Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) | |||
{ | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btDebugDrawLine(tr*contact,tr*(contact+cp.m_normalWorldOnB*10),black); | |||
#endif | |||
btScalar len = (contact-nearest).length(); | |||
if(len<triangleInfoMapPtr->m_edgeDistanceThreshold) | |||
if( bestedge==0 ) | |||
{ | |||
btVector3 edge(v0-v1); | |||
isNearEdge = true; | |||
if (info->m_edgeV0V1Angle==btScalar(0)) | |||
{ | |||
numConcaveEdgeHits++; | |||
} else | |||
{ | |||
bool isEdgeConvex = (info->m_flags & TRI_INFO_V0V1_CONVEX); | |||
btScalar swapFactor = isEdgeConvex ? btScalar(1) : btScalar(-1); | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btDebugDrawLine(tr*nearest,tr*(nearest+swapFactor*tri_normal*10),white); | |||
#endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btVector3 nA = swapFactor * tri_normal; | |||
btQuaternion orn(edge,info->m_edgeV0V1Angle); | |||
btVector3 computedNormalB = quatRotate(orn,tri_normal); | |||
if (info->m_flags & TRI_INFO_V0V1_SWAP_NORMALB) | |||
computedNormalB*=-1; | |||
btVector3 nB = swapFactor*computedNormalB; | |||
btScalar NdotA = localContactNormalOnB.dot(nA); | |||
btScalar NdotB = localContactNormalOnB.dot(nB); | |||
bool backFacingNormal = (NdotA< triangleInfoMapPtr->m_convexEpsilon) && (NdotB<triangleInfoMapPtr->m_convexEpsilon); | |||
#ifdef DEBUG_INTERNAL_EDGE | |||
{ | |||
btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+tr.getBasis()*(nB*20),red); | |||
} | |||
#endif //DEBUG_INTERNAL_EDGE | |||
if (backFacingNormal) | |||
{ | |||
numConcaveEdgeHits++; | |||
} | |||
else | |||
{ | |||
numConvexEdgeHits++; | |||
btVector3 clampedLocalNormal; | |||
bool isClamped = btClampNormal(edge,swapFactor*tri_normal,localContactNormalOnB, info->m_edgeV0V1Angle,clampedLocalNormal); | |||
if (isClamped) | |||
{ | |||
if (((normalAdjustFlags & BT_TRIANGLE_CONVEX_DOUBLE_SIDED)!=0) || (clampedLocalNormal.dot(frontFacing*tri_normal)>0)) | |||
{ | |||
btVector3 newNormal = colObj0->getWorldTransform().getBasis() * clampedLocalNormal; | |||
// cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB); | |||
cp.m_normalWorldOnB = newNormal; | |||
// Reproject collision point along normal. (what about cp.m_distance1?) | |||
cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; | |||
cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
btNearestPointInLineSegment(contact,v1,v2,nearest); | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btDebugDrawLine(tr*nearest,tr*cp.m_localPointB,green); | |||
#endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btDebugDrawLine(tr * v1 + upfix, tr * v2 + upfix , green ); | |||
#endif | |||
if (btFabs(info->m_edgeV1V2Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) | |||
{ | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btDebugDrawLine(tr*contact,tr*(contact+cp.m_normalWorldOnB*10),black); | |||
#endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btScalar len = (contact-nearest).length(); | |||
if(len<triangleInfoMapPtr->m_edgeDistanceThreshold) | |||
if( bestedge==1 ) | |||
{ | |||
isNearEdge = true; | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btDebugDrawLine(tr*nearest,tr*(nearest+tri_normal*10),white); | |||
#endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btVector3 edge(v1-v2); | |||
isNearEdge = true; | |||
if (info->m_edgeV1V2Angle == btScalar(0)) | |||
{ | |||
numConcaveEdgeHits++; | |||
} else | |||
{ | |||
bool isEdgeConvex = (info->m_flags & TRI_INFO_V1V2_CONVEX)!=0; | |||
btScalar swapFactor = isEdgeConvex ? btScalar(1) : btScalar(-1); | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btDebugDrawLine(tr*nearest,tr*(nearest+swapFactor*tri_normal*10),white); | |||
#endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btVector3 nA = swapFactor * tri_normal; | |||
btQuaternion orn(edge,info->m_edgeV1V2Angle); | |||
btVector3 computedNormalB = quatRotate(orn,tri_normal); | |||
if (info->m_flags & TRI_INFO_V1V2_SWAP_NORMALB) | |||
computedNormalB*=-1; | |||
btVector3 nB = swapFactor*computedNormalB; | |||
#ifdef DEBUG_INTERNAL_EDGE | |||
{ | |||
btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+tr.getBasis()*(nB*20),red); | |||
} | |||
#endif //DEBUG_INTERNAL_EDGE | |||
btScalar NdotA = localContactNormalOnB.dot(nA); | |||
btScalar NdotB = localContactNormalOnB.dot(nB); | |||
bool backFacingNormal = (NdotA< triangleInfoMapPtr->m_convexEpsilon) && (NdotB<triangleInfoMapPtr->m_convexEpsilon); | |||
if (backFacingNormal) | |||
{ | |||
numConcaveEdgeHits++; | |||
} | |||
else | |||
{ | |||
numConvexEdgeHits++; | |||
btVector3 localContactNormalOnB = colObj0->getWorldTransform().getBasis().transpose() * cp.m_normalWorldOnB; | |||
btVector3 clampedLocalNormal; | |||
bool isClamped = btClampNormal(edge,swapFactor*tri_normal,localContactNormalOnB, info->m_edgeV1V2Angle,clampedLocalNormal); | |||
if (isClamped) | |||
{ | |||
if (((normalAdjustFlags & BT_TRIANGLE_CONVEX_DOUBLE_SIDED)!=0) || (clampedLocalNormal.dot(frontFacing*tri_normal)>0)) | |||
{ | |||
btVector3 newNormal = colObj0->getWorldTransform().getBasis() * clampedLocalNormal; | |||
// cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB); | |||
cp.m_normalWorldOnB = newNormal; | |||
// Reproject collision point along normal. | |||
cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; | |||
cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
btNearestPointInLineSegment(contact,v2,v0,nearest); | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btDebugDrawLine(tr*nearest,tr*cp.m_localPointB,blue); | |||
#endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btDebugDrawLine(tr * v2 + upfix, tr * v0 + upfix , blue ); | |||
#endif | |||
if (btFabs(info->m_edgeV2V0Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) | |||
{ | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btDebugDrawLine(tr*contact,tr*(contact+cp.m_normalWorldOnB*10),black); | |||
#endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btScalar len = (contact-nearest).length(); | |||
if(len<triangleInfoMapPtr->m_edgeDistanceThreshold) | |||
if( bestedge==2 ) | |||
{ | |||
isNearEdge = true; | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btDebugDrawLine(tr*nearest,tr*(nearest+tri_normal*10),white); | |||
#endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btVector3 edge(v2-v0); | |||
if (info->m_edgeV2V0Angle==btScalar(0)) | |||
{ | |||
numConcaveEdgeHits++; | |||
} else | |||
{ | |||
bool isEdgeConvex = (info->m_flags & TRI_INFO_V2V0_CONVEX)!=0; | |||
btScalar swapFactor = isEdgeConvex ? btScalar(1) : btScalar(-1); | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btDebugDrawLine(tr*nearest,tr*(nearest+swapFactor*tri_normal*10),white); | |||
#endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
btVector3 nA = swapFactor * tri_normal; | |||
btQuaternion orn(edge,info->m_edgeV2V0Angle); | |||
btVector3 computedNormalB = quatRotate(orn,tri_normal); | |||
if (info->m_flags & TRI_INFO_V2V0_SWAP_NORMALB) | |||
computedNormalB*=-1; | |||
btVector3 nB = swapFactor*computedNormalB; | |||
#ifdef DEBUG_INTERNAL_EDGE | |||
{ | |||
btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+tr.getBasis()*(nB*20),red); | |||
} | |||
#endif //DEBUG_INTERNAL_EDGE | |||
btScalar NdotA = localContactNormalOnB.dot(nA); | |||
btScalar NdotB = localContactNormalOnB.dot(nB); | |||
bool backFacingNormal = (NdotA< triangleInfoMapPtr->m_convexEpsilon) && (NdotB<triangleInfoMapPtr->m_convexEpsilon); | |||
if (backFacingNormal) | |||
{ | |||
numConcaveEdgeHits++; | |||
} | |||
else | |||
{ | |||
numConvexEdgeHits++; | |||
// printf("hitting convex edge\n"); | |||
btVector3 localContactNormalOnB = colObj0->getWorldTransform().getBasis().transpose() * cp.m_normalWorldOnB; | |||
btVector3 clampedLocalNormal; | |||
bool isClamped = btClampNormal(edge,swapFactor*tri_normal,localContactNormalOnB,info->m_edgeV2V0Angle,clampedLocalNormal); | |||
if (isClamped) | |||
{ | |||
if (((normalAdjustFlags & BT_TRIANGLE_CONVEX_DOUBLE_SIDED)!=0) || (clampedLocalNormal.dot(frontFacing*tri_normal)>0)) | |||
{ | |||
btVector3 newNormal = colObj0->getWorldTransform().getBasis() * clampedLocalNormal; | |||
// cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB); | |||
cp.m_normalWorldOnB = newNormal; | |||
// Reproject collision point along normal. | |||
cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; | |||
cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
#ifdef DEBUG_INTERNAL_EDGE | |||
{ | |||
btVector3 color(0,1,1); | |||
btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+cp.m_normalWorldOnB*10,color); | |||
} | |||
#endif //DEBUG_INTERNAL_EDGE | |||
if (isNearEdge) | |||
{ | |||
if (numConcaveEdgeHits>0) | |||
{ | |||
if ((normalAdjustFlags & BT_TRIANGLE_CONCAVE_DOUBLE_SIDED)!=0) | |||
{ | |||
//fix tri_normal so it pointing the same direction as the current local contact normal | |||
if (tri_normal.dot(localContactNormalOnB) < 0) | |||
{ | |||
tri_normal *= -1; | |||
} | |||
cp.m_normalWorldOnB = colObj0->getWorldTransform().getBasis()*tri_normal; | |||
} else | |||
{ | |||
btVector3 newNormal = tri_normal *frontFacing; | |||
//if the tri_normal is pointing opposite direction as the current local contact normal, skip it | |||
btScalar d = newNormal.dot(localContactNormalOnB) ; | |||
if (d< 0) | |||
{ | |||
return; | |||
} | |||
//modify the normal to be the triangle normal (or backfacing normal) | |||
cp.m_normalWorldOnB = colObj0->getWorldTransform().getBasis() *newNormal; | |||
} | |||
// Reproject collision point along normal. | |||
cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; | |||
cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); | |||
} | |||
} | |||
} |
@@ -0,0 +1,46 @@ | |||
#ifndef BT_INTERNAL_EDGE_UTILITY_H | |||
#define BT_INTERNAL_EDGE_UTILITY_H | |||
#include "LinearMath/btHashMap.h" | |||
#include "LinearMath/btVector3.h" | |||
#include "BulletCollision/CollisionShapes/btTriangleInfoMap.h" | |||
///The btInternalEdgeUtility helps to avoid or reduce artifacts due to wrong collision normals caused by internal edges. | |||
///See also http://code.google.com/p/bullet/issues/detail?id=27 | |||
class btBvhTriangleMeshShape; | |||
class btCollisionObject; | |||
class btManifoldPoint; | |||
class btIDebugDraw; | |||
enum btInternalEdgeAdjustFlags | |||
{ | |||
BT_TRIANGLE_CONVEX_BACKFACE_MODE = 1, | |||
BT_TRIANGLE_CONCAVE_DOUBLE_SIDED = 2, //double sided options are experimental, single sided is recommended | |||
BT_TRIANGLE_CONVEX_DOUBLE_SIDED = 4 | |||
}; | |||
///Call btGenerateInternalEdgeInfo to create triangle info, store in the shape 'userInfo' | |||
void btGenerateInternalEdgeInfo (btBvhTriangleMeshShape*trimeshShape, btTriangleInfoMap* triangleInfoMap); | |||
///Call the btFixMeshNormal to adjust the collision normal, using the triangle info map (generated using btGenerateInternalEdgeInfo) | |||
///If this info map is missing, or the triangle is not store in this map, nothing will be done | |||
void btAdjustInternalEdgeContacts(btManifoldPoint& cp, const btCollisionObject* trimeshColObj0,const btCollisionObject* otherColObj1, int partId0, int index0, int normalAdjustFlags = 0); | |||
///Enable the BT_INTERNAL_EDGE_DEBUG_DRAW define and call btSetDebugDrawer, to get visual info to see if the internal edge utility works properly. | |||
///If the utility doesn't work properly, you might have to adjust the threshold values in btTriangleInfoMap | |||
//#define BT_INTERNAL_EDGE_DEBUG_DRAW | |||
#ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
void btSetDebugDrawer(btIDebugDraw* debugDrawer); | |||
#endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
#endif //BT_INTERNAL_EDGE_UTILITY_H | |||
@@ -0,0 +1,135 @@ | |||
/* | |||
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 "btManifoldResult.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
///This is to allow MaterialCombiner/Custom Friction/Restitution values | |||
ContactAddedCallback gContactAddedCallback=0; | |||
///User can override this material combiner by implementing gContactAddedCallback and setting body0->m_collisionFlags |= btCollisionObject::customMaterialCallback; | |||
inline btScalar calculateCombinedFriction(const btCollisionObject* body0,const btCollisionObject* body1) | |||
{ | |||
btScalar friction = body0->getFriction() * body1->getFriction(); | |||
const btScalar MAX_FRICTION = btScalar(10.); | |||
if (friction < -MAX_FRICTION) | |||
friction = -MAX_FRICTION; | |||
if (friction > MAX_FRICTION) | |||
friction = MAX_FRICTION; | |||
return friction; | |||
} | |||
inline btScalar calculateCombinedRestitution(const btCollisionObject* body0,const btCollisionObject* body1) | |||
{ | |||
return body0->getRestitution() * body1->getRestitution(); | |||
} | |||
btManifoldResult::btManifoldResult(btCollisionObject* body0,btCollisionObject* body1) | |||
:m_manifoldPtr(0), | |||
m_body0(body0), | |||
m_body1(body1) | |||
#ifdef DEBUG_PART_INDEX | |||
,m_partId0(-1), | |||
m_partId1(-1), | |||
m_index0(-1), | |||
m_index1(-1) | |||
#endif //DEBUG_PART_INDEX | |||
{ | |||
m_rootTransA = body0->getWorldTransform(); | |||
m_rootTransB = body1->getWorldTransform(); | |||
} | |||
void btManifoldResult::addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) | |||
{ | |||
btAssert(m_manifoldPtr); | |||
//order in manifold needs to match | |||
if (depth > m_manifoldPtr->getContactBreakingThreshold()) | |||
// if (depth > m_manifoldPtr->getContactProcessingThreshold()) | |||
return; | |||
bool isSwapped = m_manifoldPtr->getBody0() != m_body0; | |||
btVector3 pointA = pointInWorld + normalOnBInWorld * depth; | |||
btVector3 localA; | |||
btVector3 localB; | |||
if (isSwapped) | |||
{ | |||
localA = m_rootTransB.invXform(pointA ); | |||
localB = m_rootTransA.invXform(pointInWorld); | |||
} else | |||
{ | |||
localA = m_rootTransA.invXform(pointA ); | |||
localB = m_rootTransB.invXform(pointInWorld); | |||
} | |||
btManifoldPoint newPt(localA,localB,normalOnBInWorld,depth); | |||
newPt.m_positionWorldOnA = pointA; | |||
newPt.m_positionWorldOnB = pointInWorld; | |||
int insertIndex = m_manifoldPtr->getCacheEntry(newPt); | |||
newPt.m_combinedFriction = calculateCombinedFriction(m_body0,m_body1); | |||
newPt.m_combinedRestitution = calculateCombinedRestitution(m_body0,m_body1); | |||
//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; | |||
} | |||
//printf("depth=%f\n",depth); | |||
///@todo, check this for any side effects | |||
if (insertIndex >= 0) | |||
{ | |||
//const btManifoldPoint& oldPoint = m_manifoldPtr->getContactPoint(insertIndex); | |||
m_manifoldPtr->replaceContactPoint(newPt,insertIndex); | |||
} else | |||
{ | |||
insertIndex = m_manifoldPtr->addManifoldPoint(newPt); | |||
} | |||
//User can override friction and/or restitution | |||
if (gContactAddedCallback && | |||
//and if either of the two bodies requires custom material | |||
((m_body0->getCollisionFlags() & btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK) || | |||
(m_body1->getCollisionFlags() & btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK))) | |||
{ | |||
//experimental feature info, for per-triangle material etc. | |||
btCollisionObject* obj0 = isSwapped? m_body1 : m_body0; | |||
btCollisionObject* obj1 = isSwapped? m_body0 : m_body1; | |||
(*gContactAddedCallback)(m_manifoldPtr->getContactPoint(insertIndex),obj0,newPt.m_partId0,newPt.m_index0,obj1,newPt.m_partId1,newPt.m_index1); | |||
} | |||
} | |||
@@ -0,0 +1,128 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_MANIFOLD_RESULT_H | |||
#define BT_MANIFOLD_RESULT_H | |||
class btCollisionObject; | |||
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
class btManifoldPoint; | |||
#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" | |||
#include "LinearMath/btTransform.h" | |||
typedef bool (*ContactAddedCallback)(btManifoldPoint& cp, const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1); | |||
extern ContactAddedCallback gContactAddedCallback; | |||
//#define DEBUG_PART_INDEX 1 | |||
///btManifoldResult is a helper class to manage contact results. | |||
class btManifoldResult : public btDiscreteCollisionDetectorInterface::Result | |||
{ | |||
protected: | |||
btPersistentManifold* m_manifoldPtr; | |||
//we need this for compounds | |||
btTransform m_rootTransA; | |||
btTransform m_rootTransB; | |||
btCollisionObject* m_body0; | |||
btCollisionObject* m_body1; | |||
int m_partId0; | |||
int m_partId1; | |||
int m_index0; | |||
int m_index1; | |||
public: | |||
btManifoldResult() | |||
#ifdef DEBUG_PART_INDEX | |||
: | |||
m_partId0(-1), | |||
m_partId1(-1), | |||
m_index0(-1), | |||
m_index1(-1) | |||
#endif //DEBUG_PART_INDEX | |||
{ | |||
} | |||
btManifoldResult(btCollisionObject* body0,btCollisionObject* body1); | |||
virtual ~btManifoldResult() {}; | |||
void setPersistentManifold(btPersistentManifold* manifoldPtr) | |||
{ | |||
m_manifoldPtr = manifoldPtr; | |||
} | |||
const btPersistentManifold* getPersistentManifold() const | |||
{ | |||
return m_manifoldPtr; | |||
} | |||
btPersistentManifold* getPersistentManifold() | |||
{ | |||
return m_manifoldPtr; | |||
} | |||
virtual void setShapeIdentifiersA(int partId0,int index0) | |||
{ | |||
m_partId0=partId0; | |||
m_index0=index0; | |||
} | |||
virtual void setShapeIdentifiersB( int partId1,int index1) | |||
{ | |||
m_partId1=partId1; | |||
m_index1=index1; | |||
} | |||
virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth); | |||
SIMD_FORCE_INLINE void refreshContactPoints() | |||
{ | |||
btAssert(m_manifoldPtr); | |||
if (!m_manifoldPtr->getNumContacts()) | |||
return; | |||
bool isSwapped = m_manifoldPtr->getBody0() != m_body0; | |||
if (isSwapped) | |||
{ | |||
m_manifoldPtr->refreshContactPoints(m_rootTransB,m_rootTransA); | |||
} else | |||
{ | |||
m_manifoldPtr->refreshContactPoints(m_rootTransA,m_rootTransB); | |||
} | |||
} | |||
const btCollisionObject* getBody0Internal() const | |||
{ | |||
return m_body0; | |||
} | |||
const btCollisionObject* getBody1Internal() const | |||
{ | |||
return m_body1; | |||
} | |||
}; | |||
#endif //BT_MANIFOLD_RESULT_H |
@@ -0,0 +1,450 @@ | |||
/* | |||
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 "LinearMath/btScalar.h" | |||
#include "btSimulationIslandManager.h" | |||
#include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h" | |||
//#include <stdio.h> | |||
#include "LinearMath/btQuickprof.h" | |||
btSimulationIslandManager::btSimulationIslandManager(): | |||
m_splitIslands(true) | |||
{ | |||
} | |||
btSimulationIslandManager::~btSimulationIslandManager() | |||
{ | |||
} | |||
void btSimulationIslandManager::initUnionFind(int n) | |||
{ | |||
m_unionFind.reset(n); | |||
} | |||
void btSimulationIslandManager::findUnions(btDispatcher* /* dispatcher */,btCollisionWorld* colWorld) | |||
{ | |||
{ | |||
btOverlappingPairCache* pairCachePtr = colWorld->getPairCache(); | |||
const int numOverlappingPairs = pairCachePtr->getNumOverlappingPairs(); | |||
if (numOverlappingPairs) | |||
{ | |||
btBroadphasePair* pairPtr = pairCachePtr->getOverlappingPairArrayPtr(); | |||
for (int i=0;i<numOverlappingPairs;i++) | |||
{ | |||
const btBroadphasePair& collisionPair = pairPtr[i]; | |||
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject; | |||
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject; | |||
if (((colObj0) && ((colObj0)->mergesSimulationIslands())) && | |||
((colObj1) && ((colObj1)->mergesSimulationIslands()))) | |||
{ | |||
m_unionFind.unite((colObj0)->getIslandTag(), | |||
(colObj1)->getIslandTag()); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
#ifdef STATIC_SIMULATION_ISLAND_OPTIMIZATION | |||
void btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher) | |||
{ | |||
// put the index into m_controllers into m_tag | |||
int index = 0; | |||
{ | |||
int i; | |||
for (i=0;i<colWorld->getCollisionObjectArray().size(); i++) | |||
{ | |||
btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i]; | |||
//Adding filtering here | |||
if (!collisionObject->isStaticOrKinematicObject()) | |||
{ | |||
collisionObject->setIslandTag(index++); | |||
} | |||
collisionObject->setCompanionId(-1); | |||
collisionObject->setHitFraction(btScalar(1.)); | |||
} | |||
} | |||
// do the union find | |||
initUnionFind( index ); | |||
findUnions(dispatcher,colWorld); | |||
} | |||
void btSimulationIslandManager::storeIslandActivationState(btCollisionWorld* colWorld) | |||
{ | |||
// put the islandId ('find' value) into m_tag | |||
{ | |||
int index = 0; | |||
int i; | |||
for (i=0;i<colWorld->getCollisionObjectArray().size();i++) | |||
{ | |||
btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i]; | |||
if (!collisionObject->isStaticOrKinematicObject()) | |||
{ | |||
collisionObject->setIslandTag( m_unionFind.find(index) ); | |||
//Set the correct object offset in Collision Object Array | |||
m_unionFind.getElement(index).m_sz = i; | |||
collisionObject->setCompanionId(-1); | |||
index++; | |||
} else | |||
{ | |||
collisionObject->setIslandTag(-1); | |||
collisionObject->setCompanionId(-2); | |||
} | |||
} | |||
} | |||
} | |||
#else //STATIC_SIMULATION_ISLAND_OPTIMIZATION | |||
void btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher) | |||
{ | |||
initUnionFind( int (colWorld->getCollisionObjectArray().size())); | |||
// put the index into m_controllers into m_tag | |||
{ | |||
int index = 0; | |||
int i; | |||
for (i=0;i<colWorld->getCollisionObjectArray().size(); i++) | |||
{ | |||
btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i]; | |||
collisionObject->setIslandTag(index); | |||
collisionObject->setCompanionId(-1); | |||
collisionObject->setHitFraction(btScalar(1.)); | |||
index++; | |||
} | |||
} | |||
// do the union find | |||
findUnions(dispatcher,colWorld); | |||
} | |||
void btSimulationIslandManager::storeIslandActivationState(btCollisionWorld* colWorld) | |||
{ | |||
// put the islandId ('find' value) into m_tag | |||
{ | |||
int index = 0; | |||
int i; | |||
for (i=0;i<colWorld->getCollisionObjectArray().size();i++) | |||
{ | |||
btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i]; | |||
if (!collisionObject->isStaticOrKinematicObject()) | |||
{ | |||
collisionObject->setIslandTag( m_unionFind.find(index) ); | |||
collisionObject->setCompanionId(-1); | |||
} else | |||
{ | |||
collisionObject->setIslandTag(-1); | |||
collisionObject->setCompanionId(-2); | |||
} | |||
index++; | |||
} | |||
} | |||
} | |||
#endif //STATIC_SIMULATION_ISLAND_OPTIMIZATION | |||
inline int getIslandId(const btPersistentManifold* lhs) | |||
{ | |||
int islandId; | |||
const btCollisionObject* rcolObj0 = static_cast<const btCollisionObject*>(lhs->getBody0()); | |||
const btCollisionObject* rcolObj1 = static_cast<const btCollisionObject*>(lhs->getBody1()); | |||
islandId= rcolObj0->getIslandTag()>=0?rcolObj0->getIslandTag():rcolObj1->getIslandTag(); | |||
return islandId; | |||
} | |||
/// function object that routes calls to operator< | |||
class btPersistentManifoldSortPredicate | |||
{ | |||
public: | |||
SIMD_FORCE_INLINE bool operator() ( const btPersistentManifold* lhs, const btPersistentManifold* rhs ) const | |||
{ | |||
return getIslandId(lhs) < getIslandId(rhs); | |||
} | |||
}; | |||
void btSimulationIslandManager::buildIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld) | |||
{ | |||
BT_PROFILE("islandUnionFindAndQuickSort"); | |||
btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray(); | |||
m_islandmanifold.resize(0); | |||
//we are going to sort the unionfind array, and store the element id in the size | |||
//afterwards, we clean unionfind, to make sure no-one uses it anymore | |||
getUnionFind().sortIslands(); | |||
int numElem = getUnionFind().getNumElements(); | |||
int endIslandIndex=1; | |||
int startIslandIndex; | |||
//update the sleeping state for bodies, if all are sleeping | |||
for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex) | |||
{ | |||
int islandId = getUnionFind().getElement(startIslandIndex).m_id; | |||
for (endIslandIndex = startIslandIndex+1;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++) | |||
{ | |||
} | |||
//int numSleeping = 0; | |||
bool allSleeping = true; | |||
int idx; | |||
for (idx=startIslandIndex;idx<endIslandIndex;idx++) | |||
{ | |||
int i = getUnionFind().getElement(idx).m_sz; | |||
btCollisionObject* colObj0 = collisionObjects[i]; | |||
if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) | |||
{ | |||
// printf("error in island management\n"); | |||
} | |||
btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); | |||
if (colObj0->getIslandTag() == islandId) | |||
{ | |||
if (colObj0->getActivationState()== ACTIVE_TAG) | |||
{ | |||
allSleeping = false; | |||
} | |||
if (colObj0->getActivationState()== DISABLE_DEACTIVATION) | |||
{ | |||
allSleeping = false; | |||
} | |||
} | |||
} | |||
if (allSleeping) | |||
{ | |||
int idx; | |||
for (idx=startIslandIndex;idx<endIslandIndex;idx++) | |||
{ | |||
int i = getUnionFind().getElement(idx).m_sz; | |||
btCollisionObject* colObj0 = collisionObjects[i]; | |||
if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) | |||
{ | |||
// printf("error in island management\n"); | |||
} | |||
btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); | |||
if (colObj0->getIslandTag() == islandId) | |||
{ | |||
colObj0->setActivationState( ISLAND_SLEEPING ); | |||
} | |||
} | |||
} else | |||
{ | |||
int idx; | |||
for (idx=startIslandIndex;idx<endIslandIndex;idx++) | |||
{ | |||
int i = getUnionFind().getElement(idx).m_sz; | |||
btCollisionObject* colObj0 = collisionObjects[i]; | |||
if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) | |||
{ | |||
// printf("error in island management\n"); | |||
} | |||
btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); | |||
if (colObj0->getIslandTag() == islandId) | |||
{ | |||
if ( colObj0->getActivationState() == ISLAND_SLEEPING) | |||
{ | |||
colObj0->setActivationState( WANTS_DEACTIVATION); | |||
colObj0->setDeactivationTime(0.f); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
int i; | |||
int maxNumManifolds = dispatcher->getNumManifolds(); | |||
//#define SPLIT_ISLANDS 1 | |||
//#ifdef SPLIT_ISLANDS | |||
//#endif //SPLIT_ISLANDS | |||
for (i=0;i<maxNumManifolds ;i++) | |||
{ | |||
btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i); | |||
btCollisionObject* colObj0 = static_cast<btCollisionObject*>(manifold->getBody0()); | |||
btCollisionObject* colObj1 = static_cast<btCollisionObject*>(manifold->getBody1()); | |||
///@todo: check sleeping conditions! | |||
if (((colObj0) && colObj0->getActivationState() != ISLAND_SLEEPING) || | |||
((colObj1) && colObj1->getActivationState() != ISLAND_SLEEPING)) | |||
{ | |||
//kinematic objects don't merge islands, but wake up all connected objects | |||
if (colObj0->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING) | |||
{ | |||
if (colObj0->hasContactResponse()) | |||
colObj1->activate(); | |||
} | |||
if (colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING) | |||
{ | |||
if (colObj1->hasContactResponse()) | |||
colObj0->activate(); | |||
} | |||
if(m_splitIslands) | |||
{ | |||
//filtering for response | |||
if (dispatcher->needsResponse(colObj0,colObj1)) | |||
m_islandmanifold.push_back(manifold); | |||
} | |||
} | |||
} | |||
} | |||
///@todo: this is random access, it can be walked 'cache friendly'! | |||
void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld, IslandCallback* callback) | |||
{ | |||
btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray(); | |||
buildIslands(dispatcher,collisionWorld); | |||
int endIslandIndex=1; | |||
int startIslandIndex; | |||
int numElem = getUnionFind().getNumElements(); | |||
BT_PROFILE("processIslands"); | |||
if(!m_splitIslands) | |||
{ | |||
btPersistentManifold** manifold = dispatcher->getInternalManifoldPointer(); | |||
int maxNumManifolds = dispatcher->getNumManifolds(); | |||
callback->processIsland(&collisionObjects[0],collisionObjects.size(),manifold,maxNumManifolds, -1); | |||
} | |||
else | |||
{ | |||
// Sort manifolds, based on islands | |||
// Sort the vector using predicate and std::sort | |||
//std::sort(islandmanifold.begin(), islandmanifold.end(), btPersistentManifoldSortPredicate); | |||
int numManifolds = int (m_islandmanifold.size()); | |||
//tried a radix sort, but quicksort/heapsort seems still faster | |||
//@todo rewrite island management | |||
m_islandmanifold.quickSort(btPersistentManifoldSortPredicate()); | |||
//m_islandmanifold.heapSort(btPersistentManifoldSortPredicate()); | |||
//now process all active islands (sets of manifolds for now) | |||
int startManifoldIndex = 0; | |||
int endManifoldIndex = 1; | |||
//int islandId; | |||
// printf("Start Islands\n"); | |||
//traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated | |||
for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex) | |||
{ | |||
int islandId = getUnionFind().getElement(startIslandIndex).m_id; | |||
bool islandSleeping = true; | |||
for (endIslandIndex = startIslandIndex;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++) | |||
{ | |||
int i = getUnionFind().getElement(endIslandIndex).m_sz; | |||
btCollisionObject* colObj0 = collisionObjects[i]; | |||
m_islandBodies.push_back(colObj0); | |||
if (colObj0->isActive()) | |||
islandSleeping = false; | |||
} | |||
//find the accompanying contact manifold for this islandId | |||
int numIslandManifolds = 0; | |||
btPersistentManifold** startManifold = 0; | |||
if (startManifoldIndex<numManifolds) | |||
{ | |||
int curIslandId = getIslandId(m_islandmanifold[startManifoldIndex]); | |||
if (curIslandId == islandId) | |||
{ | |||
startManifold = &m_islandmanifold[startManifoldIndex]; | |||
for (endManifoldIndex = startManifoldIndex+1;(endManifoldIndex<numManifolds) && (islandId == getIslandId(m_islandmanifold[endManifoldIndex]));endManifoldIndex++) | |||
{ | |||
} | |||
/// Process the actual simulation, only if not sleeping/deactivated | |||
numIslandManifolds = endManifoldIndex-startManifoldIndex; | |||
} | |||
} | |||
if (!islandSleeping) | |||
{ | |||
callback->processIsland(&m_islandBodies[0],m_islandBodies.size(),startManifold,numIslandManifolds, islandId); | |||
// printf("Island callback of size:%d bodies, %d manifolds\n",islandBodies.size(),numIslandManifolds); | |||
} | |||
if (numIslandManifolds) | |||
{ | |||
startManifoldIndex = endManifoldIndex; | |||
} | |||
m_islandBodies.resize(0); | |||
} | |||
} // else if(!splitIslands) | |||
} |
@@ -0,0 +1,81 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_SIMULATION_ISLAND_MANAGER_H | |||
#define BT_SIMULATION_ISLAND_MANAGER_H | |||
#include "BulletCollision/CollisionDispatch/btUnionFind.h" | |||
#include "btCollisionCreateFunc.h" | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
#include "btCollisionObject.h" | |||
class btCollisionObject; | |||
class btCollisionWorld; | |||
class btDispatcher; | |||
class btPersistentManifold; | |||
///SimulationIslandManager creates and handles simulation islands, using btUnionFind | |||
class btSimulationIslandManager | |||
{ | |||
btUnionFind m_unionFind; | |||
btAlignedObjectArray<btPersistentManifold*> m_islandmanifold; | |||
btAlignedObjectArray<btCollisionObject* > m_islandBodies; | |||
bool m_splitIslands; | |||
public: | |||
btSimulationIslandManager(); | |||
virtual ~btSimulationIslandManager(); | |||
void initUnionFind(int n); | |||
btUnionFind& getUnionFind() { return m_unionFind;} | |||
virtual void updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher); | |||
virtual void storeIslandActivationState(btCollisionWorld* world); | |||
void findUnions(btDispatcher* dispatcher,btCollisionWorld* colWorld); | |||
struct IslandCallback | |||
{ | |||
virtual ~IslandCallback() {}; | |||
virtual void processIsland(btCollisionObject** bodies,int numBodies,class btPersistentManifold** manifolds,int numManifolds, int islandId) = 0; | |||
}; | |||
void buildAndProcessIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld, IslandCallback* callback); | |||
void buildIslands(btDispatcher* dispatcher,btCollisionWorld* colWorld); | |||
bool getSplitIslands() | |||
{ | |||
return m_splitIslands; | |||
} | |||
void setSplitIslands(bool doSplitIslands) | |||
{ | |||
m_splitIslands = doSplitIslands; | |||
} | |||
}; | |||
#endif //BT_SIMULATION_ISLAND_MANAGER_H | |||
@@ -0,0 +1,260 @@ | |||
/* | |||
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 "btSphereBoxCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
#include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
#include "BulletCollision/CollisionShapes/btBoxShape.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
//#include <stdio.h> | |||
btSphereBoxCollisionAlgorithm::btSphereBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped) | |||
: btActivatingCollisionAlgorithm(ci,col0,col1), | |||
m_ownManifold(false), | |||
m_manifoldPtr(mf), | |||
m_isSwapped(isSwapped) | |||
{ | |||
btCollisionObject* sphereObj = m_isSwapped? col1 : col0; | |||
btCollisionObject* boxObj = m_isSwapped? col0 : col1; | |||
if (!m_manifoldPtr && m_dispatcher->needsCollision(sphereObj,boxObj)) | |||
{ | |||
m_manifoldPtr = m_dispatcher->getNewManifold(sphereObj,boxObj); | |||
m_ownManifold = true; | |||
} | |||
} | |||
btSphereBoxCollisionAlgorithm::~btSphereBoxCollisionAlgorithm() | |||
{ | |||
if (m_ownManifold) | |||
{ | |||
if (m_manifoldPtr) | |||
m_dispatcher->releaseManifold(m_manifoldPtr); | |||
} | |||
} | |||
void btSphereBoxCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
(void)dispatchInfo; | |||
(void)resultOut; | |||
if (!m_manifoldPtr) | |||
return; | |||
btCollisionObject* sphereObj = m_isSwapped? body1 : body0; | |||
btCollisionObject* boxObj = m_isSwapped? body0 : body1; | |||
btSphereShape* sphere0 = (btSphereShape*)sphereObj->getCollisionShape(); | |||
btVector3 normalOnSurfaceB; | |||
btVector3 pOnBox,pOnSphere; | |||
btVector3 sphereCenter = sphereObj->getWorldTransform().getOrigin(); | |||
btScalar radius = sphere0->getRadius(); | |||
btScalar dist = getSphereDistance(boxObj,pOnBox,pOnSphere,sphereCenter,radius); | |||
resultOut->setPersistentManifold(m_manifoldPtr); | |||
if (dist < SIMD_EPSILON) | |||
{ | |||
btVector3 normalOnSurfaceB = (pOnBox- pOnSphere).normalize(); | |||
/// report a contact. internally this will be kept persistent, and contact reduction is done | |||
resultOut->addContactPoint(normalOnSurfaceB,pOnBox,dist); | |||
} | |||
if (m_ownManifold) | |||
{ | |||
if (m_manifoldPtr->getNumContacts()) | |||
{ | |||
resultOut->refreshContactPoints(); | |||
} | |||
} | |||
} | |||
btScalar btSphereBoxCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
(void)resultOut; | |||
(void)dispatchInfo; | |||
(void)col0; | |||
(void)col1; | |||
//not yet | |||
return btScalar(1.); | |||
} | |||
btScalar btSphereBoxCollisionAlgorithm::getSphereDistance(btCollisionObject* boxObj, btVector3& pointOnBox, btVector3& v3PointOnSphere, const btVector3& sphereCenter, btScalar fRadius ) | |||
{ | |||
btScalar margins; | |||
btVector3 bounds[2]; | |||
btBoxShape* boxShape= (btBoxShape*)boxObj->getCollisionShape(); | |||
bounds[0] = -boxShape->getHalfExtentsWithoutMargin(); | |||
bounds[1] = boxShape->getHalfExtentsWithoutMargin(); | |||
margins = boxShape->getMargin();//also add sphereShape margin? | |||
const btTransform& m44T = boxObj->getWorldTransform(); | |||
btVector3 boundsVec[2]; | |||
btScalar fPenetration; | |||
boundsVec[0] = bounds[0]; | |||
boundsVec[1] = bounds[1]; | |||
btVector3 marginsVec( margins, margins, margins ); | |||
// add margins | |||
bounds[0] += marginsVec; | |||
bounds[1] -= marginsVec; | |||
///////////////////////////////////////////////// | |||
btVector3 tmp, prel, n[6], normal, v3P; | |||
btScalar fSep = btScalar(10000000.0), fSepThis; | |||
n[0].setValue( btScalar(-1.0), btScalar(0.0), btScalar(0.0) ); | |||
n[1].setValue( btScalar(0.0), btScalar(-1.0), btScalar(0.0) ); | |||
n[2].setValue( btScalar(0.0), btScalar(0.0), btScalar(-1.0) ); | |||
n[3].setValue( btScalar(1.0), btScalar(0.0), btScalar(0.0) ); | |||
n[4].setValue( btScalar(0.0), btScalar(1.0), btScalar(0.0) ); | |||
n[5].setValue( btScalar(0.0), btScalar(0.0), btScalar(1.0) ); | |||
// convert point in local space | |||
prel = m44T.invXform( sphereCenter); | |||
bool bFound = false; | |||
v3P = prel; | |||
for (int i=0;i<6;i++) | |||
{ | |||
int j = i<3? 0:1; | |||
if ( (fSepThis = ((v3P-bounds[j]) .dot(n[i]))) > btScalar(0.0) ) | |||
{ | |||
v3P = v3P - n[i]*fSepThis; | |||
bFound = true; | |||
} | |||
} | |||
// | |||
if ( bFound ) | |||
{ | |||
bounds[0] = boundsVec[0]; | |||
bounds[1] = boundsVec[1]; | |||
normal = (prel - v3P).normalize(); | |||
pointOnBox = v3P + normal*margins; | |||
v3PointOnSphere = prel - normal*fRadius; | |||
if ( ((v3PointOnSphere - pointOnBox) .dot (normal)) > btScalar(0.0) ) | |||
{ | |||
return btScalar(1.0); | |||
} | |||
// transform back in world space | |||
tmp = m44T( pointOnBox); | |||
pointOnBox = tmp; | |||
tmp = m44T( v3PointOnSphere); | |||
v3PointOnSphere = tmp; | |||
btScalar fSeps2 = (pointOnBox-v3PointOnSphere).length2(); | |||
//if this fails, fallback into deeper penetration case, below | |||
if (fSeps2 > SIMD_EPSILON) | |||
{ | |||
fSep = - btSqrt(fSeps2); | |||
normal = (pointOnBox-v3PointOnSphere); | |||
normal *= btScalar(1.)/fSep; | |||
} | |||
return fSep; | |||
} | |||
////////////////////////////////////////////////// | |||
// Deep penetration case | |||
fPenetration = getSpherePenetration( boxObj,pointOnBox, v3PointOnSphere, sphereCenter, fRadius,bounds[0],bounds[1] ); | |||
bounds[0] = boundsVec[0]; | |||
bounds[1] = boundsVec[1]; | |||
if ( fPenetration <= btScalar(0.0) ) | |||
return (fPenetration-margins); | |||
else | |||
return btScalar(1.0); | |||
} | |||
btScalar btSphereBoxCollisionAlgorithm::getSpherePenetration( btCollisionObject* boxObj,btVector3& pointOnBox, btVector3& v3PointOnSphere, const btVector3& sphereCenter, btScalar fRadius, const btVector3& aabbMin, const btVector3& aabbMax) | |||
{ | |||
btVector3 bounds[2]; | |||
bounds[0] = aabbMin; | |||
bounds[1] = aabbMax; | |||
btVector3 p0, tmp, prel, n[6], normal; | |||
btScalar fSep = btScalar(-10000000.0), fSepThis; | |||
// set p0 and normal to a default value to shup up GCC | |||
p0.setValue(btScalar(0.), btScalar(0.), btScalar(0.)); | |||
normal.setValue(btScalar(0.), btScalar(0.), btScalar(0.)); | |||
n[0].setValue( btScalar(-1.0), btScalar(0.0), btScalar(0.0) ); | |||
n[1].setValue( btScalar(0.0), btScalar(-1.0), btScalar(0.0) ); | |||
n[2].setValue( btScalar(0.0), btScalar(0.0), btScalar(-1.0) ); | |||
n[3].setValue( btScalar(1.0), btScalar(0.0), btScalar(0.0) ); | |||
n[4].setValue( btScalar(0.0), btScalar(1.0), btScalar(0.0) ); | |||
n[5].setValue( btScalar(0.0), btScalar(0.0), btScalar(1.0) ); | |||
const btTransform& m44T = boxObj->getWorldTransform(); | |||
// convert point in local space | |||
prel = m44T.invXform( sphereCenter); | |||
/////////// | |||
for (int i=0;i<6;i++) | |||
{ | |||
int j = i<3 ? 0:1; | |||
if ( (fSepThis = ((prel-bounds[j]) .dot( n[i]))-fRadius) > btScalar(0.0) ) return btScalar(1.0); | |||
if ( fSepThis > fSep ) | |||
{ | |||
p0 = bounds[j]; normal = (btVector3&)n[i]; | |||
fSep = fSepThis; | |||
} | |||
} | |||
pointOnBox = prel - normal*(normal.dot((prel-p0))); | |||
v3PointOnSphere = pointOnBox + normal*fSep; | |||
// transform back in world space | |||
tmp = m44T( pointOnBox); | |||
pointOnBox = tmp; | |||
tmp = m44T( v3PointOnSphere); v3PointOnSphere = tmp; | |||
normal = (pointOnBox-v3PointOnSphere).normalize(); | |||
return fSep; | |||
} | |||
@@ -0,0 +1,75 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_SPHERE_BOX_COLLISION_ALGORITHM_H | |||
#define BT_SPHERE_BOX_COLLISION_ALGORITHM_H | |||
#include "btActivatingCollisionAlgorithm.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
class btPersistentManifold; | |||
#include "btCollisionDispatcher.h" | |||
#include "LinearMath/btVector3.h" | |||
/// btSphereBoxCollisionAlgorithm provides sphere-box collision detection. | |||
/// Other features are frame-coherency (persistent data) and collision response. | |||
class btSphereBoxCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
{ | |||
bool m_ownManifold; | |||
btPersistentManifold* m_manifoldPtr; | |||
bool m_isSwapped; | |||
public: | |||
btSphereBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped); | |||
virtual ~btSphereBoxCollisionAlgorithm(); | |||
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
{ | |||
if (m_manifoldPtr && m_ownManifold) | |||
{ | |||
manifoldArray.push_back(m_manifoldPtr); | |||
} | |||
} | |||
btScalar getSphereDistance( btCollisionObject* boxObj,btVector3& v3PointOnBox, btVector3& v3PointOnSphere, const btVector3& v3SphereCenter, btScalar fRadius ); | |||
btScalar getSpherePenetration( btCollisionObject* boxObj, btVector3& v3PointOnBox, btVector3& v3PointOnSphere, const btVector3& v3SphereCenter, btScalar fRadius, const btVector3& aabbMin, const btVector3& aabbMax); | |||
struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereBoxCollisionAlgorithm)); | |||
if (!m_swapped) | |||
{ | |||
return new(mem) btSphereBoxCollisionAlgorithm(0,ci,body0,body1,false); | |||
} else | |||
{ | |||
return new(mem) btSphereBoxCollisionAlgorithm(0,ci,body0,body1,true); | |||
} | |||
} | |||
}; | |||
}; | |||
#endif //BT_SPHERE_BOX_COLLISION_ALGORITHM_H | |||
@@ -0,0 +1,105 @@ | |||
/* | |||
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 "btSphereSphereCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
#include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
btSphereSphereCollisionAlgorithm::btSphereSphereCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1) | |||
: btActivatingCollisionAlgorithm(ci,col0,col1), | |||
m_ownManifold(false), | |||
m_manifoldPtr(mf) | |||
{ | |||
if (!m_manifoldPtr) | |||
{ | |||
m_manifoldPtr = m_dispatcher->getNewManifold(col0,col1); | |||
m_ownManifold = true; | |||
} | |||
} | |||
btSphereSphereCollisionAlgorithm::~btSphereSphereCollisionAlgorithm() | |||
{ | |||
if (m_ownManifold) | |||
{ | |||
if (m_manifoldPtr) | |||
m_dispatcher->releaseManifold(m_manifoldPtr); | |||
} | |||
} | |||
void btSphereSphereCollisionAlgorithm::processCollision (btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
(void)dispatchInfo; | |||
if (!m_manifoldPtr) | |||
return; | |||
resultOut->setPersistentManifold(m_manifoldPtr); | |||
btSphereShape* sphere0 = (btSphereShape*)col0->getCollisionShape(); | |||
btSphereShape* sphere1 = (btSphereShape*)col1->getCollisionShape(); | |||
btVector3 diff = col0->getWorldTransform().getOrigin()- col1->getWorldTransform().getOrigin(); | |||
btScalar len = diff.length(); | |||
btScalar radius0 = sphere0->getRadius(); | |||
btScalar radius1 = sphere1->getRadius(); | |||
#ifdef CLEAR_MANIFOLD | |||
m_manifoldPtr->clearManifold(); //don't do this, it disables warmstarting | |||
#endif | |||
///iff distance positive, don't generate a new contact | |||
if ( len > (radius0+radius1)) | |||
{ | |||
#ifndef CLEAR_MANIFOLD | |||
resultOut->refreshContactPoints(); | |||
#endif //CLEAR_MANIFOLD | |||
return; | |||
} | |||
///distance (negative means penetration) | |||
btScalar dist = len - (radius0+radius1); | |||
btVector3 normalOnSurfaceB(1,0,0); | |||
if (len > SIMD_EPSILON) | |||
{ | |||
normalOnSurfaceB = diff / len; | |||
} | |||
///point on A (worldspace) | |||
///btVector3 pos0 = col0->getWorldTransform().getOrigin() - radius0 * normalOnSurfaceB; | |||
///point on B (worldspace) | |||
btVector3 pos1 = col1->getWorldTransform().getOrigin() + radius1* normalOnSurfaceB; | |||
/// report a contact. internally this will be kept persistent, and contact reduction is done | |||
resultOut->addContactPoint(normalOnSurfaceB,pos1,dist); | |||
#ifndef CLEAR_MANIFOLD | |||
resultOut->refreshContactPoints(); | |||
#endif //CLEAR_MANIFOLD | |||
} | |||
btScalar btSphereSphereCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
(void)col0; | |||
(void)col1; | |||
(void)dispatchInfo; | |||
(void)resultOut; | |||
//not yet | |||
return btScalar(1.); | |||
} |
@@ -0,0 +1,66 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_SPHERE_SPHERE_COLLISION_ALGORITHM_H | |||
#define BT_SPHERE_SPHERE_COLLISION_ALGORITHM_H | |||
#include "btActivatingCollisionAlgorithm.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
#include "btCollisionDispatcher.h" | |||
class btPersistentManifold; | |||
/// btSphereSphereCollisionAlgorithm provides sphere-sphere collision detection. | |||
/// Other features are frame-coherency (persistent data) and collision response. | |||
/// Also provides the most basic sample for custom/user btCollisionAlgorithm | |||
class btSphereSphereCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
{ | |||
bool m_ownManifold; | |||
btPersistentManifold* m_manifoldPtr; | |||
public: | |||
btSphereSphereCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); | |||
btSphereSphereCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) | |||
: btActivatingCollisionAlgorithm(ci) {} | |||
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
{ | |||
if (m_manifoldPtr && m_ownManifold) | |||
{ | |||
manifoldArray.push_back(m_manifoldPtr); | |||
} | |||
} | |||
virtual ~btSphereSphereCollisionAlgorithm(); | |||
struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereSphereCollisionAlgorithm)); | |||
return new(mem) btSphereSphereCollisionAlgorithm(0,ci,body0,body1); | |||
} | |||
}; | |||
}; | |||
#endif //BT_SPHERE_SPHERE_COLLISION_ALGORITHM_H | |||
@@ -0,0 +1,84 @@ | |||
/* | |||
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 "btSphereTriangleCollisionAlgorithm.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
#include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
#include "SphereTriangleDetector.h" | |||
btSphereTriangleCollisionAlgorithm::btSphereTriangleCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1,bool swapped) | |||
: btActivatingCollisionAlgorithm(ci,col0,col1), | |||
m_ownManifold(false), | |||
m_manifoldPtr(mf), | |||
m_swapped(swapped) | |||
{ | |||
if (!m_manifoldPtr) | |||
{ | |||
m_manifoldPtr = m_dispatcher->getNewManifold(col0,col1); | |||
m_ownManifold = true; | |||
} | |||
} | |||
btSphereTriangleCollisionAlgorithm::~btSphereTriangleCollisionAlgorithm() | |||
{ | |||
if (m_ownManifold) | |||
{ | |||
if (m_manifoldPtr) | |||
m_dispatcher->releaseManifold(m_manifoldPtr); | |||
} | |||
} | |||
void btSphereTriangleCollisionAlgorithm::processCollision (btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
if (!m_manifoldPtr) | |||
return; | |||
btCollisionObject* sphereObj = m_swapped? col1 : col0; | |||
btCollisionObject* triObj = m_swapped? col0 : col1; | |||
btSphereShape* sphere = (btSphereShape*)sphereObj->getCollisionShape(); | |||
btTriangleShape* triangle = (btTriangleShape*)triObj->getCollisionShape(); | |||
/// report a contact. internally this will be kept persistent, and contact reduction is done | |||
resultOut->setPersistentManifold(m_manifoldPtr); | |||
SphereTriangleDetector detector(sphere,triangle, m_manifoldPtr->getContactBreakingThreshold()); | |||
btDiscreteCollisionDetectorInterface::ClosestPointInput input; | |||
input.m_maximumDistanceSquared = btScalar(BT_LARGE_FLOAT);///@todo: tighter bounds | |||
input.m_transformA = sphereObj->getWorldTransform(); | |||
input.m_transformB = triObj->getWorldTransform(); | |||
bool swapResults = m_swapped; | |||
detector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw,swapResults); | |||
if (m_ownManifold) | |||
resultOut->refreshContactPoints(); | |||
} | |||
btScalar btSphereTriangleCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
{ | |||
(void)resultOut; | |||
(void)dispatchInfo; | |||
(void)col0; | |||
(void)col1; | |||
//not yet | |||
return btScalar(1.); | |||
} |
@@ -0,0 +1,69 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_SPHERE_TRIANGLE_COLLISION_ALGORITHM_H | |||
#define BT_SPHERE_TRIANGLE_COLLISION_ALGORITHM_H | |||
#include "btActivatingCollisionAlgorithm.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
class btPersistentManifold; | |||
#include "btCollisionDispatcher.h" | |||
/// btSphereSphereCollisionAlgorithm provides sphere-sphere collision detection. | |||
/// Other features are frame-coherency (persistent data) and collision response. | |||
/// Also provides the most basic sample for custom/user btCollisionAlgorithm | |||
class btSphereTriangleCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
{ | |||
bool m_ownManifold; | |||
btPersistentManifold* m_manifoldPtr; | |||
bool m_swapped; | |||
public: | |||
btSphereTriangleCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool swapped); | |||
btSphereTriangleCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) | |||
: btActivatingCollisionAlgorithm(ci) {} | |||
virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
{ | |||
if (m_manifoldPtr && m_ownManifold) | |||
{ | |||
manifoldArray.push_back(m_manifoldPtr); | |||
} | |||
} | |||
virtual ~btSphereTriangleCollisionAlgorithm(); | |||
struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
{ | |||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
{ | |||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereTriangleCollisionAlgorithm)); | |||
return new(mem) btSphereTriangleCollisionAlgorithm(ci.m_manifold,ci,body0,body1,m_swapped); | |||
} | |||
}; | |||
}; | |||
#endif //BT_SPHERE_TRIANGLE_COLLISION_ALGORITHM_H | |||
@@ -0,0 +1,82 @@ | |||
/* | |||
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 "btUnionFind.h" | |||
btUnionFind::~btUnionFind() | |||
{ | |||
Free(); | |||
} | |||
btUnionFind::btUnionFind() | |||
{ | |||
} | |||
void btUnionFind::allocate(int N) | |||
{ | |||
m_elements.resize(N); | |||
} | |||
void btUnionFind::Free() | |||
{ | |||
m_elements.clear(); | |||
} | |||
void btUnionFind::reset(int N) | |||
{ | |||
allocate(N); | |||
for (int i = 0; i < N; i++) | |||
{ | |||
m_elements[i].m_id = i; m_elements[i].m_sz = 1; | |||
} | |||
} | |||
class btUnionFindElementSortPredicate | |||
{ | |||
public: | |||
bool operator() ( const btElement& lhs, const btElement& rhs ) const | |||
{ | |||
return lhs.m_id < rhs.m_id; | |||
} | |||
}; | |||
///this is a special operation, destroying the content of btUnionFind. | |||
///it sorts the elements, based on island id, in order to make it easy to iterate over islands | |||
void btUnionFind::sortIslands() | |||
{ | |||
//first store the original body index, and islandId | |||
int numElements = m_elements.size(); | |||
for (int i=0;i<numElements;i++) | |||
{ | |||
m_elements[i].m_id = find(i); | |||
#ifndef STATIC_SIMULATION_ISLAND_OPTIMIZATION | |||
m_elements[i].m_sz = i; | |||
#endif //STATIC_SIMULATION_ISLAND_OPTIMIZATION | |||
} | |||
// Sort the vector using predicate and std::sort | |||
//std::sort(m_elements.begin(), m_elements.end(), btUnionFindElementSortPredicate); | |||
m_elements.quickSort(btUnionFindElementSortPredicate()); | |||
} |
@@ -0,0 +1,129 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_UNION_FIND_H | |||
#define BT_UNION_FIND_H | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
#define USE_PATH_COMPRESSION 1 | |||
///see for discussion of static island optimizations by Vroonsh here: http://code.google.com/p/bullet/issues/detail?id=406 | |||
#define STATIC_SIMULATION_ISLAND_OPTIMIZATION 1 | |||
struct btElement | |||
{ | |||
int m_id; | |||
int m_sz; | |||
}; | |||
///UnionFind calculates connected subsets | |||
// Implements weighted Quick Union with path compression | |||
// optimization: could use short ints instead of ints (halving memory, would limit the number of rigid bodies to 64k, sounds reasonable) | |||
class btUnionFind | |||
{ | |||
private: | |||
btAlignedObjectArray<btElement> m_elements; | |||
public: | |||
btUnionFind(); | |||
~btUnionFind(); | |||
//this is a special operation, destroying the content of btUnionFind. | |||
//it sorts the elements, based on island id, in order to make it easy to iterate over islands | |||
void sortIslands(); | |||
void reset(int N); | |||
SIMD_FORCE_INLINE int getNumElements() const | |||
{ | |||
return int(m_elements.size()); | |||
} | |||
SIMD_FORCE_INLINE bool isRoot(int x) const | |||
{ | |||
return (x == m_elements[x].m_id); | |||
} | |||
btElement& getElement(int index) | |||
{ | |||
return m_elements[index]; | |||
} | |||
const btElement& getElement(int index) const | |||
{ | |||
return m_elements[index]; | |||
} | |||
void allocate(int N); | |||
void Free(); | |||
int find(int p, int q) | |||
{ | |||
return (find(p) == find(q)); | |||
} | |||
void unite(int p, int q) | |||
{ | |||
int i = find(p), j = find(q); | |||
if (i == j) | |||
return; | |||
#ifndef USE_PATH_COMPRESSION | |||
//weighted quick union, this keeps the 'trees' balanced, and keeps performance of unite O( log(n) ) | |||
if (m_elements[i].m_sz < m_elements[j].m_sz) | |||
{ | |||
m_elements[i].m_id = j; m_elements[j].m_sz += m_elements[i].m_sz; | |||
} | |||
else | |||
{ | |||
m_elements[j].m_id = i; m_elements[i].m_sz += m_elements[j].m_sz; | |||
} | |||
#else | |||
m_elements[i].m_id = j; m_elements[j].m_sz += m_elements[i].m_sz; | |||
#endif //USE_PATH_COMPRESSION | |||
} | |||
int find(int x) | |||
{ | |||
//btAssert(x < m_N); | |||
//btAssert(x >= 0); | |||
while (x != m_elements[x].m_id) | |||
{ | |||
//not really a reason not to use path compression, and it flattens the trees/improves find performance dramatically | |||
#ifdef USE_PATH_COMPRESSION | |||
const btElement* elementPtr = &m_elements[m_elements[x].m_id]; | |||
m_elements[x].m_id = elementPtr->m_id; | |||
x = elementPtr->m_id; | |||
#else// | |||
x = m_elements[x].m_id; | |||
#endif | |||
//btAssert(x < m_N); | |||
//btAssert(x >= 0); | |||
} | |||
return x; | |||
} | |||
}; | |||
#endif //BT_UNION_FIND_H |
@@ -0,0 +1,42 @@ | |||
/* | |||
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 "btBox2dShape.h" | |||
//{ | |||
void btBox2dShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const | |||
{ | |||
btTransformAabb(getHalfExtentsWithoutMargin(),getMargin(),t,aabbMin,aabbMax); | |||
} | |||
void btBox2dShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const | |||
{ | |||
//btScalar margin = btScalar(0.); | |||
btVector3 halfExtents = getHalfExtentsWithMargin(); | |||
btScalar lx=btScalar(2.)*(halfExtents.x()); | |||
btScalar ly=btScalar(2.)*(halfExtents.y()); | |||
btScalar lz=btScalar(2.)*(halfExtents.z()); | |||
inertia.setValue(mass/(btScalar(12.0)) * (ly*ly + lz*lz), | |||
mass/(btScalar(12.0)) * (lx*lx + lz*lz), | |||
mass/(btScalar(12.0)) * (lx*lx + ly*ly)); | |||
} | |||
@@ -0,0 +1,369 @@ | |||
/* | |||
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. | |||
*/ | |||
#ifndef BT_OBB_BOX_2D_SHAPE_H | |||
#define BT_OBB_BOX_2D_SHAPE_H | |||
#include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h" | |||
#include "BulletCollision/CollisionShapes/btCollisionMargin.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "LinearMath/btVector3.h" | |||
#include "LinearMath/btMinMax.h" | |||
///The btBox2dShape is a box primitive around the origin, its sides axis aligned with length specified by half extents, in local shape coordinates. When used as part of a btCollisionObject or btRigidBody it will be an oriented box in world space. | |||
class btBox2dShape: public btPolyhedralConvexShape | |||
{ | |||
//btVector3 m_boxHalfExtents1; //use m_implicitShapeDimensions instead | |||
btVector3 m_centroid; | |||
btVector3 m_vertices[4]; | |||
btVector3 m_normals[4]; | |||
public: | |||
btVector3 getHalfExtentsWithMargin() const | |||
{ | |||
btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
btVector3 margin(getMargin(),getMargin(),getMargin()); | |||
halfExtents += margin; | |||
return halfExtents; | |||
} | |||
const btVector3& getHalfExtentsWithoutMargin() const | |||
{ | |||
return m_implicitShapeDimensions;//changed in Bullet 2.63: assume the scaling and margin are included | |||
} | |||
virtual btVector3 localGetSupportingVertex(const btVector3& vec) const | |||
{ | |||
btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
btVector3 margin(getMargin(),getMargin(),getMargin()); | |||
halfExtents += margin; | |||
return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), | |||
btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), | |||
btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); | |||
} | |||
SIMD_FORCE_INLINE btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const | |||
{ | |||
const btVector3& halfExtents = getHalfExtentsWithoutMargin(); | |||
return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), | |||
btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), | |||
btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); | |||
} | |||
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
{ | |||
const btVector3& halfExtents = getHalfExtentsWithoutMargin(); | |||
for (int i=0;i<numVectors;i++) | |||
{ | |||
const btVector3& vec = vectors[i]; | |||
supportVerticesOut[i].setValue(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), | |||
btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), | |||
btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); | |||
} | |||
} | |||
///a btBox2dShape is a flat 2D box in the X-Y plane (Z extents are zero) | |||
btBox2dShape( const btVector3& boxHalfExtents) | |||
: btPolyhedralConvexShape(), | |||
m_centroid(0,0,0) | |||
{ | |||
m_vertices[0].setValue(-boxHalfExtents.getX(),-boxHalfExtents.getY(),0); | |||
m_vertices[1].setValue(boxHalfExtents.getX(),-boxHalfExtents.getY(),0); | |||
m_vertices[2].setValue(boxHalfExtents.getX(),boxHalfExtents.getY(),0); | |||
m_vertices[3].setValue(-boxHalfExtents.getX(),boxHalfExtents.getY(),0); | |||
m_normals[0].setValue(0,-1,0); | |||
m_normals[1].setValue(1,0,0); | |||
m_normals[2].setValue(0,1,0); | |||
m_normals[3].setValue(-1,0,0); | |||
btScalar minDimension = boxHalfExtents.getX(); | |||
if (minDimension>boxHalfExtents.getY()) | |||
minDimension = boxHalfExtents.getY(); | |||
setSafeMargin(minDimension); | |||
m_shapeType = BOX_2D_SHAPE_PROXYTYPE; | |||
btVector3 margin(getMargin(),getMargin(),getMargin()); | |||
m_implicitShapeDimensions = (boxHalfExtents * m_localScaling) - margin; | |||
}; | |||
virtual void setMargin(btScalar collisionMargin) | |||
{ | |||
//correct the m_implicitShapeDimensions for the margin | |||
btVector3 oldMargin(getMargin(),getMargin(),getMargin()); | |||
btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; | |||
btConvexInternalShape::setMargin(collisionMargin); | |||
btVector3 newMargin(getMargin(),getMargin(),getMargin()); | |||
m_implicitShapeDimensions = implicitShapeDimensionsWithMargin - newMargin; | |||
} | |||
virtual void setLocalScaling(const btVector3& scaling) | |||
{ | |||
btVector3 oldMargin(getMargin(),getMargin(),getMargin()); | |||
btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; | |||
btVector3 unScaledImplicitShapeDimensionsWithMargin = implicitShapeDimensionsWithMargin / m_localScaling; | |||
btConvexInternalShape::setLocalScaling(scaling); | |||
m_implicitShapeDimensions = (unScaledImplicitShapeDimensionsWithMargin * m_localScaling) - oldMargin; | |||
} | |||
virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; | |||
int getVertexCount() const | |||
{ | |||
return 4; | |||
} | |||
virtual int getNumVertices()const | |||
{ | |||
return 4; | |||
} | |||
const btVector3* getVertices() const | |||
{ | |||
return &m_vertices[0]; | |||
} | |||
const btVector3* getNormals() const | |||
{ | |||
return &m_normals[0]; | |||
} | |||
virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i ) const | |||
{ | |||
//this plane might not be aligned... | |||
btVector4 plane ; | |||
getPlaneEquation(plane,i); | |||
planeNormal = btVector3(plane.getX(),plane.getY(),plane.getZ()); | |||
planeSupport = localGetSupportingVertex(-planeNormal); | |||
} | |||
const btVector3& getCentroid() const | |||
{ | |||
return m_centroid; | |||
} | |||
virtual int getNumPlanes() const | |||
{ | |||
return 6; | |||
} | |||
virtual int getNumEdges() const | |||
{ | |||
return 12; | |||
} | |||
virtual void getVertex(int i,btVector3& vtx) const | |||
{ | |||
btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
vtx = btVector3( | |||
halfExtents.x() * (1-(i&1)) - halfExtents.x() * (i&1), | |||
halfExtents.y() * (1-((i&2)>>1)) - halfExtents.y() * ((i&2)>>1), | |||
halfExtents.z() * (1-((i&4)>>2)) - halfExtents.z() * ((i&4)>>2)); | |||
} | |||
virtual void getPlaneEquation(btVector4& plane,int i) const | |||
{ | |||
btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
switch (i) | |||
{ | |||
case 0: | |||
plane.setValue(btScalar(1.),btScalar(0.),btScalar(0.),-halfExtents.x()); | |||
break; | |||
case 1: | |||
plane.setValue(btScalar(-1.),btScalar(0.),btScalar(0.),-halfExtents.x()); | |||
break; | |||
case 2: | |||
plane.setValue(btScalar(0.),btScalar(1.),btScalar(0.),-halfExtents.y()); | |||
break; | |||
case 3: | |||
plane.setValue(btScalar(0.),btScalar(-1.),btScalar(0.),-halfExtents.y()); | |||
break; | |||
case 4: | |||
plane.setValue(btScalar(0.),btScalar(0.),btScalar(1.),-halfExtents.z()); | |||
break; | |||
case 5: | |||
plane.setValue(btScalar(0.),btScalar(0.),btScalar(-1.),-halfExtents.z()); | |||
break; | |||
default: | |||
btAssert(0); | |||
} | |||
} | |||
virtual void getEdge(int i,btVector3& pa,btVector3& pb) const | |||
//virtual void getEdge(int i,Edge& edge) const | |||
{ | |||
int edgeVert0 = 0; | |||
int edgeVert1 = 0; | |||
switch (i) | |||
{ | |||
case 0: | |||
edgeVert0 = 0; | |||
edgeVert1 = 1; | |||
break; | |||
case 1: | |||
edgeVert0 = 0; | |||
edgeVert1 = 2; | |||
break; | |||
case 2: | |||
edgeVert0 = 1; | |||
edgeVert1 = 3; | |||
break; | |||
case 3: | |||
edgeVert0 = 2; | |||
edgeVert1 = 3; | |||
break; | |||
case 4: | |||
edgeVert0 = 0; | |||
edgeVert1 = 4; | |||
break; | |||
case 5: | |||
edgeVert0 = 1; | |||
edgeVert1 = 5; | |||
break; | |||
case 6: | |||
edgeVert0 = 2; | |||
edgeVert1 = 6; | |||
break; | |||
case 7: | |||
edgeVert0 = 3; | |||
edgeVert1 = 7; | |||
break; | |||
case 8: | |||
edgeVert0 = 4; | |||
edgeVert1 = 5; | |||
break; | |||
case 9: | |||
edgeVert0 = 4; | |||
edgeVert1 = 6; | |||
break; | |||
case 10: | |||
edgeVert0 = 5; | |||
edgeVert1 = 7; | |||
break; | |||
case 11: | |||
edgeVert0 = 6; | |||
edgeVert1 = 7; | |||
break; | |||
default: | |||
btAssert(0); | |||
} | |||
getVertex(edgeVert0,pa ); | |||
getVertex(edgeVert1,pb ); | |||
} | |||
virtual bool isInside(const btVector3& pt,btScalar tolerance) const | |||
{ | |||
btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
//btScalar minDist = 2*tolerance; | |||
bool result = (pt.x() <= (halfExtents.x()+tolerance)) && | |||
(pt.x() >= (-halfExtents.x()-tolerance)) && | |||
(pt.y() <= (halfExtents.y()+tolerance)) && | |||
(pt.y() >= (-halfExtents.y()-tolerance)) && | |||
(pt.z() <= (halfExtents.z()+tolerance)) && | |||
(pt.z() >= (-halfExtents.z()-tolerance)); | |||
return result; | |||
} | |||
//debugging | |||
virtual const char* getName()const | |||
{ | |||
return "Box2d"; | |||
} | |||
virtual int getNumPreferredPenetrationDirections() const | |||
{ | |||
return 6; | |||
} | |||
virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const | |||
{ | |||
switch (index) | |||
{ | |||
case 0: | |||
penetrationVector.setValue(btScalar(1.),btScalar(0.),btScalar(0.)); | |||
break; | |||
case 1: | |||
penetrationVector.setValue(btScalar(-1.),btScalar(0.),btScalar(0.)); | |||
break; | |||
case 2: | |||
penetrationVector.setValue(btScalar(0.),btScalar(1.),btScalar(0.)); | |||
break; | |||
case 3: | |||
penetrationVector.setValue(btScalar(0.),btScalar(-1.),btScalar(0.)); | |||
break; | |||
case 4: | |||
penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(1.)); | |||
break; | |||
case 5: | |||
penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(-1.)); | |||
break; | |||
default: | |||
btAssert(0); | |||
} | |||
} | |||
}; | |||
#endif //BT_OBB_BOX_2D_SHAPE_H | |||
@@ -0,0 +1,51 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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 "btBoxShape.h" | |||
btBoxShape::btBoxShape( const btVector3& boxHalfExtents) | |||
: btPolyhedralConvexShape() | |||
{ | |||
m_shapeType = BOX_SHAPE_PROXYTYPE; | |||
setSafeMargin(boxHalfExtents); | |||
btVector3 margin(getMargin(),getMargin(),getMargin()); | |||
m_implicitShapeDimensions = (boxHalfExtents * m_localScaling) - margin; | |||
}; | |||
void btBoxShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const | |||
{ | |||
btTransformAabb(getHalfExtentsWithoutMargin(),getMargin(),t,aabbMin,aabbMax); | |||
} | |||
void btBoxShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const | |||
{ | |||
//btScalar margin = btScalar(0.); | |||
btVector3 halfExtents = getHalfExtentsWithMargin(); | |||
btScalar lx=btScalar(2.)*(halfExtents.x()); | |||
btScalar ly=btScalar(2.)*(halfExtents.y()); | |||
btScalar lz=btScalar(2.)*(halfExtents.z()); | |||
inertia.setValue(mass/(btScalar(12.0)) * (ly*ly + lz*lz), | |||
mass/(btScalar(12.0)) * (lx*lx + lz*lz), | |||
mass/(btScalar(12.0)) * (lx*lx + ly*ly)); | |||
} | |||
@@ -0,0 +1,312 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
#ifndef BT_OBB_BOX_MINKOWSKI_H | |||
#define BT_OBB_BOX_MINKOWSKI_H | |||
#include "btPolyhedralConvexShape.h" | |||
#include "btCollisionMargin.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
#include "LinearMath/btVector3.h" | |||
#include "LinearMath/btMinMax.h" | |||
///The btBoxShape is a box primitive around the origin, its sides axis aligned with length specified by half extents, in local shape coordinates. When used as part of a btCollisionObject or btRigidBody it will be an oriented box in world space. | |||
class btBoxShape: public btPolyhedralConvexShape | |||
{ | |||
//btVector3 m_boxHalfExtents1; //use m_implicitShapeDimensions instead | |||
public: | |||
btVector3 getHalfExtentsWithMargin() const | |||
{ | |||
btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
btVector3 margin(getMargin(),getMargin(),getMargin()); | |||
halfExtents += margin; | |||
return halfExtents; | |||
} | |||
const btVector3& getHalfExtentsWithoutMargin() const | |||
{ | |||
return m_implicitShapeDimensions;//scaling is included, margin is not | |||
} | |||
virtual btVector3 localGetSupportingVertex(const btVector3& vec) const | |||
{ | |||
btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
btVector3 margin(getMargin(),getMargin(),getMargin()); | |||
halfExtents += margin; | |||
return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), | |||
btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), | |||
btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); | |||
} | |||
SIMD_FORCE_INLINE btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const | |||
{ | |||
const btVector3& halfExtents = getHalfExtentsWithoutMargin(); | |||
return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), | |||
btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), | |||
btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); | |||
} | |||
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
{ | |||
const btVector3& halfExtents = getHalfExtentsWithoutMargin(); | |||
for (int i=0;i<numVectors;i++) | |||
{ | |||
const btVector3& vec = vectors[i]; | |||
supportVerticesOut[i].setValue(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), | |||
btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), | |||
btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); | |||
} | |||
} | |||
btBoxShape( const btVector3& boxHalfExtents); | |||
virtual void setMargin(btScalar collisionMargin) | |||
{ | |||
//correct the m_implicitShapeDimensions for the margin | |||
btVector3 oldMargin(getMargin(),getMargin(),getMargin()); | |||
btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; | |||
btConvexInternalShape::setMargin(collisionMargin); | |||
btVector3 newMargin(getMargin(),getMargin(),getMargin()); | |||
m_implicitShapeDimensions = implicitShapeDimensionsWithMargin - newMargin; | |||
} | |||
virtual void setLocalScaling(const btVector3& scaling) | |||
{ | |||
btVector3 oldMargin(getMargin(),getMargin(),getMargin()); | |||
btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; | |||
btVector3 unScaledImplicitShapeDimensionsWithMargin = implicitShapeDimensionsWithMargin / m_localScaling; | |||
btConvexInternalShape::setLocalScaling(scaling); | |||
m_implicitShapeDimensions = (unScaledImplicitShapeDimensionsWithMargin * m_localScaling) - oldMargin; | |||
} | |||
virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; | |||
virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i ) const | |||
{ | |||
//this plane might not be aligned... | |||
btVector4 plane ; | |||
getPlaneEquation(plane,i); | |||
planeNormal = btVector3(plane.getX(),plane.getY(),plane.getZ()); | |||
planeSupport = localGetSupportingVertex(-planeNormal); | |||
} | |||
virtual int getNumPlanes() const | |||
{ | |||
return 6; | |||
} | |||
virtual int getNumVertices() const | |||
{ | |||
return 8; | |||
} | |||
virtual int getNumEdges() const | |||
{ | |||
return 12; | |||
} | |||
virtual void getVertex(int i,btVector3& vtx) const | |||
{ | |||
btVector3 halfExtents = getHalfExtentsWithMargin(); | |||
vtx = btVector3( | |||
halfExtents.x() * (1-(i&1)) - halfExtents.x() * (i&1), | |||
halfExtents.y() * (1-((i&2)>>1)) - halfExtents.y() * ((i&2)>>1), | |||
halfExtents.z() * (1-((i&4)>>2)) - halfExtents.z() * ((i&4)>>2)); | |||
} | |||
virtual void getPlaneEquation(btVector4& plane,int i) const | |||
{ | |||
btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
switch (i) | |||
{ | |||
case 0: | |||
plane.setValue(btScalar(1.),btScalar(0.),btScalar(0.),-halfExtents.x()); | |||
break; | |||
case 1: | |||
plane.setValue(btScalar(-1.),btScalar(0.),btScalar(0.),-halfExtents.x()); | |||
break; | |||
case 2: | |||
plane.setValue(btScalar(0.),btScalar(1.),btScalar(0.),-halfExtents.y()); | |||
break; | |||
case 3: | |||
plane.setValue(btScalar(0.),btScalar(-1.),btScalar(0.),-halfExtents.y()); | |||
break; | |||
case 4: | |||
plane.setValue(btScalar(0.),btScalar(0.),btScalar(1.),-halfExtents.z()); | |||
break; | |||
case 5: | |||
plane.setValue(btScalar(0.),btScalar(0.),btScalar(-1.),-halfExtents.z()); | |||
break; | |||
default: | |||
btAssert(0); | |||
} | |||
} | |||
virtual void getEdge(int i,btVector3& pa,btVector3& pb) const | |||
//virtual void getEdge(int i,Edge& edge) const | |||
{ | |||
int edgeVert0 = 0; | |||
int edgeVert1 = 0; | |||
switch (i) | |||
{ | |||
case 0: | |||
edgeVert0 = 0; | |||
edgeVert1 = 1; | |||
break; | |||
case 1: | |||
edgeVert0 = 0; | |||
edgeVert1 = 2; | |||
break; | |||
case 2: | |||
edgeVert0 = 1; | |||
edgeVert1 = 3; | |||
break; | |||
case 3: | |||
edgeVert0 = 2; | |||
edgeVert1 = 3; | |||
break; | |||
case 4: | |||
edgeVert0 = 0; | |||
edgeVert1 = 4; | |||
break; | |||
case 5: | |||
edgeVert0 = 1; | |||
edgeVert1 = 5; | |||
break; | |||
case 6: | |||
edgeVert0 = 2; | |||
edgeVert1 = 6; | |||
break; | |||
case 7: | |||
edgeVert0 = 3; | |||
edgeVert1 = 7; | |||
break; | |||
case 8: | |||
edgeVert0 = 4; | |||
edgeVert1 = 5; | |||
break; | |||
case 9: | |||
edgeVert0 = 4; | |||
edgeVert1 = 6; | |||
break; | |||
case 10: | |||
edgeVert0 = 5; | |||
edgeVert1 = 7; | |||
break; | |||
case 11: | |||
edgeVert0 = 6; | |||
edgeVert1 = 7; | |||
break; | |||
default: | |||
btAssert(0); | |||
} | |||
getVertex(edgeVert0,pa ); | |||
getVertex(edgeVert1,pb ); | |||
} | |||
virtual bool isInside(const btVector3& pt,btScalar tolerance) const | |||
{ | |||
btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
//btScalar minDist = 2*tolerance; | |||
bool result = (pt.x() <= (halfExtents.x()+tolerance)) && | |||
(pt.x() >= (-halfExtents.x()-tolerance)) && | |||
(pt.y() <= (halfExtents.y()+tolerance)) && | |||
(pt.y() >= (-halfExtents.y()-tolerance)) && | |||
(pt.z() <= (halfExtents.z()+tolerance)) && | |||
(pt.z() >= (-halfExtents.z()-tolerance)); | |||
return result; | |||
} | |||
//debugging | |||
virtual const char* getName()const | |||
{ | |||
return "Box"; | |||
} | |||
virtual int getNumPreferredPenetrationDirections() const | |||
{ | |||
return 6; | |||
} | |||
virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const | |||
{ | |||
switch (index) | |||
{ | |||
case 0: | |||
penetrationVector.setValue(btScalar(1.),btScalar(0.),btScalar(0.)); | |||
break; | |||
case 1: | |||
penetrationVector.setValue(btScalar(-1.),btScalar(0.),btScalar(0.)); | |||
break; | |||
case 2: | |||
penetrationVector.setValue(btScalar(0.),btScalar(1.),btScalar(0.)); | |||
break; | |||
case 3: | |||
penetrationVector.setValue(btScalar(0.),btScalar(-1.),btScalar(0.)); | |||
break; | |||
case 4: | |||
penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(1.)); | |||
break; | |||
case 5: | |||
penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(-1.)); | |||
break; | |||
default: | |||
btAssert(0); | |||
} | |||
} | |||
}; | |||
#endif //BT_OBB_BOX_MINKOWSKI_H | |||
@@ -0,0 +1,466 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
//#define DISABLE_BVH | |||
#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" | |||
#include "BulletCollision/CollisionShapes/btOptimizedBvh.h" | |||
#include "LinearMath/btSerializer.h" | |||
///Bvh Concave triangle mesh is a static-triangle mesh shape with Bounding Volume Hierarchy optimization. | |||
///Uses an interface to access the triangles to allow for sharing graphics/physics triangles. | |||
btBvhTriangleMeshShape::btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh) | |||
:btTriangleMeshShape(meshInterface), | |||
m_bvh(0), | |||
m_triangleInfoMap(0), | |||
m_useQuantizedAabbCompression(useQuantizedAabbCompression), | |||
m_ownsBvh(false) | |||
{ | |||
m_shapeType = TRIANGLE_MESH_SHAPE_PROXYTYPE; | |||
//construct bvh from meshInterface | |||
#ifndef DISABLE_BVH | |||
if (buildBvh) | |||
{ | |||
buildOptimizedBvh(); | |||
} | |||
#endif //DISABLE_BVH | |||
} | |||
btBvhTriangleMeshShape::btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,bool buildBvh) | |||
:btTriangleMeshShape(meshInterface), | |||
m_bvh(0), | |||
m_triangleInfoMap(0), | |||
m_useQuantizedAabbCompression(useQuantizedAabbCompression), | |||
m_ownsBvh(false) | |||
{ | |||
m_shapeType = TRIANGLE_MESH_SHAPE_PROXYTYPE; | |||
//construct bvh from meshInterface | |||
#ifndef DISABLE_BVH | |||
if (buildBvh) | |||
{ | |||
void* mem = btAlignedAlloc(sizeof(btOptimizedBvh),16); | |||
m_bvh = new (mem) btOptimizedBvh(); | |||
m_bvh->build(meshInterface,m_useQuantizedAabbCompression,bvhAabbMin,bvhAabbMax); | |||
m_ownsBvh = true; | |||
} | |||
#endif //DISABLE_BVH | |||
} | |||
void btBvhTriangleMeshShape::partialRefitTree(const btVector3& aabbMin,const btVector3& aabbMax) | |||
{ | |||
m_bvh->refitPartial( m_meshInterface,aabbMin,aabbMax ); | |||
m_localAabbMin.setMin(aabbMin); | |||
m_localAabbMax.setMax(aabbMax); | |||
} | |||
void btBvhTriangleMeshShape::refitTree(const btVector3& aabbMin,const btVector3& aabbMax) | |||
{ | |||
m_bvh->refit( m_meshInterface, aabbMin,aabbMax ); | |||
recalcLocalAabb(); | |||
} | |||
btBvhTriangleMeshShape::~btBvhTriangleMeshShape() | |||
{ | |||
if (m_ownsBvh) | |||
{ | |||
m_bvh->~btOptimizedBvh(); | |||
btAlignedFree(m_bvh); | |||
} | |||
} | |||
void btBvhTriangleMeshShape::performRaycast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget) | |||
{ | |||
struct MyNodeOverlapCallback : public btNodeOverlapCallback | |||
{ | |||
btStridingMeshInterface* m_meshInterface; | |||
btTriangleCallback* m_callback; | |||
MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface) | |||
:m_meshInterface(meshInterface), | |||
m_callback(callback) | |||
{ | |||
} | |||
virtual void processNode(int nodeSubPart, int nodeTriangleIndex) | |||
{ | |||
btVector3 m_triangle[3]; | |||
const unsigned char *vertexbase; | |||
int numverts; | |||
PHY_ScalarType type; | |||
int stride; | |||
const unsigned char *indexbase; | |||
int indexstride; | |||
int numfaces; | |||
PHY_ScalarType indicestype; | |||
m_meshInterface->getLockedReadOnlyVertexIndexBase( | |||
&vertexbase, | |||
numverts, | |||
type, | |||
stride, | |||
&indexbase, | |||
indexstride, | |||
numfaces, | |||
indicestype, | |||
nodeSubPart); | |||
unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride); | |||
btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT); | |||
const btVector3& meshScaling = m_meshInterface->getScaling(); | |||
for (int j=2;j>=0;j--) | |||
{ | |||
int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; | |||
if (type == PHY_FLOAT) | |||
{ | |||
float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); | |||
m_triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ()); | |||
} | |||
else | |||
{ | |||
double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); | |||
m_triangle[j] = btVector3(btScalar(graphicsbase[0])*meshScaling.getX(),btScalar(graphicsbase[1])*meshScaling.getY(),btScalar(graphicsbase[2])*meshScaling.getZ()); | |||
} | |||
} | |||
/* Perform ray vs. triangle collision here */ | |||
m_callback->processTriangle(m_triangle,nodeSubPart,nodeTriangleIndex); | |||
m_meshInterface->unLockReadOnlyVertexBase(nodeSubPart); | |||
} | |||
}; | |||
MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface); | |||
m_bvh->reportRayOverlappingNodex(&myNodeCallback,raySource,rayTarget); | |||
} | |||
void btBvhTriangleMeshShape::performConvexcast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax) | |||
{ | |||
struct MyNodeOverlapCallback : public btNodeOverlapCallback | |||
{ | |||
btStridingMeshInterface* m_meshInterface; | |||
btTriangleCallback* m_callback; | |||
MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface) | |||
:m_meshInterface(meshInterface), | |||
m_callback(callback) | |||
{ | |||
} | |||
virtual void processNode(int nodeSubPart, int nodeTriangleIndex) | |||
{ | |||
btVector3 m_triangle[3]; | |||
const unsigned char *vertexbase; | |||
int numverts; | |||
PHY_ScalarType type; | |||
int stride; | |||
const unsigned char *indexbase; | |||
int indexstride; | |||
int numfaces; | |||
PHY_ScalarType indicestype; | |||
m_meshInterface->getLockedReadOnlyVertexIndexBase( | |||
&vertexbase, | |||
numverts, | |||
type, | |||
stride, | |||
&indexbase, | |||
indexstride, | |||
numfaces, | |||
indicestype, | |||
nodeSubPart); | |||
unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride); | |||
btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT); | |||
const btVector3& meshScaling = m_meshInterface->getScaling(); | |||
for (int j=2;j>=0;j--) | |||
{ | |||
int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; | |||
if (type == PHY_FLOAT) | |||
{ | |||
float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); | |||
m_triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ()); | |||
} | |||
else | |||
{ | |||
double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); | |||
m_triangle[j] = btVector3(btScalar(graphicsbase[0])*meshScaling.getX(),btScalar(graphicsbase[1])*meshScaling.getY(),btScalar(graphicsbase[2])*meshScaling.getZ()); | |||
} | |||
} | |||
/* Perform ray vs. triangle collision here */ | |||
m_callback->processTriangle(m_triangle,nodeSubPart,nodeTriangleIndex); | |||
m_meshInterface->unLockReadOnlyVertexBase(nodeSubPart); | |||
} | |||
}; | |||
MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface); | |||
m_bvh->reportBoxCastOverlappingNodex (&myNodeCallback, raySource, rayTarget, aabbMin, aabbMax); | |||
} | |||
//perform bvh tree traversal and report overlapping triangles to 'callback' | |||
void btBvhTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const | |||
{ | |||
#ifdef DISABLE_BVH | |||
//brute force traverse all triangles | |||
btTriangleMeshShape::processAllTriangles(callback,aabbMin,aabbMax); | |||
#else | |||
//first get all the nodes | |||
struct MyNodeOverlapCallback : public btNodeOverlapCallback | |||
{ | |||
btStridingMeshInterface* m_meshInterface; | |||
btTriangleCallback* m_callback; | |||
btVector3 m_triangle[3]; | |||
MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface) | |||
:m_meshInterface(meshInterface), | |||
m_callback(callback) | |||
{ | |||
} | |||
virtual void processNode(int nodeSubPart, int nodeTriangleIndex) | |||
{ | |||
const unsigned char *vertexbase; | |||
int numverts; | |||
PHY_ScalarType type; | |||
int stride; | |||
const unsigned char *indexbase; | |||
int indexstride; | |||
int numfaces; | |||
PHY_ScalarType indicestype; | |||
m_meshInterface->getLockedReadOnlyVertexIndexBase( | |||
&vertexbase, | |||
numverts, | |||
type, | |||
stride, | |||
&indexbase, | |||
indexstride, | |||
numfaces, | |||
indicestype, | |||
nodeSubPart); | |||
unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride); | |||
btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT||indicestype==PHY_UCHAR); | |||
const btVector3& meshScaling = m_meshInterface->getScaling(); | |||
for (int j=2;j>=0;j--) | |||
{ | |||
int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:indicestype==PHY_INTEGER?gfxbase[j]:((unsigned char*)gfxbase)[j]; | |||
#ifdef DEBUG_TRIANGLE_MESH | |||
printf("%d ,",graphicsindex); | |||
#endif //DEBUG_TRIANGLE_MESH | |||
if (type == PHY_FLOAT) | |||
{ | |||
float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); | |||
m_triangle[j] = btVector3( | |||
graphicsbase[0]*meshScaling.getX(), | |||
graphicsbase[1]*meshScaling.getY(), | |||
graphicsbase[2]*meshScaling.getZ()); | |||
} | |||
else | |||
{ | |||
double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); | |||
m_triangle[j] = btVector3( | |||
btScalar(graphicsbase[0])*meshScaling.getX(), | |||
btScalar(graphicsbase[1])*meshScaling.getY(), | |||
btScalar(graphicsbase[2])*meshScaling.getZ()); | |||
} | |||
#ifdef DEBUG_TRIANGLE_MESH | |||
printf("triangle vertices:%f,%f,%f\n",triangle[j].x(),triangle[j].y(),triangle[j].z()); | |||
#endif //DEBUG_TRIANGLE_MESH | |||
} | |||
m_callback->processTriangle(m_triangle,nodeSubPart,nodeTriangleIndex); | |||
m_meshInterface->unLockReadOnlyVertexBase(nodeSubPart); | |||
} | |||
}; | |||
MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface); | |||
m_bvh->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax); | |||
#endif//DISABLE_BVH | |||
} | |||
void btBvhTriangleMeshShape::setLocalScaling(const btVector3& scaling) | |||
{ | |||
if ((getLocalScaling() -scaling).length2() > SIMD_EPSILON) | |||
{ | |||
btTriangleMeshShape::setLocalScaling(scaling); | |||
buildOptimizedBvh(); | |||
} | |||
} | |||
void btBvhTriangleMeshShape::buildOptimizedBvh() | |||
{ | |||
if (m_ownsBvh) | |||
{ | |||
m_bvh->~btOptimizedBvh(); | |||
btAlignedFree(m_bvh); | |||
} | |||
///m_localAabbMin/m_localAabbMax is already re-calculated in btTriangleMeshShape. We could just scale aabb, but this needs some more work | |||
void* mem = btAlignedAlloc(sizeof(btOptimizedBvh),16); | |||
m_bvh = new(mem) btOptimizedBvh(); | |||
//rebuild the bvh... | |||
m_bvh->build(m_meshInterface,m_useQuantizedAabbCompression,m_localAabbMin,m_localAabbMax); | |||
m_ownsBvh = true; | |||
} | |||
void btBvhTriangleMeshShape::setOptimizedBvh(btOptimizedBvh* bvh, const btVector3& scaling) | |||
{ | |||
btAssert(!m_bvh); | |||
btAssert(!m_ownsBvh); | |||
m_bvh = bvh; | |||
m_ownsBvh = false; | |||
// update the scaling without rebuilding the bvh | |||
if ((getLocalScaling() -scaling).length2() > SIMD_EPSILON) | |||
{ | |||
btTriangleMeshShape::setLocalScaling(scaling); | |||
} | |||
} | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
const char* btBvhTriangleMeshShape::serialize(void* dataBuffer, btSerializer* serializer) const | |||
{ | |||
btTriangleMeshShapeData* trimeshData = (btTriangleMeshShapeData*) dataBuffer; | |||
btCollisionShape::serialize(&trimeshData->m_collisionShapeData,serializer); | |||
m_meshInterface->serialize(&trimeshData->m_meshInterface, serializer); | |||
trimeshData->m_collisionMargin = float(m_collisionMargin); | |||
if (m_bvh && !(serializer->getSerializationFlags()&BT_SERIALIZE_NO_BVH)) | |||
{ | |||
void* chunk = serializer->findPointer(m_bvh); | |||
if (chunk) | |||
{ | |||
#ifdef BT_USE_DOUBLE_PRECISION | |||
trimeshData->m_quantizedDoubleBvh = (btQuantizedBvhData*)chunk; | |||
trimeshData->m_quantizedFloatBvh = 0; | |||
#else | |||
trimeshData->m_quantizedFloatBvh = (btQuantizedBvhData*)chunk; | |||
trimeshData->m_quantizedDoubleBvh= 0; | |||
#endif //BT_USE_DOUBLE_PRECISION | |||
} else | |||
{ | |||
#ifdef BT_USE_DOUBLE_PRECISION | |||
trimeshData->m_quantizedDoubleBvh = (btQuantizedBvhData*)serializer->getUniquePointer(m_bvh); | |||
trimeshData->m_quantizedFloatBvh = 0; | |||
#else | |||
trimeshData->m_quantizedFloatBvh = (btQuantizedBvhData*)serializer->getUniquePointer(m_bvh); | |||
trimeshData->m_quantizedDoubleBvh= 0; | |||
#endif //BT_USE_DOUBLE_PRECISION | |||
int sz = m_bvh->calculateSerializeBufferSizeNew(); | |||
btChunk* chunk = serializer->allocate(sz,1); | |||
const char* structType = m_bvh->serialize(chunk->m_oldPtr, serializer); | |||
serializer->finalizeChunk(chunk,structType,BT_QUANTIZED_BVH_CODE,m_bvh); | |||
} | |||
} else | |||
{ | |||
trimeshData->m_quantizedFloatBvh = 0; | |||
trimeshData->m_quantizedDoubleBvh = 0; | |||
} | |||
if (m_triangleInfoMap && !(serializer->getSerializationFlags()&BT_SERIALIZE_NO_TRIANGLEINFOMAP)) | |||
{ | |||
void* chunk = serializer->findPointer(m_triangleInfoMap); | |||
if (chunk) | |||
{ | |||
trimeshData->m_triangleInfoMap = (btTriangleInfoMapData*)chunk; | |||
} else | |||
{ | |||
trimeshData->m_triangleInfoMap = (btTriangleInfoMapData*)serializer->getUniquePointer(m_triangleInfoMap); | |||
int sz = m_triangleInfoMap->calculateSerializeBufferSize(); | |||
btChunk* chunk = serializer->allocate(sz,1); | |||
const char* structType = m_triangleInfoMap->serialize(chunk->m_oldPtr, serializer); | |||
serializer->finalizeChunk(chunk,structType,BT_TRIANLGE_INFO_MAP,m_triangleInfoMap); | |||
} | |||
} else | |||
{ | |||
trimeshData->m_triangleInfoMap = 0; | |||
} | |||
return "btTriangleMeshShapeData"; | |||
} | |||
void btBvhTriangleMeshShape::serializeSingleBvh(btSerializer* serializer) const | |||
{ | |||
if (m_bvh) | |||
{ | |||
int len = m_bvh->calculateSerializeBufferSizeNew(); //make sure not to use calculateSerializeBufferSize because it is used for in-place | |||
btChunk* chunk = serializer->allocate(len,1); | |||
const char* structType = m_bvh->serialize(chunk->m_oldPtr, serializer); | |||
serializer->finalizeChunk(chunk,structType,BT_QUANTIZED_BVH_CODE,(void*)m_bvh); | |||
} | |||
} | |||
void btBvhTriangleMeshShape::serializeSingleTriangleInfoMap(btSerializer* serializer) const | |||
{ | |||
if (m_triangleInfoMap) | |||
{ | |||
int len = m_triangleInfoMap->calculateSerializeBufferSize(); | |||
btChunk* chunk = serializer->allocate(len,1); | |||
const char* structType = m_triangleInfoMap->serialize(chunk->m_oldPtr, serializer); | |||
serializer->finalizeChunk(chunk,structType,BT_TRIANLGE_INFO_MAP,(void*)m_triangleInfoMap); | |||
} | |||
} | |||
@@ -0,0 +1,139 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
#ifndef BT_BVH_TRIANGLE_MESH_SHAPE_H | |||
#define BT_BVH_TRIANGLE_MESH_SHAPE_H | |||
#include "btTriangleMeshShape.h" | |||
#include "btOptimizedBvh.h" | |||
#include "LinearMath/btAlignedAllocator.h" | |||
#include "btTriangleInfoMap.h" | |||
///The btBvhTriangleMeshShape is a static-triangle mesh shape with several optimizations, such as bounding volume hierarchy and cache friendly traversal for PlayStation 3 Cell SPU. It is recommended to enable useQuantizedAabbCompression for better memory usage. | |||
///It takes a triangle mesh as input, for example a btTriangleMesh or btTriangleIndexVertexArray. The btBvhTriangleMeshShape class allows for triangle mesh deformations by a refit or partialRefit method. | |||
///Instead of building the bounding volume hierarchy acceleration structure, it is also possible to serialize (save) and deserialize (load) the structure from disk. | |||
///See Demos\ConcaveDemo\ConcavePhysicsDemo.cpp for an example. | |||
ATTRIBUTE_ALIGNED16(class) btBvhTriangleMeshShape : public btTriangleMeshShape | |||
{ | |||
btOptimizedBvh* m_bvh; | |||
btTriangleInfoMap* m_triangleInfoMap; | |||
bool m_useQuantizedAabbCompression; | |||
bool m_ownsBvh; | |||
bool m_pad[11];////need padding due to alignment | |||
public: | |||
BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh = true); | |||
///optionally pass in a larger bvh aabb, used for quantization. This allows for deformations within this aabb | |||
btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax, bool buildBvh = true); | |||
virtual ~btBvhTriangleMeshShape(); | |||
bool getOwnsBvh () const | |||
{ | |||
return m_ownsBvh; | |||
} | |||
void performRaycast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget); | |||
void performConvexcast (btTriangleCallback* callback, const btVector3& boxSource, const btVector3& boxTarget, const btVector3& boxMin, const btVector3& boxMax); | |||
virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; | |||
void refitTree(const btVector3& aabbMin,const btVector3& aabbMax); | |||
///for a fast incremental refit of parts of the tree. Note: the entire AABB of the tree will become more conservative, it never shrinks | |||
void partialRefitTree(const btVector3& aabbMin,const btVector3& aabbMax); | |||
//debugging | |||
virtual const char* getName()const {return "BVHTRIANGLEMESH";} | |||
virtual void setLocalScaling(const btVector3& scaling); | |||
btOptimizedBvh* getOptimizedBvh() | |||
{ | |||
return m_bvh; | |||
} | |||
void setOptimizedBvh(btOptimizedBvh* bvh, const btVector3& localScaling=btVector3(1,1,1)); | |||
void buildOptimizedBvh(); | |||
bool usesQuantizedAabbCompression() const | |||
{ | |||
return m_useQuantizedAabbCompression; | |||
} | |||
void setTriangleInfoMap(btTriangleInfoMap* triangleInfoMap) | |||
{ | |||
m_triangleInfoMap = triangleInfoMap; | |||
} | |||
const btTriangleInfoMap* getTriangleInfoMap() const | |||
{ | |||
return m_triangleInfoMap; | |||
} | |||
btTriangleInfoMap* getTriangleInfoMap() | |||
{ | |||
return m_triangleInfoMap; | |||
} | |||
virtual int calculateSerializeBufferSize() const; | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
virtual void serializeSingleBvh(btSerializer* serializer) const; | |||
virtual void serializeSingleTriangleInfoMap(btSerializer* serializer) const; | |||
}; | |||
///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
struct btTriangleMeshShapeData | |||
{ | |||
btCollisionShapeData m_collisionShapeData; | |||
btStridingMeshInterfaceData m_meshInterface; | |||
btQuantizedBvhFloatData *m_quantizedFloatBvh; | |||
btQuantizedBvhDoubleData *m_quantizedDoubleBvh; | |||
btTriangleInfoMapData *m_triangleInfoMap; | |||
float m_collisionMargin; | |||
char m_pad3[4]; | |||
}; | |||
SIMD_FORCE_INLINE int btBvhTriangleMeshShape::calculateSerializeBufferSize() const | |||
{ | |||
return sizeof(btTriangleMeshShapeData); | |||
} | |||
#endif //BT_BVH_TRIANGLE_MESH_SHAPE_H |
@@ -0,0 +1,171 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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 "btCapsuleShape.h" | |||
#include "BulletCollision/CollisionShapes/btCollisionMargin.h" | |||
#include "LinearMath/btQuaternion.h" | |||
btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height) : btConvexInternalShape () | |||
{ | |||
m_shapeType = CAPSULE_SHAPE_PROXYTYPE; | |||
m_upAxis = 1; | |||
m_implicitShapeDimensions.setValue(radius,0.5f*height,radius); | |||
} | |||
btVector3 btCapsuleShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const | |||
{ | |||
btVector3 supVec(0,0,0); | |||
btScalar maxDot(btScalar(-BT_LARGE_FLOAT)); | |||
btVector3 vec = vec0; | |||
btScalar lenSqr = vec.length2(); | |||
if (lenSqr < btScalar(0.0001)) | |||
{ | |||
vec.setValue(1,0,0); | |||
} else | |||
{ | |||
btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); | |||
vec *= rlen; | |||
} | |||
btVector3 vtx; | |||
btScalar newDot; | |||
btScalar radius = getRadius(); | |||
{ | |||
btVector3 pos(0,0,0); | |||
pos[getUpAxis()] = getHalfHeight(); | |||
vtx = pos +vec*(radius) - vec * getMargin(); | |||
newDot = vec.dot(vtx); | |||
if (newDot > maxDot) | |||
{ | |||
maxDot = newDot; | |||
supVec = vtx; | |||
} | |||
} | |||
{ | |||
btVector3 pos(0,0,0); | |||
pos[getUpAxis()] = -getHalfHeight(); | |||
vtx = pos +vec*(radius) - vec * getMargin(); | |||
newDot = vec.dot(vtx); | |||
if (newDot > maxDot) | |||
{ | |||
maxDot = newDot; | |||
supVec = vtx; | |||
} | |||
} | |||
return supVec; | |||
} | |||
void btCapsuleShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
{ | |||
btScalar radius = getRadius(); | |||
for (int j=0;j<numVectors;j++) | |||
{ | |||
btScalar maxDot(btScalar(-BT_LARGE_FLOAT)); | |||
const btVector3& vec = vectors[j]; | |||
btVector3 vtx; | |||
btScalar newDot; | |||
{ | |||
btVector3 pos(0,0,0); | |||
pos[getUpAxis()] = getHalfHeight(); | |||
vtx = pos +vec*(radius) - vec * getMargin(); | |||
newDot = vec.dot(vtx); | |||
if (newDot > maxDot) | |||
{ | |||
maxDot = newDot; | |||
supportVerticesOut[j] = vtx; | |||
} | |||
} | |||
{ | |||
btVector3 pos(0,0,0); | |||
pos[getUpAxis()] = -getHalfHeight(); | |||
vtx = pos +vec*(radius) - vec * getMargin(); | |||
newDot = vec.dot(vtx); | |||
if (newDot > maxDot) | |||
{ | |||
maxDot = newDot; | |||
supportVerticesOut[j] = vtx; | |||
} | |||
} | |||
} | |||
} | |||
void btCapsuleShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const | |||
{ | |||
//as an approximation, take the inertia of the box that bounds the spheres | |||
btTransform ident; | |||
ident.setIdentity(); | |||
btScalar radius = getRadius(); | |||
btVector3 halfExtents(radius,radius,radius); | |||
halfExtents[getUpAxis()]+=getHalfHeight(); | |||
btScalar margin = CONVEX_DISTANCE_MARGIN; | |||
btScalar lx=btScalar(2.)*(halfExtents[0]+margin); | |||
btScalar ly=btScalar(2.)*(halfExtents[1]+margin); | |||
btScalar lz=btScalar(2.)*(halfExtents[2]+margin); | |||
const btScalar x2 = lx*lx; | |||
const btScalar y2 = ly*ly; | |||
const btScalar z2 = lz*lz; | |||
const btScalar scaledmass = mass * btScalar(.08333333); | |||
inertia[0] = scaledmass * (y2+z2); | |||
inertia[1] = scaledmass * (x2+z2); | |||
inertia[2] = scaledmass * (x2+y2); | |||
} | |||
btCapsuleShapeX::btCapsuleShapeX(btScalar radius,btScalar height) | |||
{ | |||
m_upAxis = 0; | |||
m_implicitShapeDimensions.setValue(0.5f*height, radius,radius); | |||
} | |||
btCapsuleShapeZ::btCapsuleShapeZ(btScalar radius,btScalar height) | |||
{ | |||
m_upAxis = 2; | |||
m_implicitShapeDimensions.setValue(radius,radius,0.5f*height); | |||
} | |||
@@ -0,0 +1,173 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
#ifndef BT_CAPSULE_SHAPE_H | |||
#define BT_CAPSULE_SHAPE_H | |||
#include "btConvexInternalShape.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types | |||
///The btCapsuleShape represents a capsule around the Y axis, there is also the btCapsuleShapeX aligned around the X axis and btCapsuleShapeZ around the Z axis. | |||
///The total height is height+2*radius, so the height is just the height between the center of each 'sphere' of the capsule caps. | |||
///The btCapsuleShape is a convex hull of two spheres. The btMultiSphereShape is a more general collision shape that takes the convex hull of multiple sphere, so it can also represent a capsule when just using two spheres. | |||
class btCapsuleShape : public btConvexInternalShape | |||
{ | |||
protected: | |||
int m_upAxis; | |||
protected: | |||
///only used for btCapsuleShapeZ and btCapsuleShapeX subclasses. | |||
btCapsuleShape() : btConvexInternalShape() {m_shapeType = CAPSULE_SHAPE_PROXYTYPE;}; | |||
public: | |||
btCapsuleShape(btScalar radius,btScalar height); | |||
///CollisionShape Interface | |||
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; | |||
/// btConvexShape Interface | |||
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; | |||
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; | |||
virtual void setMargin(btScalar collisionMargin) | |||
{ | |||
//correct the m_implicitShapeDimensions for the margin | |||
btVector3 oldMargin(getMargin(),getMargin(),getMargin()); | |||
btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; | |||
btConvexInternalShape::setMargin(collisionMargin); | |||
btVector3 newMargin(getMargin(),getMargin(),getMargin()); | |||
m_implicitShapeDimensions = implicitShapeDimensionsWithMargin - newMargin; | |||
} | |||
virtual void getAabb (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const | |||
{ | |||
btVector3 halfExtents(getRadius(),getRadius(),getRadius()); | |||
halfExtents[m_upAxis] = getRadius() + getHalfHeight(); | |||
halfExtents += btVector3(getMargin(),getMargin(),getMargin()); | |||
btMatrix3x3 abs_b = t.getBasis().absolute(); | |||
btVector3 center = t.getOrigin(); | |||
btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); | |||
aabbMin = center - extent; | |||
aabbMax = center + extent; | |||
} | |||
virtual const char* getName()const | |||
{ | |||
return "CapsuleShape"; | |||
} | |||
int getUpAxis() const | |||
{ | |||
return m_upAxis; | |||
} | |||
btScalar getRadius() const | |||
{ | |||
int radiusAxis = (m_upAxis+2)%3; | |||
return m_implicitShapeDimensions[radiusAxis]; | |||
} | |||
btScalar getHalfHeight() const | |||
{ | |||
return m_implicitShapeDimensions[m_upAxis]; | |||
} | |||
virtual void setLocalScaling(const btVector3& scaling) | |||
{ | |||
btVector3 oldMargin(getMargin(),getMargin(),getMargin()); | |||
btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; | |||
btVector3 unScaledImplicitShapeDimensionsWithMargin = implicitShapeDimensionsWithMargin / m_localScaling; | |||
btConvexInternalShape::setLocalScaling(scaling); | |||
m_implicitShapeDimensions = (unScaledImplicitShapeDimensionsWithMargin * m_localScaling) - oldMargin; | |||
} | |||
virtual int calculateSerializeBufferSize() const; | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
}; | |||
///btCapsuleShapeX represents a capsule around the Z axis | |||
///the total height is height+2*radius, so the height is just the height between the center of each 'sphere' of the capsule caps. | |||
class btCapsuleShapeX : public btCapsuleShape | |||
{ | |||
public: | |||
btCapsuleShapeX(btScalar radius,btScalar height); | |||
//debugging | |||
virtual const char* getName()const | |||
{ | |||
return "CapsuleX"; | |||
} | |||
}; | |||
///btCapsuleShapeZ represents a capsule around the Z axis | |||
///the total height is height+2*radius, so the height is just the height between the center of each 'sphere' of the capsule caps. | |||
class btCapsuleShapeZ : public btCapsuleShape | |||
{ | |||
public: | |||
btCapsuleShapeZ(btScalar radius,btScalar height); | |||
//debugging | |||
virtual const char* getName()const | |||
{ | |||
return "CapsuleZ"; | |||
} | |||
}; | |||
///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
struct btCapsuleShapeData | |||
{ | |||
btConvexInternalShapeData m_convexInternalShapeData; | |||
int m_upAxis; | |||
char m_padding[4]; | |||
}; | |||
SIMD_FORCE_INLINE int btCapsuleShape::calculateSerializeBufferSize() const | |||
{ | |||
return sizeof(btCapsuleShapeData); | |||
} | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
SIMD_FORCE_INLINE const char* btCapsuleShape::serialize(void* dataBuffer, btSerializer* serializer) const | |||
{ | |||
btCapsuleShapeData* shapeData = (btCapsuleShapeData*) dataBuffer; | |||
btConvexInternalShape::serialize(&shapeData->m_convexInternalShapeData,serializer); | |||
shapeData->m_upAxis = m_upAxis; | |||
return "btCapsuleShapeData"; | |||
} | |||
#endif //BT_CAPSULE_SHAPE_H |
@@ -0,0 +1,27 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
#ifndef BT_COLLISION_MARGIN_H | |||
#define BT_COLLISION_MARGIN_H | |||
///The CONVEX_DISTANCE_MARGIN is a default collision margin for convex collision shapes derived from btConvexInternalShape. | |||
///This collision margin is used by Gjk and some other algorithms | |||
///Note that when creating small objects, you need to make sure to set a smaller collision margin, using the 'setMargin' API | |||
#define CONVEX_DISTANCE_MARGIN btScalar(0.04)// btScalar(0.1)//;//btScalar(0.01) | |||
#endif //BT_COLLISION_MARGIN_H | |||
@@ -0,0 +1,119 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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 "BulletCollision/CollisionShapes/btCollisionShape.h" | |||
#include "LinearMath/btSerializer.h" | |||
/* | |||
Make sure this dummy function never changes so that it | |||
can be used by probes that are checking whether the | |||
library is actually installed. | |||
*/ | |||
extern "C" | |||
{ | |||
void btBulletCollisionProbe (); | |||
void btBulletCollisionProbe () {} | |||
} | |||
void btCollisionShape::getBoundingSphere(btVector3& center,btScalar& radius) const | |||
{ | |||
btTransform tr; | |||
tr.setIdentity(); | |||
btVector3 aabbMin,aabbMax; | |||
getAabb(tr,aabbMin,aabbMax); | |||
radius = (aabbMax-aabbMin).length()*btScalar(0.5); | |||
center = (aabbMin+aabbMax)*btScalar(0.5); | |||
} | |||
btScalar btCollisionShape::getContactBreakingThreshold(btScalar defaultContactThreshold) const | |||
{ | |||
return getAngularMotionDisc() * defaultContactThreshold; | |||
} | |||
btScalar btCollisionShape::getAngularMotionDisc() const | |||
{ | |||
///@todo cache this value, to improve performance | |||
btVector3 center; | |||
btScalar disc; | |||
getBoundingSphere(center,disc); | |||
disc += (center).length(); | |||
return disc; | |||
} | |||
void btCollisionShape::calculateTemporalAabb(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep, btVector3& temporalAabbMin,btVector3& temporalAabbMax) const | |||
{ | |||
//start with static aabb | |||
getAabb(curTrans,temporalAabbMin,temporalAabbMax); | |||
btScalar temporalAabbMaxx = temporalAabbMax.getX(); | |||
btScalar temporalAabbMaxy = temporalAabbMax.getY(); | |||
btScalar temporalAabbMaxz = temporalAabbMax.getZ(); | |||
btScalar temporalAabbMinx = temporalAabbMin.getX(); | |||
btScalar temporalAabbMiny = temporalAabbMin.getY(); | |||
btScalar temporalAabbMinz = temporalAabbMin.getZ(); | |||
// add linear motion | |||
btVector3 linMotion = linvel*timeStep; | |||
///@todo: simd would have a vector max/min operation, instead of per-element access | |||
if (linMotion.x() > btScalar(0.)) | |||
temporalAabbMaxx += linMotion.x(); | |||
else | |||
temporalAabbMinx += linMotion.x(); | |||
if (linMotion.y() > btScalar(0.)) | |||
temporalAabbMaxy += linMotion.y(); | |||
else | |||
temporalAabbMiny += linMotion.y(); | |||
if (linMotion.z() > btScalar(0.)) | |||
temporalAabbMaxz += linMotion.z(); | |||
else | |||
temporalAabbMinz += linMotion.z(); | |||
//add conservative angular motion | |||
btScalar angularMotion = angvel.length() * getAngularMotionDisc() * timeStep; | |||
btVector3 angularMotion3d(angularMotion,angularMotion,angularMotion); | |||
temporalAabbMin = btVector3(temporalAabbMinx,temporalAabbMiny,temporalAabbMinz); | |||
temporalAabbMax = btVector3(temporalAabbMaxx,temporalAabbMaxy,temporalAabbMaxz); | |||
temporalAabbMin -= angularMotion3d; | |||
temporalAabbMax += angularMotion3d; | |||
} | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
const char* btCollisionShape::serialize(void* dataBuffer, btSerializer* serializer) const | |||
{ | |||
btCollisionShapeData* shapeData = (btCollisionShapeData*) dataBuffer; | |||
char* name = (char*) serializer->findNameForPointer(this); | |||
shapeData->m_name = (char*)serializer->getUniquePointer(name); | |||
if (shapeData->m_name) | |||
{ | |||
serializer->serializeName(name); | |||
} | |||
shapeData->m_shapeType = m_shapeType; | |||
//shapeData->m_padding//?? | |||
return "btCollisionShapeData"; | |||
} | |||
void btCollisionShape::serializeSingleShape(btSerializer* serializer) const | |||
{ | |||
int len = calculateSerializeBufferSize(); | |||
btChunk* chunk = serializer->allocate(len,1); | |||
const char* structType = serialize(chunk->m_oldPtr, serializer); | |||
serializer->finalizeChunk(chunk,structType,BT_SHAPE_CODE,(void*)this); | |||
} |
@@ -0,0 +1,150 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
#ifndef BT_COLLISION_SHAPE_H | |||
#define BT_COLLISION_SHAPE_H | |||
#include "LinearMath/btTransform.h" | |||
#include "LinearMath/btVector3.h" | |||
#include "LinearMath/btMatrix3x3.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" //for the shape types | |||
class btSerializer; | |||
///The btCollisionShape class provides an interface for collision shapes that can be shared among btCollisionObjects. | |||
class btCollisionShape | |||
{ | |||
protected: | |||
int m_shapeType; | |||
void* m_userPointer; | |||
public: | |||
btCollisionShape() : m_shapeType (INVALID_SHAPE_PROXYTYPE), m_userPointer(0) | |||
{ | |||
} | |||
virtual ~btCollisionShape() | |||
{ | |||
} | |||
///getAabb returns the axis aligned bounding box in the coordinate frame of the given transform t. | |||
virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const =0; | |||
virtual void getBoundingSphere(btVector3& center,btScalar& radius) const; | |||
///getAngularMotionDisc returns the maximus radius needed for Conservative Advancement to handle time-of-impact with rotations. | |||
virtual btScalar getAngularMotionDisc() const; | |||
virtual btScalar getContactBreakingThreshold(btScalar defaultContactThresholdFactor) const; | |||
///calculateTemporalAabb calculates the enclosing aabb for the moving object over interval [0..timeStep) | |||
///result is conservative | |||
void calculateTemporalAabb(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep, btVector3& temporalAabbMin,btVector3& temporalAabbMax) const; | |||
SIMD_FORCE_INLINE bool isPolyhedral() const | |||
{ | |||
return btBroadphaseProxy::isPolyhedral(getShapeType()); | |||
} | |||
SIMD_FORCE_INLINE bool isConvex2d() const | |||
{ | |||
return btBroadphaseProxy::isConvex2d(getShapeType()); | |||
} | |||
SIMD_FORCE_INLINE bool isConvex() const | |||
{ | |||
return btBroadphaseProxy::isConvex(getShapeType()); | |||
} | |||
SIMD_FORCE_INLINE bool isNonMoving() const | |||
{ | |||
return btBroadphaseProxy::isNonMoving(getShapeType()); | |||
} | |||
SIMD_FORCE_INLINE bool isConcave() const | |||
{ | |||
return btBroadphaseProxy::isConcave(getShapeType()); | |||
} | |||
SIMD_FORCE_INLINE bool isCompound() const | |||
{ | |||
return btBroadphaseProxy::isCompound(getShapeType()); | |||
} | |||
SIMD_FORCE_INLINE bool isSoftBody() const | |||
{ | |||
return btBroadphaseProxy::isSoftBody(getShapeType()); | |||
} | |||
///isInfinite is used to catch simulation error (aabb check) | |||
SIMD_FORCE_INLINE bool isInfinite() const | |||
{ | |||
return btBroadphaseProxy::isInfinite(getShapeType()); | |||
} | |||
#ifndef __SPU__ | |||
virtual void setLocalScaling(const btVector3& scaling) =0; | |||
virtual const btVector3& getLocalScaling() const =0; | |||
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const = 0; | |||
//debugging support | |||
virtual const char* getName()const =0 ; | |||
#endif //__SPU__ | |||
int getShapeType() const { return m_shapeType; } | |||
virtual void setMargin(btScalar margin) = 0; | |||
virtual btScalar getMargin() const = 0; | |||
///optional user data pointer | |||
void setUserPointer(void* userPtr) | |||
{ | |||
m_userPointer = userPtr; | |||
} | |||
void* getUserPointer() const | |||
{ | |||
return m_userPointer; | |||
} | |||
virtual int calculateSerializeBufferSize() const; | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
virtual void serializeSingleShape(btSerializer* serializer) const; | |||
}; | |||
///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
struct btCollisionShapeData | |||
{ | |||
char *m_name; | |||
int m_shapeType; | |||
char m_padding[4]; | |||
}; | |||
SIMD_FORCE_INLINE int btCollisionShape::calculateSerializeBufferSize() const | |||
{ | |||
return sizeof(btCollisionShapeData); | |||
} | |||
#endif //BT_COLLISION_SHAPE_H | |||
@@ -0,0 +1,356 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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 "btCompoundShape.h" | |||
#include "btCollisionShape.h" | |||
#include "BulletCollision/BroadphaseCollision/btDbvt.h" | |||
#include "LinearMath/btSerializer.h" | |||
btCompoundShape::btCompoundShape(bool enableDynamicAabbTree) | |||
: m_localAabbMin(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)), | |||
m_localAabbMax(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)), | |||
m_dynamicAabbTree(0), | |||
m_updateRevision(1), | |||
m_collisionMargin(btScalar(0.)), | |||
m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.)) | |||
{ | |||
m_shapeType = COMPOUND_SHAPE_PROXYTYPE; | |||
if (enableDynamicAabbTree) | |||
{ | |||
void* mem = btAlignedAlloc(sizeof(btDbvt),16); | |||
m_dynamicAabbTree = new(mem) btDbvt(); | |||
btAssert(mem==m_dynamicAabbTree); | |||
} | |||
} | |||
btCompoundShape::~btCompoundShape() | |||
{ | |||
if (m_dynamicAabbTree) | |||
{ | |||
m_dynamicAabbTree->~btDbvt(); | |||
btAlignedFree(m_dynamicAabbTree); | |||
} | |||
} | |||
void btCompoundShape::addChildShape(const btTransform& localTransform,btCollisionShape* shape) | |||
{ | |||
m_updateRevision++; | |||
//m_childTransforms.push_back(localTransform); | |||
//m_childShapes.push_back(shape); | |||
btCompoundShapeChild child; | |||
child.m_node = 0; | |||
child.m_transform = localTransform; | |||
child.m_childShape = shape; | |||
child.m_childShapeType = shape->getShapeType(); | |||
child.m_childMargin = shape->getMargin(); | |||
//extend the local aabbMin/aabbMax | |||
btVector3 localAabbMin,localAabbMax; | |||
shape->getAabb(localTransform,localAabbMin,localAabbMax); | |||
for (int i=0;i<3;i++) | |||
{ | |||
if (m_localAabbMin[i] > localAabbMin[i]) | |||
{ | |||
m_localAabbMin[i] = localAabbMin[i]; | |||
} | |||
if (m_localAabbMax[i] < localAabbMax[i]) | |||
{ | |||
m_localAabbMax[i] = localAabbMax[i]; | |||
} | |||
} | |||
if (m_dynamicAabbTree) | |||
{ | |||
const btDbvtVolume bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); | |||
int index = m_children.size(); | |||
child.m_node = m_dynamicAabbTree->insert(bounds,(void*)index); | |||
} | |||
m_children.push_back(child); | |||
} | |||
void btCompoundShape::updateChildTransform(int childIndex, const btTransform& newChildTransform,bool shouldRecalculateLocalAabb) | |||
{ | |||
m_children[childIndex].m_transform = newChildTransform; | |||
if (m_dynamicAabbTree) | |||
{ | |||
///update the dynamic aabb tree | |||
btVector3 localAabbMin,localAabbMax; | |||
m_children[childIndex].m_childShape->getAabb(newChildTransform,localAabbMin,localAabbMax); | |||
ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); | |||
//int index = m_children.size()-1; | |||
m_dynamicAabbTree->update(m_children[childIndex].m_node,bounds); | |||
} | |||
if (shouldRecalculateLocalAabb) | |||
{ | |||
recalculateLocalAabb(); | |||
} | |||
} | |||
void btCompoundShape::removeChildShapeByIndex(int childShapeIndex) | |||
{ | |||
m_updateRevision++; | |||
btAssert(childShapeIndex >=0 && childShapeIndex < m_children.size()); | |||
if (m_dynamicAabbTree) | |||
{ | |||
m_dynamicAabbTree->remove(m_children[childShapeIndex].m_node); | |||
} | |||
m_children.swap(childShapeIndex,m_children.size()-1); | |||
if (m_dynamicAabbTree) | |||
m_children[childShapeIndex].m_node->dataAsInt = childShapeIndex; | |||
m_children.pop_back(); | |||
} | |||
void btCompoundShape::removeChildShape(btCollisionShape* shape) | |||
{ | |||
m_updateRevision++; | |||
// Find the children containing the shape specified, and remove those children. | |||
//note: there might be multiple children using the same shape! | |||
for(int i = m_children.size()-1; i >= 0 ; i--) | |||
{ | |||
if(m_children[i].m_childShape == shape) | |||
{ | |||
removeChildShapeByIndex(i); | |||
} | |||
} | |||
recalculateLocalAabb(); | |||
} | |||
void btCompoundShape::recalculateLocalAabb() | |||
{ | |||
// Recalculate the local aabb | |||
// Brute force, it iterates over all the shapes left. | |||
m_localAabbMin = btVector3(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); | |||
m_localAabbMax = btVector3(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); | |||
//extend the local aabbMin/aabbMax | |||
for (int j = 0; j < m_children.size(); j++) | |||
{ | |||
btVector3 localAabbMin,localAabbMax; | |||
m_children[j].m_childShape->getAabb(m_children[j].m_transform, localAabbMin, localAabbMax); | |||
for (int i=0;i<3;i++) | |||
{ | |||
if (m_localAabbMin[i] > localAabbMin[i]) | |||
m_localAabbMin[i] = localAabbMin[i]; | |||
if (m_localAabbMax[i] < localAabbMax[i]) | |||
m_localAabbMax[i] = localAabbMax[i]; | |||
} | |||
} | |||
} | |||
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version | |||
void btCompoundShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const | |||
{ | |||
btVector3 localHalfExtents = btScalar(0.5)*(m_localAabbMax-m_localAabbMin); | |||
btVector3 localCenter = btScalar(0.5)*(m_localAabbMax+m_localAabbMin); | |||
//avoid an illegal AABB when there are no children | |||
if (!m_children.size()) | |||
{ | |||
localHalfExtents.setValue(0,0,0); | |||
localCenter.setValue(0,0,0); | |||
} | |||
localHalfExtents += btVector3(getMargin(),getMargin(),getMargin()); | |||
btMatrix3x3 abs_b = trans.getBasis().absolute(); | |||
btVector3 center = trans(localCenter); | |||
btVector3 extent = btVector3(abs_b[0].dot(localHalfExtents), | |||
abs_b[1].dot(localHalfExtents), | |||
abs_b[2].dot(localHalfExtents)); | |||
aabbMin = center-extent; | |||
aabbMax = center+extent; | |||
} | |||
void btCompoundShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const | |||
{ | |||
//approximation: take the inertia from the aabb for now | |||
btTransform ident; | |||
ident.setIdentity(); | |||
btVector3 aabbMin,aabbMax; | |||
getAabb(ident,aabbMin,aabbMax); | |||
btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5); | |||
btScalar lx=btScalar(2.)*(halfExtents.x()); | |||
btScalar ly=btScalar(2.)*(halfExtents.y()); | |||
btScalar lz=btScalar(2.)*(halfExtents.z()); | |||
inertia[0] = mass/(btScalar(12.0)) * (ly*ly + lz*lz); | |||
inertia[1] = mass/(btScalar(12.0)) * (lx*lx + lz*lz); | |||
inertia[2] = mass/(btScalar(12.0)) * (lx*lx + ly*ly); | |||
} | |||
void btCompoundShape::calculatePrincipalAxisTransform(btScalar* masses, btTransform& principal, btVector3& inertia) const | |||
{ | |||
int n = m_children.size(); | |||
btScalar totalMass = 0; | |||
btVector3 center(0, 0, 0); | |||
int k; | |||
for (k = 0; k < n; k++) | |||
{ | |||
btAssert(masses[k]>0); | |||
center += m_children[k].m_transform.getOrigin() * masses[k]; | |||
totalMass += masses[k]; | |||
} | |||
btAssert(totalMass>0); | |||
center /= totalMass; | |||
principal.setOrigin(center); | |||
btMatrix3x3 tensor(0, 0, 0, 0, 0, 0, 0, 0, 0); | |||
for ( k = 0; k < n; k++) | |||
{ | |||
btVector3 i; | |||
m_children[k].m_childShape->calculateLocalInertia(masses[k], i); | |||
const btTransform& t = m_children[k].m_transform; | |||
btVector3 o = t.getOrigin() - center; | |||
//compute inertia tensor in coordinate system of compound shape | |||
btMatrix3x3 j = t.getBasis().transpose(); | |||
j[0] *= i[0]; | |||
j[1] *= i[1]; | |||
j[2] *= i[2]; | |||
j = t.getBasis() * j; | |||
//add inertia tensor | |||
tensor[0] += j[0]; | |||
tensor[1] += j[1]; | |||
tensor[2] += j[2]; | |||
//compute inertia tensor of pointmass at o | |||
btScalar o2 = o.length2(); | |||
j[0].setValue(o2, 0, 0); | |||
j[1].setValue(0, o2, 0); | |||
j[2].setValue(0, 0, o2); | |||
j[0] += o * -o.x(); | |||
j[1] += o * -o.y(); | |||
j[2] += o * -o.z(); | |||
//add inertia tensor of pointmass | |||
tensor[0] += masses[k] * j[0]; | |||
tensor[1] += masses[k] * j[1]; | |||
tensor[2] += masses[k] * j[2]; | |||
} | |||
tensor.diagonalize(principal.getBasis(), btScalar(0.00001), 20); | |||
inertia.setValue(tensor[0][0], tensor[1][1], tensor[2][2]); | |||
} | |||
void btCompoundShape::setLocalScaling(const btVector3& scaling) | |||
{ | |||
for(int i = 0; i < m_children.size(); i++) | |||
{ | |||
btTransform childTrans = getChildTransform(i); | |||
btVector3 childScale = m_children[i].m_childShape->getLocalScaling(); | |||
// childScale = childScale * (childTrans.getBasis() * scaling); | |||
childScale = childScale * scaling / m_localScaling; | |||
m_children[i].m_childShape->setLocalScaling(childScale); | |||
childTrans.setOrigin((childTrans.getOrigin())*scaling); | |||
updateChildTransform(i, childTrans,false); | |||
} | |||
m_localScaling = scaling; | |||
recalculateLocalAabb(); | |||
} | |||
void btCompoundShape::createAabbTreeFromChildren() | |||
{ | |||
if ( !m_dynamicAabbTree ) | |||
{ | |||
void* mem = btAlignedAlloc(sizeof(btDbvt),16); | |||
m_dynamicAabbTree = new(mem) btDbvt(); | |||
btAssert(mem==m_dynamicAabbTree); | |||
for ( int index = 0; index < m_children.size(); index++ ) | |||
{ | |||
btCompoundShapeChild &child = m_children[index]; | |||
//extend the local aabbMin/aabbMax | |||
btVector3 localAabbMin,localAabbMax; | |||
child.m_childShape->getAabb(child.m_transform,localAabbMin,localAabbMax); | |||
const btDbvtVolume bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); | |||
child.m_node = m_dynamicAabbTree->insert(bounds,(void*)index); | |||
} | |||
} | |||
} | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
const char* btCompoundShape::serialize(void* dataBuffer, btSerializer* serializer) const | |||
{ | |||
btCompoundShapeData* shapeData = (btCompoundShapeData*) dataBuffer; | |||
btCollisionShape::serialize(&shapeData->m_collisionShapeData, serializer); | |||
shapeData->m_collisionMargin = float(m_collisionMargin); | |||
shapeData->m_numChildShapes = m_children.size(); | |||
shapeData->m_childShapePtr = 0; | |||
if (shapeData->m_numChildShapes) | |||
{ | |||
btChunk* chunk = serializer->allocate(sizeof(btCompoundShapeChildData),shapeData->m_numChildShapes); | |||
btCompoundShapeChildData* memPtr = (btCompoundShapeChildData*)chunk->m_oldPtr; | |||
shapeData->m_childShapePtr = (btCompoundShapeChildData*)serializer->getUniquePointer(memPtr); | |||
for (int i=0;i<shapeData->m_numChildShapes;i++,memPtr++) | |||
{ | |||
memPtr->m_childMargin = float(m_children[i].m_childMargin); | |||
memPtr->m_childShape = (btCollisionShapeData*)serializer->getUniquePointer(m_children[i].m_childShape); | |||
//don't serialize shapes that already have been serialized | |||
if (!serializer->findPointer(m_children[i].m_childShape)) | |||
{ | |||
btChunk* chunk = serializer->allocate(m_children[i].m_childShape->calculateSerializeBufferSize(),1); | |||
const char* structType = m_children[i].m_childShape->serialize(chunk->m_oldPtr,serializer); | |||
serializer->finalizeChunk(chunk,structType,BT_SHAPE_CODE,m_children[i].m_childShape); | |||
} | |||
memPtr->m_childShapeType = m_children[i].m_childShapeType; | |||
m_children[i].m_transform.serializeFloat(memPtr->m_transform); | |||
} | |||
serializer->finalizeChunk(chunk,"btCompoundShapeChildData",BT_ARRAY_CODE,chunk->m_oldPtr); | |||
} | |||
return "btCompoundShapeData"; | |||
} | |||
@@ -0,0 +1,212 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
#ifndef BT_COMPOUND_SHAPE_H | |||
#define BT_COMPOUND_SHAPE_H | |||
#include "btCollisionShape.h" | |||
#include "LinearMath/btVector3.h" | |||
#include "LinearMath/btTransform.h" | |||
#include "LinearMath/btMatrix3x3.h" | |||
#include "btCollisionMargin.h" | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
//class btOptimizedBvh; | |||
struct btDbvt; | |||
ATTRIBUTE_ALIGNED16(struct) btCompoundShapeChild | |||
{ | |||
BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
btTransform m_transform; | |||
btCollisionShape* m_childShape; | |||
int m_childShapeType; | |||
btScalar m_childMargin; | |||
struct btDbvtNode* m_node; | |||
}; | |||
SIMD_FORCE_INLINE bool operator==(const btCompoundShapeChild& c1, const btCompoundShapeChild& c2) | |||
{ | |||
return ( c1.m_transform == c2.m_transform && | |||
c1.m_childShape == c2.m_childShape && | |||
c1.m_childShapeType == c2.m_childShapeType && | |||
c1.m_childMargin == c2.m_childMargin ); | |||
} | |||
/// The btCompoundShape allows to store multiple other btCollisionShapes | |||
/// This allows for moving concave collision objects. This is more general then the static concave btBvhTriangleMeshShape. | |||
/// It has an (optional) dynamic aabb tree to accelerate early rejection tests. | |||
/// @todo: This aabb tree can also be use to speed up ray tests on btCompoundShape, see http://code.google.com/p/bullet/issues/detail?id=25 | |||
/// Currently, removal of child shapes is only supported when disabling the aabb tree (pass 'false' in the constructor of btCompoundShape) | |||
ATTRIBUTE_ALIGNED16(class) btCompoundShape : public btCollisionShape | |||
{ | |||
btAlignedObjectArray<btCompoundShapeChild> m_children; | |||
btVector3 m_localAabbMin; | |||
btVector3 m_localAabbMax; | |||
btDbvt* m_dynamicAabbTree; | |||
///increment m_updateRevision when adding/removing/replacing child shapes, so that some caches can be updated | |||
int m_updateRevision; | |||
btScalar m_collisionMargin; | |||
protected: | |||
btVector3 m_localScaling; | |||
public: | |||
BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
btCompoundShape(bool enableDynamicAabbTree = true); | |||
virtual ~btCompoundShape(); | |||
void addChildShape(const btTransform& localTransform,btCollisionShape* shape); | |||
/// Remove all children shapes that contain the specified shape | |||
virtual void removeChildShape(btCollisionShape* shape); | |||
void removeChildShapeByIndex(int childShapeindex); | |||
int getNumChildShapes() const | |||
{ | |||
return int (m_children.size()); | |||
} | |||
btCollisionShape* getChildShape(int index) | |||
{ | |||
return m_children[index].m_childShape; | |||
} | |||
const btCollisionShape* getChildShape(int index) const | |||
{ | |||
return m_children[index].m_childShape; | |||
} | |||
btTransform& getChildTransform(int index) | |||
{ | |||
return m_children[index].m_transform; | |||
} | |||
const btTransform& getChildTransform(int index) const | |||
{ | |||
return m_children[index].m_transform; | |||
} | |||
///set a new transform for a child, and update internal data structures (local aabb and dynamic tree) | |||
void updateChildTransform(int childIndex, const btTransform& newChildTransform, bool shouldRecalculateLocalAabb = true); | |||
btCompoundShapeChild* getChildList() | |||
{ | |||
return &m_children[0]; | |||
} | |||
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version | |||
virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
/** Re-calculate the local Aabb. Is called at the end of removeChildShapes. | |||
Use this yourself if you modify the children or their transforms. */ | |||
virtual void recalculateLocalAabb(); | |||
virtual void setLocalScaling(const btVector3& scaling); | |||
virtual const btVector3& getLocalScaling() const | |||
{ | |||
return m_localScaling; | |||
} | |||
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; | |||
virtual void setMargin(btScalar margin) | |||
{ | |||
m_collisionMargin = margin; | |||
} | |||
virtual btScalar getMargin() const | |||
{ | |||
return m_collisionMargin; | |||
} | |||
virtual const char* getName()const | |||
{ | |||
return "Compound"; | |||
} | |||
const btDbvt* getDynamicAabbTree() const | |||
{ | |||
return m_dynamicAabbTree; | |||
} | |||
btDbvt* getDynamicAabbTree() | |||
{ | |||
return m_dynamicAabbTree; | |||
} | |||
void createAabbTreeFromChildren(); | |||
///computes the exact moment of inertia and the transform from the coordinate system defined by the principal axes of the moment of inertia | |||
///and the center of mass to the current coordinate system. "masses" points to an array of masses of the children. The resulting transform | |||
///"principal" has to be applied inversely to all children transforms in order for the local coordinate system of the compound | |||
///shape to be centered at the center of mass and to coincide with the principal axes. This also necessitates a correction of the world transform | |||
///of the collision object by the principal transform. | |||
void calculatePrincipalAxisTransform(btScalar* masses, btTransform& principal, btVector3& inertia) const; | |||
int getUpdateRevision() const | |||
{ | |||
return m_updateRevision; | |||
} | |||
virtual int calculateSerializeBufferSize() const; | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
}; | |||
///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
struct btCompoundShapeChildData | |||
{ | |||
btTransformFloatData m_transform; | |||
btCollisionShapeData *m_childShape; | |||
int m_childShapeType; | |||
float m_childMargin; | |||
}; | |||
///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
struct btCompoundShapeData | |||
{ | |||
btCollisionShapeData m_collisionShapeData; | |||
btCompoundShapeChildData *m_childShapePtr; | |||
int m_numChildShapes; | |||
float m_collisionMargin; | |||
}; | |||
SIMD_FORCE_INLINE int btCompoundShape::calculateSerializeBufferSize() const | |||
{ | |||
return sizeof(btCompoundShapeData); | |||
} | |||
#endif //BT_COMPOUND_SHAPE_H |
@@ -0,0 +1,27 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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 "btConcaveShape.h" | |||
btConcaveShape::btConcaveShape() : m_collisionMargin(btScalar(0.)) | |||
{ | |||
} | |||
btConcaveShape::~btConcaveShape() | |||
{ | |||
} |
@@ -0,0 +1,60 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
#ifndef BT_CONCAVE_SHAPE_H | |||
#define BT_CONCAVE_SHAPE_H | |||
#include "btCollisionShape.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types | |||
#include "btTriangleCallback.h" | |||
/// PHY_ScalarType enumerates possible scalar types. | |||
/// See the btStridingMeshInterface or btHeightfieldTerrainShape for its use | |||
typedef enum PHY_ScalarType { | |||
PHY_FLOAT, | |||
PHY_DOUBLE, | |||
PHY_INTEGER, | |||
PHY_SHORT, | |||
PHY_FIXEDPOINT88, | |||
PHY_UCHAR | |||
} PHY_ScalarType; | |||
///The btConcaveShape class provides an interface for non-moving (static) concave shapes. | |||
///It has been implemented by the btStaticPlaneShape, btBvhTriangleMeshShape and btHeightfieldTerrainShape. | |||
class btConcaveShape : public btCollisionShape | |||
{ | |||
protected: | |||
btScalar m_collisionMargin; | |||
public: | |||
btConcaveShape(); | |||
virtual ~btConcaveShape(); | |||
virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const = 0; | |||
virtual btScalar getMargin() const { | |||
return m_collisionMargin; | |||
} | |||
virtual void setMargin(btScalar collisionMargin) | |||
{ | |||
m_collisionMargin = collisionMargin; | |||
} | |||
}; | |||
#endif //BT_CONCAVE_SHAPE_H |
@@ -0,0 +1,143 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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 "btConeShape.h" | |||
btConeShape::btConeShape (btScalar radius,btScalar height): btConvexInternalShape (), | |||
m_radius (radius), | |||
m_height(height) | |||
{ | |||
m_shapeType = CONE_SHAPE_PROXYTYPE; | |||
setConeUpIndex(1); | |||
btVector3 halfExtents; | |||
m_sinAngle = (m_radius / btSqrt(m_radius * m_radius + m_height * m_height)); | |||
} | |||
btConeShapeZ::btConeShapeZ (btScalar radius,btScalar height): | |||
btConeShape(radius,height) | |||
{ | |||
setConeUpIndex(2); | |||
} | |||
btConeShapeX::btConeShapeX (btScalar radius,btScalar height): | |||
btConeShape(radius,height) | |||
{ | |||
setConeUpIndex(0); | |||
} | |||
///choose upAxis index | |||
void btConeShape::setConeUpIndex(int upIndex) | |||
{ | |||
switch (upIndex) | |||
{ | |||
case 0: | |||
m_coneIndices[0] = 1; | |||
m_coneIndices[1] = 0; | |||
m_coneIndices[2] = 2; | |||
break; | |||
case 1: | |||
m_coneIndices[0] = 0; | |||
m_coneIndices[1] = 1; | |||
m_coneIndices[2] = 2; | |||
break; | |||
case 2: | |||
m_coneIndices[0] = 0; | |||
m_coneIndices[1] = 2; | |||
m_coneIndices[2] = 1; | |||
break; | |||
default: | |||
btAssert(0); | |||
}; | |||
} | |||
btVector3 btConeShape::coneLocalSupport(const btVector3& v) const | |||
{ | |||
btScalar halfHeight = m_height * btScalar(0.5); | |||
if (v[m_coneIndices[1]] > v.length() * m_sinAngle) | |||
{ | |||
btVector3 tmp; | |||
tmp[m_coneIndices[0]] = btScalar(0.); | |||
tmp[m_coneIndices[1]] = halfHeight; | |||
tmp[m_coneIndices[2]] = btScalar(0.); | |||
return tmp; | |||
} | |||
else { | |||
btScalar s = btSqrt(v[m_coneIndices[0]] * v[m_coneIndices[0]] + v[m_coneIndices[2]] * v[m_coneIndices[2]]); | |||
if (s > SIMD_EPSILON) { | |||
btScalar d = m_radius / s; | |||
btVector3 tmp; | |||
tmp[m_coneIndices[0]] = v[m_coneIndices[0]] * d; | |||
tmp[m_coneIndices[1]] = -halfHeight; | |||
tmp[m_coneIndices[2]] = v[m_coneIndices[2]] * d; | |||
return tmp; | |||
} | |||
else { | |||
btVector3 tmp; | |||
tmp[m_coneIndices[0]] = btScalar(0.); | |||
tmp[m_coneIndices[1]] = -halfHeight; | |||
tmp[m_coneIndices[2]] = btScalar(0.); | |||
return tmp; | |||
} | |||
} | |||
} | |||
btVector3 btConeShape::localGetSupportingVertexWithoutMargin(const btVector3& vec) const | |||
{ | |||
return coneLocalSupport(vec); | |||
} | |||
void btConeShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
{ | |||
for (int i=0;i<numVectors;i++) | |||
{ | |||
const btVector3& vec = vectors[i]; | |||
supportVerticesOut[i] = coneLocalSupport(vec); | |||
} | |||
} | |||
btVector3 btConeShape::localGetSupportingVertex(const btVector3& vec) const | |||
{ | |||
btVector3 supVertex = coneLocalSupport(vec); | |||
if ( getMargin()!=btScalar(0.) ) | |||
{ | |||
btVector3 vecnorm = vec; | |||
if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) | |||
{ | |||
vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); | |||
} | |||
vecnorm.normalize(); | |||
supVertex+= getMargin() * vecnorm; | |||
} | |||
return supVertex; | |||
} | |||
void btConeShape::setLocalScaling(const btVector3& scaling) | |||
{ | |||
int axis = m_coneIndices[1]; | |||
int r1 = m_coneIndices[0]; | |||
int r2 = m_coneIndices[2]; | |||
m_height *= scaling[axis] / m_localScaling[axis]; | |||
m_radius *= (scaling[r1] / m_localScaling[r1] + scaling[r2] / m_localScaling[r2]) / 2; | |||
m_sinAngle = (m_radius / btSqrt(m_radius * m_radius + m_height * m_height)); | |||
btConvexInternalShape::setLocalScaling(scaling); | |||
} |
@@ -0,0 +1,103 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
#ifndef BT_CONE_MINKOWSKI_H | |||
#define BT_CONE_MINKOWSKI_H | |||
#include "btConvexInternalShape.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types | |||
///The btConeShape implements a cone shape primitive, centered around the origin and aligned with the Y axis. The btConeShapeX is aligned around the X axis and btConeShapeZ around the Z axis. | |||
class btConeShape : public btConvexInternalShape | |||
{ | |||
btScalar m_sinAngle; | |||
btScalar m_radius; | |||
btScalar m_height; | |||
int m_coneIndices[3]; | |||
btVector3 coneLocalSupport(const btVector3& v) const; | |||
public: | |||
btConeShape (btScalar radius,btScalar height); | |||
virtual btVector3 localGetSupportingVertex(const btVector3& vec) const; | |||
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec) const; | |||
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; | |||
btScalar getRadius() const { return m_radius;} | |||
btScalar getHeight() const { return m_height;} | |||
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const | |||
{ | |||
btTransform identity; | |||
identity.setIdentity(); | |||
btVector3 aabbMin,aabbMax; | |||
getAabb(identity,aabbMin,aabbMax); | |||
btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5); | |||
btScalar margin = getMargin(); | |||
btScalar lx=btScalar(2.)*(halfExtents.x()+margin); | |||
btScalar ly=btScalar(2.)*(halfExtents.y()+margin); | |||
btScalar lz=btScalar(2.)*(halfExtents.z()+margin); | |||
const btScalar x2 = lx*lx; | |||
const btScalar y2 = ly*ly; | |||
const btScalar z2 = lz*lz; | |||
const btScalar scaledmass = mass * btScalar(0.08333333); | |||
inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2)); | |||
// inertia.x() = scaledmass * (y2+z2); | |||
// inertia.y() = scaledmass * (x2+z2); | |||
// inertia.z() = scaledmass * (x2+y2); | |||
} | |||
virtual const char* getName()const | |||
{ | |||
return "Cone"; | |||
} | |||
///choose upAxis index | |||
void setConeUpIndex(int upIndex); | |||
int getConeUpIndex() const | |||
{ | |||
return m_coneIndices[1]; | |||
} | |||
virtual void setLocalScaling(const btVector3& scaling); | |||
}; | |||
///btConeShape implements a Cone shape, around the X axis | |||
class btConeShapeX : public btConeShape | |||
{ | |||
public: | |||
btConeShapeX(btScalar radius,btScalar height); | |||
}; | |||
///btConeShapeZ implements a Cone shape, around the Z axis | |||
class btConeShapeZ : public btConeShape | |||
{ | |||
public: | |||
btConeShapeZ(btScalar radius,btScalar height); | |||
}; | |||
#endif //BT_CONE_MINKOWSKI_H | |||
@@ -0,0 +1,92 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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 "btConvex2dShape.h" | |||
btConvex2dShape::btConvex2dShape( btConvexShape* convexChildShape): | |||
btConvexShape (), m_childConvexShape(convexChildShape) | |||
{ | |||
m_shapeType = CONVEX_2D_SHAPE_PROXYTYPE; | |||
} | |||
btConvex2dShape::~btConvex2dShape() | |||
{ | |||
} | |||
btVector3 btConvex2dShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const | |||
{ | |||
return m_childConvexShape->localGetSupportingVertexWithoutMargin(vec); | |||
} | |||
void btConvex2dShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
{ | |||
m_childConvexShape->batchedUnitVectorGetSupportingVertexWithoutMargin(vectors,supportVerticesOut,numVectors); | |||
} | |||
btVector3 btConvex2dShape::localGetSupportingVertex(const btVector3& vec)const | |||
{ | |||
return m_childConvexShape->localGetSupportingVertex(vec); | |||
} | |||
void btConvex2dShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const | |||
{ | |||
///this linear upscaling is not realistic, but we don't deal with large mass ratios... | |||
m_childConvexShape->calculateLocalInertia(mass,inertia); | |||
} | |||
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version | |||
void btConvex2dShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const | |||
{ | |||
m_childConvexShape->getAabb(t,aabbMin,aabbMax); | |||
} | |||
void btConvex2dShape::getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const | |||
{ | |||
m_childConvexShape->getAabbSlow(t,aabbMin,aabbMax); | |||
} | |||
void btConvex2dShape::setLocalScaling(const btVector3& scaling) | |||
{ | |||
m_childConvexShape->setLocalScaling(scaling); | |||
} | |||
const btVector3& btConvex2dShape::getLocalScaling() const | |||
{ | |||
return m_childConvexShape->getLocalScaling(); | |||
} | |||
void btConvex2dShape::setMargin(btScalar margin) | |||
{ | |||
m_childConvexShape->setMargin(margin); | |||
} | |||
btScalar btConvex2dShape::getMargin() const | |||
{ | |||
return m_childConvexShape->getMargin(); | |||
} | |||
int btConvex2dShape::getNumPreferredPenetrationDirections() const | |||
{ | |||
return m_childConvexShape->getNumPreferredPenetrationDirections(); | |||
} | |||
void btConvex2dShape::getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const | |||
{ | |||
m_childConvexShape->getPreferredPenetrationDirection(index,penetrationVector); | |||
} |
@@ -0,0 +1,80 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
#ifndef BT_CONVEX_2D_SHAPE_H | |||
#define BT_CONVEX_2D_SHAPE_H | |||
#include "BulletCollision/CollisionShapes/btConvexShape.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types | |||
///The btConvex2dShape allows to use arbitrary convex shapes as 2d convex shapes, with the Z component assumed to be 0. | |||
///For 2d boxes, the btBox2dShape is recommended. | |||
class btConvex2dShape : public btConvexShape | |||
{ | |||
btConvexShape* m_childConvexShape; | |||
public: | |||
btConvex2dShape( btConvexShape* convexChildShape); | |||
virtual ~btConvex2dShape(); | |||
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; | |||
virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; | |||
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; | |||
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; | |||
btConvexShape* getChildShape() | |||
{ | |||
return m_childConvexShape; | |||
} | |||
const btConvexShape* getChildShape() const | |||
{ | |||
return m_childConvexShape; | |||
} | |||
virtual const char* getName()const | |||
{ | |||
return "Convex2dShape"; | |||
} | |||
/////////////////////////// | |||
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version | |||
void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
virtual void setLocalScaling(const btVector3& scaling) ; | |||
virtual const btVector3& getLocalScaling() const ; | |||
virtual void setMargin(btScalar margin); | |||
virtual btScalar getMargin() const; | |||
virtual int getNumPreferredPenetrationDirections() const; | |||
virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const; | |||
}; | |||
#endif //BT_CONVEX_2D_SHAPE_H |
@@ -0,0 +1,255 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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 "btConvexHullShape.h" | |||
#include "BulletCollision/CollisionShapes/btCollisionMargin.h" | |||
#include "LinearMath/btQuaternion.h" | |||
#include "LinearMath/btSerializer.h" | |||
btConvexHullShape ::btConvexHullShape (const btScalar* points,int numPoints,int stride) : btPolyhedralConvexAabbCachingShape () | |||
{ | |||
m_shapeType = CONVEX_HULL_SHAPE_PROXYTYPE; | |||
m_unscaledPoints.resize(numPoints); | |||
unsigned char* pointsAddress = (unsigned char*)points; | |||
for (int i=0;i<numPoints;i++) | |||
{ | |||
btScalar* point = (btScalar*)pointsAddress; | |||
m_unscaledPoints[i] = btVector3(point[0], point[1], point[2]); | |||
pointsAddress += stride; | |||
} | |||
recalcLocalAabb(); | |||
} | |||
void btConvexHullShape::setLocalScaling(const btVector3& scaling) | |||
{ | |||
m_localScaling = scaling; | |||
recalcLocalAabb(); | |||
} | |||
void btConvexHullShape::addPoint(const btVector3& point) | |||
{ | |||
m_unscaledPoints.push_back(point); | |||
recalcLocalAabb(); | |||
} | |||
btVector3 btConvexHullShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const | |||
{ | |||
btVector3 supVec(btScalar(0.),btScalar(0.),btScalar(0.)); | |||
btScalar newDot,maxDot = btScalar(-BT_LARGE_FLOAT); | |||
for (int i=0;i<m_unscaledPoints.size();i++) | |||
{ | |||
btVector3 vtx = m_unscaledPoints[i] * m_localScaling; | |||
newDot = vec.dot(vtx); | |||
if (newDot > maxDot) | |||
{ | |||
maxDot = newDot; | |||
supVec = vtx; | |||
} | |||
} | |||
return supVec; | |||
} | |||
void btConvexHullShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
{ | |||
btScalar newDot; | |||
//use 'w' component of supportVerticesOut? | |||
{ | |||
for (int i=0;i<numVectors;i++) | |||
{ | |||
supportVerticesOut[i][3] = btScalar(-BT_LARGE_FLOAT); | |||
} | |||
} | |||
for (int i=0;i<m_unscaledPoints.size();i++) | |||
{ | |||
btVector3 vtx = getScaledPoint(i); | |||
for (int j=0;j<numVectors;j++) | |||
{ | |||
const btVector3& vec = vectors[j]; | |||
newDot = vec.dot(vtx); | |||
if (newDot > supportVerticesOut[j][3]) | |||
{ | |||
//WARNING: don't swap next lines, the w component would get overwritten! | |||
supportVerticesOut[j] = vtx; | |||
supportVerticesOut[j][3] = newDot; | |||
} | |||
} | |||
} | |||
} | |||
btVector3 btConvexHullShape::localGetSupportingVertex(const btVector3& vec)const | |||
{ | |||
btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); | |||
if ( getMargin()!=btScalar(0.) ) | |||
{ | |||
btVector3 vecnorm = vec; | |||
if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) | |||
{ | |||
vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); | |||
} | |||
vecnorm.normalize(); | |||
supVertex+= getMargin() * vecnorm; | |||
} | |||
return supVertex; | |||
} | |||
//currently just for debugging (drawing), perhaps future support for algebraic continuous collision detection | |||
//Please note that you can debug-draw btConvexHullShape with the Raytracer Demo | |||
int btConvexHullShape::getNumVertices() const | |||
{ | |||
return m_unscaledPoints.size(); | |||
} | |||
int btConvexHullShape::getNumEdges() const | |||
{ | |||
return m_unscaledPoints.size(); | |||
} | |||
void btConvexHullShape::getEdge(int i,btVector3& pa,btVector3& pb) const | |||
{ | |||
int index0 = i%m_unscaledPoints.size(); | |||
int index1 = (i+1)%m_unscaledPoints.size(); | |||
pa = getScaledPoint(index0); | |||
pb = getScaledPoint(index1); | |||
} | |||
void btConvexHullShape::getVertex(int i,btVector3& vtx) const | |||
{ | |||
vtx = getScaledPoint(i); | |||
} | |||
int btConvexHullShape::getNumPlanes() const | |||
{ | |||
return 0; | |||
} | |||
void btConvexHullShape::getPlane(btVector3& ,btVector3& ,int ) const | |||
{ | |||
btAssert(0); | |||
} | |||
//not yet | |||
bool btConvexHullShape::isInside(const btVector3& ,btScalar ) const | |||
{ | |||
btAssert(0); | |||
return false; | |||
} | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
const char* btConvexHullShape::serialize(void* dataBuffer, btSerializer* serializer) const | |||
{ | |||
//int szc = sizeof(btConvexHullShapeData); | |||
btConvexHullShapeData* shapeData = (btConvexHullShapeData*) dataBuffer; | |||
btConvexInternalShape::serialize(&shapeData->m_convexInternalShapeData, serializer); | |||
int numElem = m_unscaledPoints.size(); | |||
shapeData->m_numUnscaledPoints = numElem; | |||
#ifdef BT_USE_DOUBLE_PRECISION | |||
shapeData->m_unscaledPointsFloatPtr = 0; | |||
shapeData->m_unscaledPointsDoublePtr = numElem ? (btVector3Data*)serializer->getUniquePointer((void*)&m_unscaledPoints[0]): 0; | |||
#else | |||
shapeData->m_unscaledPointsFloatPtr = numElem ? (btVector3Data*)serializer->getUniquePointer((void*)&m_unscaledPoints[0]): 0; | |||
shapeData->m_unscaledPointsDoublePtr = 0; | |||
#endif | |||
if (numElem) | |||
{ | |||
int sz = sizeof(btVector3Data); | |||
// int sz2 = sizeof(btVector3DoubleData); | |||
// int sz3 = sizeof(btVector3FloatData); | |||
btChunk* chunk = serializer->allocate(sz,numElem); | |||
btVector3Data* memPtr = (btVector3Data*)chunk->m_oldPtr; | |||
for (int i=0;i<numElem;i++,memPtr++) | |||
{ | |||
m_unscaledPoints[i].serialize(*memPtr); | |||
} | |||
serializer->finalizeChunk(chunk,btVector3DataName,BT_ARRAY_CODE,(void*)&m_unscaledPoints[0]); | |||
} | |||
return "btConvexHullShapeData"; | |||
} | |||
void btConvexHullShape::project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const | |||
{ | |||
#if 1 | |||
min = FLT_MAX; | |||
max = -FLT_MAX; | |||
btVector3 witnesPtMin; | |||
btVector3 witnesPtMax; | |||
int numVerts = m_unscaledPoints.size(); | |||
for(int i=0;i<numVerts;i++) | |||
{ | |||
btVector3 vtx = m_unscaledPoints[i] * m_localScaling; | |||
btVector3 pt = trans * vtx; | |||
btScalar dp = pt.dot(dir); | |||
if(dp < min) | |||
{ | |||
min = dp; | |||
witnesPtMin = pt; | |||
} | |||
if(dp > max) | |||
{ | |||
max = dp; | |||
witnesPtMax=pt; | |||
} | |||
} | |||
#else | |||
btVector3 localAxis = dir*trans.getBasis(); | |||
btVector3 vtx1 = trans(localGetSupportingVertex(localAxis)); | |||
btVector3 vtx2 = trans(localGetSupportingVertex(-localAxis)); | |||
min = vtx1.dot(dir); | |||
max = vtx2.dot(dir); | |||
#endif | |||
if(min>max) | |||
{ | |||
btScalar tmp = min; | |||
min = max; | |||
max = tmp; | |||
} | |||
} | |||
@@ -0,0 +1,122 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
#ifndef BT_CONVEX_HULL_SHAPE_H | |||
#define BT_CONVEX_HULL_SHAPE_H | |||
#include "btPolyhedralConvexShape.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
///The btConvexHullShape implements an implicit convex hull of an array of vertices. | |||
///Bullet provides a general and fast collision detector for convex shapes based on GJK and EPA using localGetSupportingVertex. | |||
ATTRIBUTE_ALIGNED16(class) btConvexHullShape : public btPolyhedralConvexAabbCachingShape | |||
{ | |||
btAlignedObjectArray<btVector3> m_unscaledPoints; | |||
public: | |||
BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
///this constructor optionally takes in a pointer to points. Each point is assumed to be 3 consecutive btScalar (x,y,z), the striding defines the number of bytes between each point, in memory. | |||
///It is easier to not pass any points in the constructor, and just add one point at a time, using addPoint. | |||
///btConvexHullShape make an internal copy of the points. | |||
btConvexHullShape(const btScalar* points=0,int numPoints=0, int stride=sizeof(btVector3)); | |||
void addPoint(const btVector3& point); | |||
btVector3* getUnscaledPoints() | |||
{ | |||
return &m_unscaledPoints[0]; | |||
} | |||
const btVector3* getUnscaledPoints() const | |||
{ | |||
return &m_unscaledPoints[0]; | |||
} | |||
///getPoints is obsolete, please use getUnscaledPoints | |||
const btVector3* getPoints() const | |||
{ | |||
return getUnscaledPoints(); | |||
} | |||
SIMD_FORCE_INLINE btVector3 getScaledPoint(int i) const | |||
{ | |||
return m_unscaledPoints[i] * m_localScaling; | |||
} | |||
SIMD_FORCE_INLINE int getNumPoints() const | |||
{ | |||
return m_unscaledPoints.size(); | |||
} | |||
virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; | |||
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; | |||
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; | |||
virtual void project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const; | |||
//debugging | |||
virtual const char* getName()const {return "Convex";} | |||
virtual int getNumVertices() const; | |||
virtual int getNumEdges() const; | |||
virtual void getEdge(int i,btVector3& pa,btVector3& pb) const; | |||
virtual void getVertex(int i,btVector3& vtx) const; | |||
virtual int getNumPlanes() const; | |||
virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i ) const; | |||
virtual bool isInside(const btVector3& pt,btScalar tolerance) const; | |||
///in case we receive negative scaling | |||
virtual void setLocalScaling(const btVector3& scaling); | |||
virtual int calculateSerializeBufferSize() const; | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
}; | |||
///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
struct btConvexHullShapeData | |||
{ | |||
btConvexInternalShapeData m_convexInternalShapeData; | |||
btVector3FloatData *m_unscaledPointsFloatPtr; | |||
btVector3DoubleData *m_unscaledPointsDoublePtr; | |||
int m_numUnscaledPoints; | |||
char m_padding3[4]; | |||
}; | |||
SIMD_FORCE_INLINE int btConvexHullShape::calculateSerializeBufferSize() const | |||
{ | |||
return sizeof(btConvexHullShapeData); | |||
} | |||
#endif //BT_CONVEX_HULL_SHAPE_H | |||
@@ -0,0 +1,151 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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 "btConvexInternalShape.h" | |||
btConvexInternalShape::btConvexInternalShape() | |||
: m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.)), | |||
m_collisionMargin(CONVEX_DISTANCE_MARGIN) | |||
{ | |||
} | |||
void btConvexInternalShape::setLocalScaling(const btVector3& scaling) | |||
{ | |||
m_localScaling = scaling.absolute(); | |||
} | |||
void btConvexInternalShape::getAabbSlow(const btTransform& trans,btVector3&minAabb,btVector3&maxAabb) const | |||
{ | |||
#ifndef __SPU__ | |||
//use localGetSupportingVertexWithoutMargin? | |||
btScalar margin = getMargin(); | |||
for (int i=0;i<3;i++) | |||
{ | |||
btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); | |||
vec[i] = btScalar(1.); | |||
btVector3 sv = localGetSupportingVertex(vec*trans.getBasis()); | |||
btVector3 tmp = trans(sv); | |||
maxAabb[i] = tmp[i]+margin; | |||
vec[i] = btScalar(-1.); | |||
tmp = trans(localGetSupportingVertex(vec*trans.getBasis())); | |||
minAabb[i] = tmp[i]-margin; | |||
} | |||
#endif | |||
} | |||
btVector3 btConvexInternalShape::localGetSupportingVertex(const btVector3& vec)const | |||
{ | |||
#ifndef __SPU__ | |||
btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); | |||
if ( getMargin()!=btScalar(0.) ) | |||
{ | |||
btVector3 vecnorm = vec; | |||
if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) | |||
{ | |||
vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); | |||
} | |||
vecnorm.normalize(); | |||
supVertex+= getMargin() * vecnorm; | |||
} | |||
return supVertex; | |||
#else | |||
btAssert(0); | |||
return btVector3(0,0,0); | |||
#endif //__SPU__ | |||
} | |||
btConvexInternalAabbCachingShape::btConvexInternalAabbCachingShape() | |||
: btConvexInternalShape(), | |||
m_localAabbMin(1,1,1), | |||
m_localAabbMax(-1,-1,-1), | |||
m_isLocalAabbValid(false) | |||
{ | |||
} | |||
void btConvexInternalAabbCachingShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const | |||
{ | |||
getNonvirtualAabb(trans,aabbMin,aabbMax,getMargin()); | |||
} | |||
void btConvexInternalAabbCachingShape::setLocalScaling(const btVector3& scaling) | |||
{ | |||
btConvexInternalShape::setLocalScaling(scaling); | |||
recalcLocalAabb(); | |||
} | |||
void btConvexInternalAabbCachingShape::recalcLocalAabb() | |||
{ | |||
m_isLocalAabbValid = true; | |||
#if 1 | |||
static const btVector3 _directions[] = | |||
{ | |||
btVector3( 1., 0., 0.), | |||
btVector3( 0., 1., 0.), | |||
btVector3( 0., 0., 1.), | |||
btVector3( -1., 0., 0.), | |||
btVector3( 0., -1., 0.), | |||
btVector3( 0., 0., -1.) | |||
}; | |||
btVector3 _supporting[] = | |||
{ | |||
btVector3( 0., 0., 0.), | |||
btVector3( 0., 0., 0.), | |||
btVector3( 0., 0., 0.), | |||
btVector3( 0., 0., 0.), | |||
btVector3( 0., 0., 0.), | |||
btVector3( 0., 0., 0.) | |||
}; | |||
batchedUnitVectorGetSupportingVertexWithoutMargin(_directions, _supporting, 6); | |||
for ( int i = 0; i < 3; ++i ) | |||
{ | |||
m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin; | |||
m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin; | |||
} | |||
#else | |||
for (int i=0;i<3;i++) | |||
{ | |||
btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); | |||
vec[i] = btScalar(1.); | |||
btVector3 tmp = localGetSupportingVertex(vec); | |||
m_localAabbMax[i] = tmp[i]+m_collisionMargin; | |||
vec[i] = btScalar(-1.); | |||
tmp = localGetSupportingVertex(vec); | |||
m_localAabbMin[i] = tmp[i]-m_collisionMargin; | |||
} | |||
#endif | |||
} |
@@ -0,0 +1,224 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
#ifndef BT_CONVEX_INTERNAL_SHAPE_H | |||
#define BT_CONVEX_INTERNAL_SHAPE_H | |||
#include "btConvexShape.h" | |||
#include "LinearMath/btAabbUtil2.h" | |||
///The btConvexInternalShape is an internal base class, shared by most convex shape implementations. | |||
///The btConvexInternalShape uses a default collision margin set to CONVEX_DISTANCE_MARGIN. | |||
///This collision margin used by Gjk and some other algorithms, see also btCollisionMargin.h | |||
///Note that when creating small shapes (derived from btConvexInternalShape), | |||
///you need to make sure to set a smaller collision margin, using the 'setMargin' API | |||
///There is a automatic mechanism 'setSafeMargin' used by btBoxShape and btCylinderShape | |||
class btConvexInternalShape : public btConvexShape | |||
{ | |||
protected: | |||
//local scaling. collisionMargin is not scaled ! | |||
btVector3 m_localScaling; | |||
btVector3 m_implicitShapeDimensions; | |||
btScalar m_collisionMargin; | |||
btScalar m_padding; | |||
btConvexInternalShape(); | |||
public: | |||
virtual ~btConvexInternalShape() | |||
{ | |||
} | |||
virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; | |||
const btVector3& getImplicitShapeDimensions() const | |||
{ | |||
return m_implicitShapeDimensions; | |||
} | |||
///warning: use setImplicitShapeDimensions with care | |||
///changing a collision shape while the body is in the world is not recommended, | |||
///it is best to remove the body from the world, then make the change, and re-add it | |||
///alternatively flush the contact points, see documentation for 'cleanProxyFromPairs' | |||
void setImplicitShapeDimensions(const btVector3& dimensions) | |||
{ | |||
m_implicitShapeDimensions = dimensions; | |||
} | |||
void setSafeMargin(btScalar minDimension, btScalar defaultMarginMultiplier = 0.1f) | |||
{ | |||
btScalar safeMargin = defaultMarginMultiplier*minDimension; | |||
if (safeMargin < getMargin()) | |||
{ | |||
setMargin(safeMargin); | |||
} | |||
} | |||
void setSafeMargin(const btVector3& halfExtents, btScalar defaultMarginMultiplier = 0.1f) | |||
{ | |||
//see http://code.google.com/p/bullet/issues/detail?id=349 | |||
//this margin check could could be added to other collision shapes too, | |||
//or add some assert/warning somewhere | |||
btScalar minDimension=halfExtents[halfExtents.minAxis()]; | |||
setSafeMargin(minDimension, defaultMarginMultiplier); | |||
} | |||
///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version | |||
void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const | |||
{ | |||
getAabbSlow(t,aabbMin,aabbMax); | |||
} | |||
virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
virtual void setLocalScaling(const btVector3& scaling); | |||
virtual const btVector3& getLocalScaling() const | |||
{ | |||
return m_localScaling; | |||
} | |||
const btVector3& getLocalScalingNV() const | |||
{ | |||
return m_localScaling; | |||
} | |||
virtual void setMargin(btScalar margin) | |||
{ | |||
m_collisionMargin = margin; | |||
} | |||
virtual btScalar getMargin() const | |||
{ | |||
return m_collisionMargin; | |||
} | |||
btScalar getMarginNV() const | |||
{ | |||
return m_collisionMargin; | |||
} | |||
virtual int getNumPreferredPenetrationDirections() const | |||
{ | |||
return 0; | |||
} | |||
virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const | |||
{ | |||
(void)penetrationVector; | |||
(void)index; | |||
btAssert(0); | |||
} | |||
virtual int calculateSerializeBufferSize() const; | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
}; | |||
///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
struct btConvexInternalShapeData | |||
{ | |||
btCollisionShapeData m_collisionShapeData; | |||
btVector3FloatData m_localScaling; | |||
btVector3FloatData m_implicitShapeDimensions; | |||
float m_collisionMargin; | |||
int m_padding; | |||
}; | |||
SIMD_FORCE_INLINE int btConvexInternalShape::calculateSerializeBufferSize() const | |||
{ | |||
return sizeof(btConvexInternalShapeData); | |||
} | |||
///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
SIMD_FORCE_INLINE const char* btConvexInternalShape::serialize(void* dataBuffer, btSerializer* serializer) const | |||
{ | |||
btConvexInternalShapeData* shapeData = (btConvexInternalShapeData*) dataBuffer; | |||
btCollisionShape::serialize(&shapeData->m_collisionShapeData, serializer); | |||
m_implicitShapeDimensions.serializeFloat(shapeData->m_implicitShapeDimensions); | |||
m_localScaling.serializeFloat(shapeData->m_localScaling); | |||
shapeData->m_collisionMargin = float(m_collisionMargin); | |||
return "btConvexInternalShapeData"; | |||
} | |||
///btConvexInternalAabbCachingShape adds local aabb caching for convex shapes, to avoid expensive bounding box calculations | |||
class btConvexInternalAabbCachingShape : public btConvexInternalShape | |||
{ | |||
btVector3 m_localAabbMin; | |||
btVector3 m_localAabbMax; | |||
bool m_isLocalAabbValid; | |||
protected: | |||
btConvexInternalAabbCachingShape(); | |||
void setCachedLocalAabb (const btVector3& aabbMin, const btVector3& aabbMax) | |||
{ | |||
m_isLocalAabbValid = true; | |||
m_localAabbMin = aabbMin; | |||
m_localAabbMax = aabbMax; | |||
} | |||
inline void getCachedLocalAabb (btVector3& aabbMin, btVector3& aabbMax) const | |||
{ | |||
btAssert(m_isLocalAabbValid); | |||
aabbMin = m_localAabbMin; | |||
aabbMax = m_localAabbMax; | |||
} | |||
inline void getNonvirtualAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax, btScalar margin) const | |||
{ | |||
//lazy evaluation of local aabb | |||
btAssert(m_isLocalAabbValid); | |||
btTransformAabb(m_localAabbMin,m_localAabbMax,margin,trans,aabbMin,aabbMax); | |||
} | |||
public: | |||
virtual void setLocalScaling(const btVector3& scaling); | |||
virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
void recalcLocalAabb(); | |||
}; | |||
#endif //BT_CONVEX_INTERNAL_SHAPE_H |
@@ -0,0 +1,157 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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 "btConvexPointCloudShape.h" | |||
#include "BulletCollision/CollisionShapes/btCollisionMargin.h" | |||
#include "LinearMath/btQuaternion.h" | |||
void btConvexPointCloudShape::setLocalScaling(const btVector3& scaling) | |||
{ | |||
m_localScaling = scaling; | |||
recalcLocalAabb(); | |||
} | |||
#ifndef __SPU__ | |||
btVector3 btConvexPointCloudShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const | |||
{ | |||
btVector3 supVec(btScalar(0.),btScalar(0.),btScalar(0.)); | |||
btScalar newDot,maxDot = btScalar(-BT_LARGE_FLOAT); | |||
btVector3 vec = vec0; | |||
btScalar lenSqr = vec.length2(); | |||
if (lenSqr < btScalar(0.0001)) | |||
{ | |||
vec.setValue(1,0,0); | |||
} else | |||
{ | |||
btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); | |||
vec *= rlen; | |||
} | |||
for (int i=0;i<m_numPoints;i++) | |||
{ | |||
btVector3 vtx = getScaledPoint(i); | |||
newDot = vec.dot(vtx); | |||
if (newDot > maxDot) | |||
{ | |||
maxDot = newDot; | |||
supVec = vtx; | |||
} | |||
} | |||
return supVec; | |||
} | |||
void btConvexPointCloudShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
{ | |||
btScalar newDot; | |||
//use 'w' component of supportVerticesOut? | |||
{ | |||
for (int i=0;i<numVectors;i++) | |||
{ | |||
supportVerticesOut[i][3] = btScalar(-BT_LARGE_FLOAT); | |||
} | |||
} | |||
for (int i=0;i<m_numPoints;i++) | |||
{ | |||
btVector3 vtx = getScaledPoint(i); | |||
for (int j=0;j<numVectors;j++) | |||
{ | |||
const btVector3& vec = vectors[j]; | |||
newDot = vec.dot(vtx); | |||
if (newDot > supportVerticesOut[j][3]) | |||
{ | |||
//WARNING: don't swap next lines, the w component would get overwritten! | |||
supportVerticesOut[j] = vtx; | |||
supportVerticesOut[j][3] = newDot; | |||
} | |||
} | |||
} | |||
} | |||
btVector3 btConvexPointCloudShape::localGetSupportingVertex(const btVector3& vec)const | |||
{ | |||
btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); | |||
if ( getMargin()!=btScalar(0.) ) | |||
{ | |||
btVector3 vecnorm = vec; | |||
if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) | |||
{ | |||
vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); | |||
} | |||
vecnorm.normalize(); | |||
supVertex+= getMargin() * vecnorm; | |||
} | |||
return supVertex; | |||
} | |||
#endif | |||
//currently just for debugging (drawing), perhaps future support for algebraic continuous collision detection | |||
//Please note that you can debug-draw btConvexHullShape with the Raytracer Demo | |||
int btConvexPointCloudShape::getNumVertices() const | |||
{ | |||
return m_numPoints; | |||
} | |||
int btConvexPointCloudShape::getNumEdges() const | |||
{ | |||
return 0; | |||
} | |||
void btConvexPointCloudShape::getEdge(int i,btVector3& pa,btVector3& pb) const | |||
{ | |||
btAssert (0); | |||
} | |||
void btConvexPointCloudShape::getVertex(int i,btVector3& vtx) const | |||
{ | |||
vtx = m_unscaledPoints[i]*m_localScaling; | |||
} | |||
int btConvexPointCloudShape::getNumPlanes() const | |||
{ | |||
return 0; | |||
} | |||
void btConvexPointCloudShape::getPlane(btVector3& ,btVector3& ,int ) const | |||
{ | |||
btAssert(0); | |||
} | |||
//not yet | |||
bool btConvexPointCloudShape::isInside(const btVector3& ,btScalar ) const | |||
{ | |||
btAssert(0); | |||
return false; | |||
} | |||
@@ -0,0 +1,105 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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. | |||
*/ | |||
#ifndef BT_CONVEX_POINT_CLOUD_SHAPE_H | |||
#define BT_CONVEX_POINT_CLOUD_SHAPE_H | |||
#include "btPolyhedralConvexShape.h" | |||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
///The btConvexPointCloudShape implements an implicit convex hull of an array of vertices. | |||
ATTRIBUTE_ALIGNED16(class) btConvexPointCloudShape : public btPolyhedralConvexAabbCachingShape | |||
{ | |||
btVector3* m_unscaledPoints; | |||
int m_numPoints; | |||
public: | |||
BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
btConvexPointCloudShape() | |||
{ | |||
m_localScaling.setValue(1.f,1.f,1.f); | |||
m_shapeType = CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE; | |||
m_unscaledPoints = 0; | |||
m_numPoints = 0; | |||
} | |||
btConvexPointCloudShape(btVector3* points,int numPoints, const btVector3& localScaling,bool computeAabb = true) | |||
{ | |||
m_localScaling = localScaling; | |||
m_shapeType = CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE; | |||
m_unscaledPoints = points; | |||
m_numPoints = numPoints; | |||
if (computeAabb) | |||
recalcLocalAabb(); | |||
} | |||
void setPoints (btVector3* points, int numPoints, bool computeAabb = true,const btVector3& localScaling=btVector3(1.f,1.f,1.f)) | |||
{ | |||
m_unscaledPoints = points; | |||
m_numPoints = numPoints; | |||
m_localScaling = localScaling; | |||
if (computeAabb) | |||
recalcLocalAabb(); | |||
} | |||
SIMD_FORCE_INLINE btVector3* getUnscaledPoints() | |||
{ | |||
return m_unscaledPoints; | |||
} | |||
SIMD_FORCE_INLINE const btVector3* getUnscaledPoints() const | |||
{ | |||
return m_unscaledPoints; | |||
} | |||
SIMD_FORCE_INLINE int getNumPoints() const | |||
{ | |||
return m_numPoints; | |||
} | |||
SIMD_FORCE_INLINE btVector3 getScaledPoint( int index) const | |||
{ | |||
return m_unscaledPoints[index] * m_localScaling; | |||
} | |||
#ifndef __SPU__ | |||
virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; | |||
virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; | |||
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; | |||
#endif | |||
//debugging | |||
virtual const char* getName()const {return "ConvexPointCloud";} | |||
virtual int getNumVertices() const; | |||
virtual int getNumEdges() const; | |||
virtual void getEdge(int i,btVector3& pa,btVector3& pb) const; | |||
virtual void getVertex(int i,btVector3& vtx) const; | |||
virtual int getNumPlanes() const; | |||
virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i ) const; | |||
virtual bool isInside(const btVector3& pt,btScalar tolerance) const; | |||
///in case we receive negative scaling | |||
virtual void setLocalScaling(const btVector3& scaling); | |||
}; | |||
#endif //BT_CONVEX_POINT_CLOUD_SHAPE_H | |||
@@ -0,0 +1,296 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2011 Advanced Micro Devices, Inc. http://bulletphysics.org | |||
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. | |||
*/ | |||
///This file was written by Erwin Coumans | |||
///Separating axis rest based on work from Pierre Terdiman, see | |||
///And contact clipping based on work from Simon Hobbs | |||
#include "btConvexPolyhedron.h" | |||
#include "LinearMath/btHashMap.h" | |||
btConvexPolyhedron::btConvexPolyhedron() | |||
{ | |||
} | |||
btConvexPolyhedron::~btConvexPolyhedron() | |||
{ | |||
} | |||
inline bool IsAlmostZero(const btVector3& v) | |||
{ | |||
if(fabsf(v.x())>1e-6 || fabsf(v.y())>1e-6 || fabsf(v.z())>1e-6) return false; | |||
return true; | |||
} | |||
struct btInternalVertexPair | |||
{ | |||
btInternalVertexPair(short int v0,short int v1) | |||
:m_v0(v0), | |||
m_v1(v1) | |||
{ | |||
if (m_v1>m_v0) | |||
btSwap(m_v0,m_v1); | |||
} | |||
short int m_v0; | |||
short int m_v1; | |||
int getHash() const | |||
{ | |||
return m_v0+(m_v1<<16); | |||
} | |||
bool equals(const btInternalVertexPair& other) const | |||
{ | |||
return m_v0==other.m_v0 && m_v1==other.m_v1; | |||
} | |||
}; | |||
struct btInternalEdge | |||
{ | |||
btInternalEdge() | |||
:m_face0(-1), | |||
m_face1(-1) | |||
{ | |||
} | |||
short int m_face0; | |||
short int m_face1; | |||
}; | |||
// | |||
#ifdef TEST_INTERNAL_OBJECTS | |||
bool btConvexPolyhedron::testContainment() const | |||
{ | |||
for(int p=0;p<8;p++) | |||
{ | |||
btVector3 LocalPt; | |||
if(p==0) LocalPt = m_localCenter + btVector3(m_extents[0], m_extents[1], m_extents[2]); | |||
else if(p==1) LocalPt = m_localCenter + btVector3(m_extents[0], m_extents[1], -m_extents[2]); | |||
else if(p==2) LocalPt = m_localCenter + btVector3(m_extents[0], -m_extents[1], m_extents[2]); | |||
else if(p==3) LocalPt = m_localCenter + btVector3(m_extents[0], -m_extents[1], -m_extents[2]); | |||
else if(p==4) LocalPt = m_localCenter + btVector3(-m_extents[0], m_extents[1], m_extents[2]); | |||
else if(p==5) LocalPt = m_localCenter + btVector3(-m_extents[0], m_extents[1], -m_extents[2]); | |||
else if(p==6) LocalPt = m_localCenter + btVector3(-m_extents[0], -m_extents[1], m_extents[2]); | |||
else if(p==7) LocalPt = m_localCenter + btVector3(-m_extents[0], -m_extents[1], -m_extents[2]); | |||
for(int i=0;i<m_faces.size();i++) | |||
{ | |||
const btVector3 Normal(m_faces[i].m_plane[0], m_faces[i].m_plane[1], m_faces[i].m_plane[2]); | |||
const btScalar d = LocalPt.dot(Normal) + m_faces[i].m_plane[3]; | |||
if(d>0.0f) | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
#endif | |||
void btConvexPolyhedron::initialize() | |||
{ | |||
btHashMap<btInternalVertexPair,btInternalEdge> edges; | |||
btScalar TotalArea = 0.0f; | |||
m_localCenter.setValue(0, 0, 0); | |||
for(int i=0;i<m_faces.size();i++) | |||
{ | |||
int numVertices = m_faces[i].m_indices.size(); | |||
int NbTris = numVertices; | |||
for(int j=0;j<NbTris;j++) | |||
{ | |||
int k = (j+1)%numVertices; | |||
btInternalVertexPair vp(m_faces[i].m_indices[j],m_faces[i].m_indices[k]); | |||
btInternalEdge* edptr = edges.find(vp); | |||
btVector3 edge = m_vertices[vp.m_v1]-m_vertices[vp.m_v0]; | |||
edge.normalize(); | |||
bool found = false; | |||
for (int p=0;p<m_uniqueEdges.size();p++) | |||
{ | |||
if (IsAlmostZero(m_uniqueEdges[p]-edge) || | |||
IsAlmostZero(m_uniqueEdges[p]+edge)) | |||
{ | |||
found = true; | |||
break; | |||
} | |||
} | |||
if (!found) | |||
{ | |||
m_uniqueEdges.push_back(edge); | |||
} | |||
if (edptr) | |||
{ | |||
btAssert(edptr->m_face0>=0); | |||
btAssert(edptr->m_face1<0); | |||
edptr->m_face1 = i; | |||
} else | |||
{ | |||
btInternalEdge ed; | |||
ed.m_face0 = i; | |||
edges.insert(vp,ed); | |||
} | |||
} | |||
} | |||
#ifdef USE_CONNECTED_FACES | |||
for(int i=0;i<m_faces.size();i++) | |||
{ | |||
int numVertices = m_faces[i].m_indices.size(); | |||
m_faces[i].m_connectedFaces.resize(numVertices); | |||
for(int j=0;j<numVertices;j++) | |||
{ | |||
int k = (j+1)%numVertices; | |||
btInternalVertexPair vp(m_faces[i].m_indices[j],m_faces[i].m_indices[k]); | |||
btInternalEdge* edptr = edges.find(vp); | |||
btAssert(edptr); | |||
btAssert(edptr->m_face0>=0); | |||
btAssert(edptr->m_face1>=0); | |||
int connectedFace = (edptr->m_face0==i)?edptr->m_face1:edptr->m_face0; | |||
m_faces[i].m_connectedFaces[j] = connectedFace; | |||
} | |||
} | |||
#endif//USE_CONNECTED_FACES | |||
for(int i=0;i<m_faces.size();i++) | |||
{ | |||
int numVertices = m_faces[i].m_indices.size(); | |||
int NbTris = numVertices-2; | |||
const btVector3& p0 = m_vertices[m_faces[i].m_indices[0]]; | |||
for(int j=1;j<=NbTris;j++) | |||
{ | |||
int k = (j+1)%numVertices; | |||
const btVector3& p1 = m_vertices[m_faces[i].m_indices[j]]; | |||
const btVector3& p2 = m_vertices[m_faces[i].m_indices[k]]; | |||
btScalar Area = ((p0 - p1).cross(p0 - p2)).length() * 0.5f; | |||
btVector3 Center = (p0+p1+p2)/3.0f; | |||
m_localCenter += Area * Center; | |||
TotalArea += Area; | |||
} | |||
} | |||
m_localCenter /= TotalArea; | |||
#ifdef TEST_INTERNAL_OBJECTS | |||
if(1) | |||
{ | |||
m_radius = FLT_MAX; | |||
for(int i=0;i<m_faces.size();i++) | |||
{ | |||
const btVector3 Normal(m_faces[i].m_plane[0], m_faces[i].m_plane[1], m_faces[i].m_plane[2]); | |||
const btScalar dist = btFabs(m_localCenter.dot(Normal) + m_faces[i].m_plane[3]); | |||
if(dist<m_radius) | |||
m_radius = dist; | |||
} | |||
btScalar MinX = FLT_MAX; | |||
btScalar MinY = FLT_MAX; | |||
btScalar MinZ = FLT_MAX; | |||
btScalar MaxX = -FLT_MAX; | |||
btScalar MaxY = -FLT_MAX; | |||
btScalar MaxZ = -FLT_MAX; | |||
for(int i=0; i<m_vertices.size(); i++) | |||
{ | |||
const btVector3& pt = m_vertices[i]; | |||
if(pt.x()<MinX) MinX = pt.x(); | |||
if(pt.x()>MaxX) MaxX = pt.x(); | |||
if(pt.y()<MinY) MinY = pt.y(); | |||
if(pt.y()>MaxY) MaxY = pt.y(); | |||
if(pt.z()<MinZ) MinZ = pt.z(); | |||
if(pt.z()>MaxZ) MaxZ = pt.z(); | |||
} | |||
mC.setValue(MaxX+MinX, MaxY+MinY, MaxZ+MinZ); | |||
mE.setValue(MaxX-MinX, MaxY-MinY, MaxZ-MinZ); | |||
// const btScalar r = m_radius / sqrtf(2.0f); | |||
const btScalar r = m_radius / sqrtf(3.0f); | |||
const int LargestExtent = mE.maxAxis(); | |||
const btScalar Step = (mE[LargestExtent]*0.5f - r)/1024.0f; | |||
m_extents[0] = m_extents[1] = m_extents[2] = r; | |||
m_extents[LargestExtent] = mE[LargestExtent]*0.5f; | |||
bool FoundBox = false; | |||
for(int j=0;j<1024;j++) | |||
{ | |||
if(testContainment()) | |||
{ | |||
FoundBox = true; | |||
break; | |||
} | |||
m_extents[LargestExtent] -= Step; | |||
} | |||
if(!FoundBox) | |||
{ | |||
m_extents[0] = m_extents[1] = m_extents[2] = r; | |||
} | |||
else | |||
{ | |||
// Refine the box | |||
const btScalar Step = (m_radius - r)/1024.0f; | |||
const int e0 = (1<<LargestExtent) & 3; | |||
const int e1 = (1<<e0) & 3; | |||
for(int j=0;j<1024;j++) | |||
{ | |||
const btScalar Saved0 = m_extents[e0]; | |||
const btScalar Saved1 = m_extents[e1]; | |||
m_extents[e0] += Step; | |||
m_extents[e1] += Step; | |||
if(!testContainment()) | |||
{ | |||
m_extents[e0] = Saved0; | |||
m_extents[e1] = Saved1; | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
#endif | |||
} | |||
void btConvexPolyhedron::project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const | |||
{ | |||
min = FLT_MAX; | |||
max = -FLT_MAX; | |||
int numVerts = m_vertices.size(); | |||
for(int i=0;i<numVerts;i++) | |||
{ | |||
btVector3 pt = trans * m_vertices[i]; | |||
btScalar dp = pt.dot(dir); | |||
if(dp < min) min = dp; | |||
if(dp > max) max = dp; | |||
} | |||
if(min>max) | |||
{ | |||
btScalar tmp = min; | |||
min = max; | |||
max = tmp; | |||
} | |||
} |
@@ -0,0 +1,62 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2011 Advanced Micro Devices, Inc. http://bulletphysics.org | |||
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. | |||
*/ | |||
///This file was written by Erwin Coumans | |||
#ifndef _BT_POLYHEDRAL_FEATURES_H | |||
#define _BT_POLYHEDRAL_FEATURES_H | |||
#include "LinearMath/btTransform.h" | |||
#include "LinearMath/btAlignedObjectArray.h" | |||
#define TEST_INTERNAL_OBJECTS 1 | |||
struct btFace | |||
{ | |||
btAlignedObjectArray<int> m_indices; | |||
// btAlignedObjectArray<int> m_connectedFaces; | |||
btScalar m_plane[4]; | |||
}; | |||
class btConvexPolyhedron | |||
{ | |||
public: | |||
btConvexPolyhedron(); | |||
virtual ~btConvexPolyhedron(); | |||
btAlignedObjectArray<btVector3> m_vertices; | |||
btAlignedObjectArray<btFace> m_faces; | |||
btAlignedObjectArray<btVector3> m_uniqueEdges; | |||
btVector3 m_localCenter; | |||
btVector3 m_extents; | |||
btScalar m_radius; | |||
btVector3 mC; | |||
btVector3 mE; | |||
void initialize(); | |||
bool testContainment() const; | |||
void project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const; | |||
}; | |||
#endif //_BT_POLYHEDRAL_FEATURES_H | |||
@@ -0,0 +1,446 @@ | |||
/* | |||
Bullet Continuous Collision Detection and Physics Library | |||
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
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 "btConvexShape.h" | |||
#include "btTriangleShape.h" | |||
#include "btSphereShape.h" | |||
#include "btCylinderShape.h" | |||
#include "btCapsuleShape.h" | |||
#include "btConvexHullShape.h" | |||
#include "btConvexPointCloudShape.h" | |||
///not supported on IBM SDK, until we fix the alignment of btVector3 | |||
#if defined (__CELLOS_LV2__) && defined (__SPU__) | |||
#include <spu_intrinsics.h> | |||
static inline vec_float4 vec_dot3( vec_float4 vec0, vec_float4 vec1 ) | |||
{ | |||
vec_float4 result; | |||
result = spu_mul( vec0, vec1 ); | |||
result = spu_madd( spu_rlqwbyte( vec0, 4 ), spu_rlqwbyte( vec1, 4 ), result ); | |||
return spu_madd( spu_rlqwbyte( vec0, 8 ), spu_rlqwbyte( vec1, 8 ), result ); | |||
} | |||
#endif //__SPU__ | |||
btConvexShape::btConvexShape () | |||
{ | |||
} | |||
btConvexShape::~btConvexShape() | |||
{ | |||
} | |||
void btConvexShape::project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const | |||
{ | |||
btVector3 localAxis = dir*trans.getBasis(); | |||
btVector3 vtx1 = trans(localGetSupportingVertex(localAxis)); | |||
btVector3 vtx2 = trans(localGetSupportingVertex(-localAxis)); | |||
min = vtx1.dot(dir); | |||
max = vtx2.dot(dir); | |||
if(min>max) | |||
{ | |||
btScalar tmp = min; | |||
min = max; | |||
max = tmp; | |||
} | |||
} | |||
static btVector3 convexHullSupport (const btVector3& localDirOrg, const btVector3* points, int numPoints, const btVector3& localScaling) | |||
{ | |||
btVector3 vec = localDirOrg * localScaling; | |||
#if defined (__CELLOS_LV2__) && defined (__SPU__) | |||
btVector3 localDir = vec; | |||
vec_float4 v_distMax = {-FLT_MAX,0,0,0}; | |||
vec_int4 v_idxMax = {-999,0,0,0}; | |||
int v=0; | |||
int numverts = numPoints; | |||
for(;v<(int)numverts-4;v+=4) { | |||
vec_float4 p0 = vec_dot3(points[v ].get128(),localDir.get128()); | |||
vec_float4 p1 = vec_dot3(points[v+1].get128(),localDir.get128()); | |||
vec_float4 p2 = vec_dot3(points[v+2].get128(),localDir.get128()); | |||
vec_float4 p3 = vec_dot3(points[v+3].get128(),localDir.get128()); | |||
const vec_int4 i0 = {v ,0,0,0}; | |||
const vec_int4 i1 = {v+1,0,0,0}; | |||
const vec_int4 i2 = {v+2,0,0,0}; | |||
const vec_int4 i3 = {v+3,0,0,0}; | |||
vec_uint4 retGt01 = spu_cmpgt(p0,p1); | |||
vec_float4 pmax01 = spu_sel(p1,p0,retGt01); | |||
vec_int4 imax01 = spu_sel(i1,i0,retGt01); | |||
vec_uint4 retGt23 = spu_cmpgt(p2,p3); | |||
vec_float4 pmax23 = spu_sel(p3,p2,retGt23); | |||
vec_int4 imax23 = spu_sel(i3,i2,retGt23); | |||
vec_uint4 retGt0123 = spu_cmpgt(pmax01,pmax23); | |||
vec_float4 pmax0123 = spu_sel(pmax23,pmax01,retGt0123); | |||
vec_int4 imax0123 = spu_sel(imax23,imax01,retGt0123); | |||
vec_uint4 retGtMax = spu_cmpgt(v_distMax,pmax0123); | |||
v_distMax = spu_sel(pmax0123,v_distMax,retGtMax); | |||
v_idxMax = spu_sel(imax0123,v_idxMax,retGtMax); | |||
} | |||
for(;v<(int)numverts;v++) { | |||
vec_float4 p = vec_dot3(points[v].get128(),localDir.get128()); | |||
const vec_int4 i = {v,0,0,0}; | |||
vec_uint4 retGtMax = spu_cmpgt(v_distMax,p); | |||
v_distMax = spu_sel(p,v_distMax,retGtMax); | |||
v_idxMax = spu_sel(i,v_idxMax,retGtMax); | |||
} | |||
int ptIndex = spu_extract(v_idxMax,0); | |||
const btVector3& supVec= points[ptIndex] * localScaling; | |||
return supVec; | |||
#else | |||
btScalar newDot,maxDot = btScalar(-BT_LARGE_FLOAT); | |||
int ptIndex = -1; | |||
for (int i=0;i<numPoints;i++) | |||
{ | |||
newDot = vec.dot(points[i]); | |||
if (newDot > maxDot) | |||
{ | |||
maxDot = newDot; | |||
ptIndex = i; | |||
} | |||
} | |||
btAssert(ptIndex >= 0); | |||
btVector3 supVec = points[ptIndex] * localScaling; | |||
return supVec; | |||
#endif //__SPU__ | |||
} | |||
btVector3 btConvexShape::localGetSupportVertexWithoutMarginNonVirtual (const btVector3& localDir) const | |||
{ | |||
switch (m_shapeType) | |||
{ | |||
case SPHERE_SHAPE_PROXYTYPE: | |||
{ | |||
return btVector3(0,0,0); | |||
} | |||
case BOX_SHAPE_PROXYTYPE: | |||
{ | |||
btBoxShape* convexShape = (btBoxShape*)this; | |||
const btVector3& halfExtents = convexShape->getImplicitShapeDimensions(); | |||
return btVector3(btFsels(localDir.x(), halfExtents.x(), -halfExtents.x()), | |||
btFsels(localDir.y(), halfExtents.y(), -halfExtents.y()), | |||
btFsels(localDir.z(), halfExtents.z(), -halfExtents.z())); | |||
} | |||
case TRIANGLE_SHAPE_PROXYTYPE: | |||
{ | |||
btTriangleShape* triangleShape = (btTriangleShape*)this; | |||
btVector3 dir(localDir.getX(),localDir.getY(),localDir.getZ()); | |||
btVector3* vertices = &triangleShape->m_vertices1[0]; | |||
btVector3 dots(dir.dot(vertices[0]), dir.dot(vertices[1]), dir.dot(vertices[2])); | |||
btVector3 sup = vertices[dots.maxAxis()]; | |||
return btVector3(sup.getX(),sup.getY(),sup.getZ()); | |||
} | |||
case CYLINDER_SHAPE_PROXYTYPE: | |||
{ | |||
btCylinderShape* cylShape = (btCylinderShape*)this; | |||
//mapping of halfextents/dimension onto radius/height depends on how cylinder local orientation is (upAxis) | |||
btVector3 halfExtents = cylShape->getImplicitShapeDimensions(); | |||
btVector3 v(localDir.getX(),localDir.getY(),localDir.getZ()); | |||
int cylinderUpAxis = cylShape->getUpAxis(); | |||
int XX(1),YY(0),ZZ(2); | |||
switch (cylinderUpAxis) | |||
{ | |||
case 0: | |||
{ | |||
XX = 1; | |||
YY = 0; | |||
ZZ = 2; | |||
} | |||
break; | |||
case 1: | |||
{ | |||
XX = 0; | |||
YY = 1; | |||
ZZ = 2; | |||
} | |||
break; | |||
case 2: | |||
{ | |||
XX = 0; | |||
YY = 2; | |||
ZZ = 1; | |||
} | |||
break; | |||
default: | |||
btAssert(0); | |||
break; | |||
}; | |||
btScalar radius = halfExtents[XX]; | |||
btScalar halfHeight = halfExtents[cylinderUpAxis]; | |||
btVector3 tmp; | |||
btScalar d ; | |||
btScalar s = btSqrt(v[XX] * v[XX] + v[ZZ] * v[ZZ]); | |||
if (s != btScalar(0.0)) | |||
{ | |||
d = radius / s; | |||
tmp[XX] = v[XX] * d; | |||
tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; | |||
tmp[ZZ] = v[ZZ] * d; | |||
return btVector3(tmp.getX(),tmp.getY(),tmp.getZ()); | |||
} else { | |||
tmp[XX] = radius; | |||
tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; | |||
tmp[ZZ] = btScalar(0.0); | |||
return btVector3(tmp.getX(),tmp.getY(),tmp.getZ()); | |||
} | |||
} | |||
case CAPSULE_SHAPE_PROXYTYPE: | |||
{ | |||
btVector3 vec0(localDir.getX(),localDir.getY(),localDir.getZ()); | |||
btCapsuleShape* capsuleShape = (btCapsuleShape*)this; | |||
btScalar halfHeight = capsuleShape->getHalfHeight(); | |||
int capsuleUpAxis = capsuleShape->getUpAxis(); | |||
btScalar radius = capsuleShape->getRadius(); | |||
btVector3 supVec(0,0,0); | |||
btScalar maxDot(btScalar(-BT_LARGE_FLOAT)); | |||
btVector3 vec = vec0; | |||
btScalar lenSqr = vec.length2(); | |||
if (lenSqr < btScalar(0.0001)) | |||
{ | |||
vec.setValue(1,0,0); | |||
} else | |||
{ | |||
btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); | |||
vec *= rlen; | |||
} | |||
btVector3 vtx; | |||
btScalar newDot; | |||
{ | |||
btVector3 pos(0,0,0); | |||
pos[capsuleUpAxis] = halfHeight; | |||
//vtx = pos +vec*(radius); | |||
vtx = pos +vec*(radius) - vec * capsuleShape->getMarginNV(); | |||
newDot = vec.dot(vtx); | |||
if (newDot > maxDot) | |||
{ | |||
maxDot = newDot; | |||
supVec = vtx; | |||
} | |||
} | |||
{ | |||
btVector3 pos(0,0,0); | |||
pos[capsuleUpAxis] = -halfHeight; | |||
//vtx = pos +vec*(radius); | |||
vtx = pos +vec*(radius) - vec * capsuleShape->getMarginNV(); | |||
newDot = vec.dot(vtx); | |||
if (newDot > maxDot) | |||
{ | |||
maxDot = newDot; | |||
supVec = vtx; | |||
} | |||
} | |||
return btVector3(supVec.getX(),supVec.getY(),supVec.getZ()); | |||
} | |||
case CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: | |||
{ | |||
btConvexPointCloudShape* convexPointCloudShape = (btConvexPointCloudShape*)this; | |||
btVector3* points = convexPointCloudShape->getUnscaledPoints (); | |||
int numPoints = convexPointCloudShape->getNumPoints (); | |||
return convexHullSupport (localDir, points, numPoints,convexPointCloudShape->getLocalScalingNV()); | |||
} | |||
case CONVEX_HULL_SHAPE_PROXYTYPE: | |||
{ | |||
btConvexHullShape* convexHullShape = (btConvexHullShape*)this; | |||
btVector3* points = convexHullShape->getUnscaledPoints(); | |||
int numPoints = convexHullShape->getNumPoints (); | |||
return convexHullSupport (localDir, points, numPoints,convexHullShape->getLocalScalingNV()); | |||
} | |||
default: | |||
#ifndef __SPU__ | |||
return this->localGetSupportingVertexWithoutMargin (localDir); | |||
#else | |||
btAssert (0); | |||
#endif | |||
} | |||
// should never reach here | |||
btAssert (0); | |||
return btVector3 (btScalar(0.0f), btScalar(0.0f), btScalar(0.0f)); | |||
} | |||
btVector3 btConvexShape::localGetSupportVertexNonVirtual (const btVector3& localDir) const | |||
{ | |||
btVector3 localDirNorm = localDir; | |||
if (localDirNorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) | |||
{ | |||
localDirNorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); | |||
} | |||
localDirNorm.normalize (); | |||
return localGetSupportVertexWithoutMarginNonVirtual(localDirNorm)+ getMarginNonVirtual() * localDirNorm; | |||
} | |||
/* TODO: This should be bumped up to btCollisionShape () */ | |||
btScalar btConvexShape::getMarginNonVirtual () const | |||
{ | |||
switch (m_shapeType) | |||
{ | |||
case SPHERE_SHAPE_PROXYTYPE: | |||
{ | |||
btSphereShape* sphereShape = (btSphereShape*)this; | |||
return sphereShape->getRadius (); | |||
} | |||
case BOX_SHAPE_PROXYTYPE: | |||
{ | |||
btBoxShape* convexShape = (btBoxShape*)this; | |||
return convexShape->getMarginNV (); | |||
} | |||
case TRIANGLE_SHAPE_PROXYTYPE: | |||
{ | |||
btTriangleShape* triangleShape = (btTriangleShape*)this; | |||
return triangleShape->getMarginNV (); | |||
} | |||
case CYLINDER_SHAPE_PROXYTYPE: | |||
{ | |||
btCylinderShape* cylShape = (btCylinderShape*)this; | |||
return cylShape->getMarginNV(); | |||
} | |||
case CAPSULE_SHAPE_PROXYTYPE: | |||
{ | |||
btCapsuleShape* capsuleShape = (btCapsuleShape*)this; | |||
return capsuleShape->getMarginNV(); | |||
} | |||
case CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: | |||
/* fall through */ | |||
case CONVEX_HULL_SHAPE_PROXYTYPE: | |||
{ | |||
btPolyhedralConvexShape* convexHullShape = (btPolyhedralConvexShape*)this; | |||
return convexHullShape->getMarginNV(); | |||
} | |||
default: | |||
#ifndef __SPU__ | |||
return this->getMargin (); | |||
#else | |||
btAssert (0); | |||
#endif | |||
} | |||
// should never reach here | |||
btAssert (0); | |||
return btScalar(0.0f); | |||
} | |||
#ifndef __SPU__ | |||
void btConvexShape::getAabbNonVirtual (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const | |||
{ | |||
switch (m_shapeType) | |||
{ | |||
case SPHERE_SHAPE_PROXYTYPE: | |||
{ | |||
btSphereShape* sphereShape = (btSphereShape*)this; | |||
btScalar radius = sphereShape->getImplicitShapeDimensions().getX();// * convexShape->getLocalScaling().getX(); | |||
btScalar margin = radius + sphereShape->getMarginNonVirtual(); | |||
const btVector3& center = t.getOrigin(); | |||
btVector3 extent(margin,margin,margin); | |||
aabbMin = center - extent; | |||
aabbMax = center + extent; | |||
} | |||
break; | |||
case CYLINDER_SHAPE_PROXYTYPE: | |||
/* fall through */ | |||
case BOX_SHAPE_PROXYTYPE: | |||
{ | |||
btBoxShape* convexShape = (btBoxShape*)this; | |||
btScalar margin=convexShape->getMarginNonVirtual(); | |||
btVector3 halfExtents = convexShape->getImplicitShapeDimensions(); | |||
halfExtents += btVector3(margin,margin,margin); | |||
btMatrix3x3 abs_b = t.getBasis().absolute(); | |||
btVector3 center = t.getOrigin(); | |||
btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); | |||
aabbMin = center - extent; | |||
aabbMax = center + extent; | |||
break; | |||
} | |||
case TRIANGLE_SHAPE_PROXYTYPE: | |||
{ | |||
btTriangleShape* triangleShape = (btTriangleShape*)this; | |||
btScalar margin = triangleShape->getMarginNonVirtual(); | |||
for (int i=0;i<3;i++) | |||
{ | |||
btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); | |||
vec[i] = btScalar(1.); | |||
btVector3 sv = localGetSupportVertexWithoutMarginNonVirtual(vec*t.getBasis()); | |||
btVector3 tmp = t(sv); | |||
aabbMax[i] = tmp[i]+margin; | |||
vec[i] = btScalar(-1.); | |||
tmp = t(localGetSupportVertexWithoutMarginNonVirtual(vec*t.getBasis())); | |||
aabbMin[i] = tmp[i]-margin; | |||
} | |||
} | |||
break; | |||
case CAPSULE_SHAPE_PROXYTYPE: | |||
{ | |||
btCapsuleShape* capsuleShape = (btCapsuleShape*)this; | |||
btVector3 halfExtents(capsuleShape->getRadius(),capsuleShape->getRadius(),capsuleShape->getRadius()); | |||
int m_upAxis = capsuleShape->getUpAxis(); | |||
halfExtents[m_upAxis] = capsuleShape->getRadius() + capsuleShape->getHalfHeight(); | |||
halfExtents += btVector3(capsuleShape->getMarginNonVirtual(),capsuleShape->getMarginNonVirtual(),capsuleShape->getMarginNonVirtual()); | |||
btMatrix3x3 abs_b = t.getBasis().absolute(); | |||
btVector3 center = t.getOrigin(); | |||
btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); | |||
aabbMin = center - extent; | |||
aabbMax = center + extent; | |||
} | |||
break; | |||
case CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: | |||
case CONVEX_HULL_SHAPE_PROXYTYPE: | |||
{ | |||
btPolyhedralConvexAabbCachingShape* convexHullShape = (btPolyhedralConvexAabbCachingShape*)this; | |||
btScalar margin = convexHullShape->getMarginNonVirtual(); | |||
convexHullShape->getNonvirtualAabb (t, aabbMin, aabbMax, margin); | |||
} | |||
break; | |||
default: | |||
#ifndef __SPU__ | |||
this->getAabb (t, aabbMin, aabbMax); | |||
#else | |||
btAssert (0); | |||
#endif | |||
break; | |||
} | |||
// should never reach here | |||
btAssert (0); | |||
} | |||
#endif //__SPU__ |