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__ | |||||