that’s precisely how they want us to use it.legacy
@@ -35,6 +35,7 @@ liblol_a_SOURCES = \ | |||||
$(sdl_sources) \ | $(sdl_sources) \ | ||||
$(d3d9_sources) \ | $(d3d9_sources) \ | ||||
$(android_sources) \ | $(android_sources) \ | ||||
$(bullet_sources) \ | |||||
\ | \ | ||||
thread/threadbase.h thread/thread.h \ | 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/fps.cpp debug/fps.h debug/sphere.cpp debug/sphere.h \ | ||||
debug/record.cpp debug/record.h debug/stats.cpp debug/stats.h \ | debug/record.cpp debug/record.h debug/stats.cpp debug/stats.h \ | ||||
debug/quad.cpp debug/quad.h | debug/quad.cpp debug/quad.h | ||||
liblol_a_CPPFLAGS = @LOL_CFLAGS@ | |||||
liblol_a_CPPFLAGS = @LOL_CFLAGS@ -Ibullet | |||||
SUFFIXES = .lolfx | SUFFIXES = .lolfx | ||||
.lolfx.o: | .lolfx.o: | ||||
@@ -113,3 +114,545 @@ android_sources = \ | |||||
image/codec/android-image.cpp \ | image/codec/android-image.cpp \ | ||||
platform/android/androidapp.cpp platform/android/androidapp.h | 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__ |