that’s precisely how they want us to use it.legacy
| @@ -35,6 +35,7 @@ liblol_a_SOURCES = \ | |||
| $(sdl_sources) \ | |||
| $(d3d9_sources) \ | |||
| $(android_sources) \ | |||
| $(bullet_sources) \ | |||
| \ | |||
| thread/threadbase.h thread/thread.h \ | |||
| \ | |||
| @@ -60,7 +61,7 @@ liblol_a_SOURCES = \ | |||
| debug/fps.cpp debug/fps.h debug/sphere.cpp debug/sphere.h \ | |||
| debug/record.cpp debug/record.h debug/stats.cpp debug/stats.h \ | |||
| debug/quad.cpp debug/quad.h | |||
| liblol_a_CPPFLAGS = @LOL_CFLAGS@ | |||
| liblol_a_CPPFLAGS = @LOL_CFLAGS@ -Ibullet | |||
| SUFFIXES = .lolfx | |||
| .lolfx.o: | |||
| @@ -113,3 +114,545 @@ android_sources = \ | |||
| image/codec/android-image.cpp \ | |||
| platform/android/androidapp.cpp platform/android/androidapp.h | |||
| bullet_sources = | |||
| if FALSE #CONDITIONAL_BUILD_MULTITHREADED | |||
| bullet_sources += \ | |||
| bullet/BulletMultiThreaded/PosixThreadSupport.h \ | |||
| bullet/BulletMultiThreaded/vectormath/scalar/cpp/mat_aos.h \ | |||
| bullet/BulletMultiThreaded/vectormath/scalar/cpp/vec_aos.h \ | |||
| bullet/BulletMultiThreaded/vectormath/scalar/cpp/quat_aos.h \ | |||
| bullet/BulletMultiThreaded/vectormath/scalar/cpp/vectormath_aos.h \ | |||
| bullet/BulletMultiThreaded/PpuAddressSpace.h \ | |||
| bullet/BulletMultiThreaded/SpuCollisionTaskProcess.h \ | |||
| bullet/BulletMultiThreaded/PlatformDefinitions.h \ | |||
| bullet/BulletMultiThreaded/vectormath2bullet.h \ | |||
| bullet/BulletMultiThreaded/SpuGatheringCollisionDispatcher.h \ | |||
| bullet/BulletMultiThreaded/SpuCollisionObjectWrapper.h \ | |||
| bullet/BulletMultiThreaded/SpuSampleTaskProcess.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/boxBoxDistance.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/Box.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPenetrationDepthSolver.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuLocalSupport.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuConvexPenetrationDepthSolver.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuContactResult.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuPreferredPenetrationDirections.h \ | |||
| bullet/BulletMultiThreaded/SpuSync.h \ | |||
| bullet/BulletMultiThreaded/btThreadSupportInterface.h \ | |||
| bullet/BulletMultiThreaded/SpuLibspe2Support.h \ | |||
| bullet/BulletMultiThreaded/SpuSampleTask/SpuSampleTask.h \ | |||
| bullet/BulletMultiThreaded/SpuFakeDma.h \ | |||
| bullet/BulletMultiThreaded/SpuContactManifoldCollisionAlgorithm.h \ | |||
| bullet/BulletMultiThreaded/SpuDoubleBuffer.h \ | |||
| bullet/BulletMultiThreaded/Win32ThreadSupport.h \ | |||
| bullet/BulletMultiThreaded/SequentialThreadSupport.h | |||
| libBulletMultiThreaded_la_CXXFLAGS = ${CXXFLAGS} -I./BulletMultiThreaded/vectormath/scalar/cpp | |||
| bullet_sources += \ | |||
| bullet/BulletMultiThreaded/SpuCollisionObjectWrapper.cpp \ | |||
| bullet/BulletMultiThreaded/SpuSampleTask/SpuSampleTask.cpp \ | |||
| bullet/BulletMultiThreaded/SpuLibspe2Support.cpp \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuContactResult.cpp \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.cpp \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPenetrationDepthSolver.cpp \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.cpp \ | |||
| bullet/BulletMultiThreaded/btThreadSupportInterface.cpp \ | |||
| bullet/BulletMultiThreaded/SequentialThreadSupport.cpp \ | |||
| bullet/BulletMultiThreaded/SpuGatheringCollisionDispatcher.cpp \ | |||
| bullet/BulletMultiThreaded/Win32ThreadSupport.cpp \ | |||
| bullet/BulletMultiThreaded/SpuFakeDma.cpp \ | |||
| bullet/BulletMultiThreaded/PosixThreadSupport.cpp \ | |||
| bullet/BulletMultiThreaded/SpuCollisionTaskProcess.cpp \ | |||
| bullet/BulletMultiThreaded/SpuContactManifoldCollisionAlgorithm.cpp \ | |||
| bullet/BulletMultiThreaded/SpuSampleTaskProcess.cpp \ | |||
| bullet/BulletMultiThreaded/SpuSampleTask/SpuSampleTask.h \ | |||
| bullet/BulletMultiThreaded/PpuAddressSpace.h \ | |||
| bullet/BulletMultiThreaded/SpuSampleTaskProcess.h \ | |||
| bullet/BulletMultiThreaded/SequentialThreadSupport.h \ | |||
| bullet/BulletMultiThreaded/PlatformDefinitions.h \ | |||
| bullet/BulletMultiThreaded/Win32ThreadSupport.h \ | |||
| bullet/BulletMultiThreaded/SpuContactManifoldCollisionAlgorithm.h \ | |||
| bullet/BulletMultiThreaded/btThreadSupportInterface.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuConvexPenetrationDepthSolver.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuPreferredPenetrationDirections.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuLocalSupport.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPenetrationDepthSolver.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuContactResult.h \ | |||
| bullet/BulletMultiThreaded/SpuGatheringCollisionDispatcher.h \ | |||
| bullet/BulletMultiThreaded/SpuFakeDma.h \ | |||
| bullet/BulletMultiThreaded/SpuSync.h \ | |||
| bullet/BulletMultiThreaded/SpuCollisionObjectWrapper.h \ | |||
| bullet/BulletMultiThreaded/SpuDoubleBuffer.h \ | |||
| bullet/BulletMultiThreaded/SpuCollisionTaskProcess.h \ | |||
| bullet/BulletMultiThreaded/PosixThreadSupport.h \ | |||
| bullet/BulletMultiThreaded/SpuLibspe2Support.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/boxBoxDistance.cpp \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/boxBoxDistance.h \ | |||
| bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/Box.h | |||
| endif | |||
| bullet_sources += \ | |||
| bullet/LinearMath/btQuickprof.cpp \ | |||
| bullet/LinearMath/btGeometryUtil.cpp \ | |||
| bullet/LinearMath/btAlignedAllocator.cpp \ | |||
| bullet/LinearMath/btSerializer.cpp \ | |||
| bullet/LinearMath/btConvexHull.cpp \ | |||
| bullet/LinearMath/btConvexHullComputer.cpp \ | |||
| bullet/LinearMath/btHashMap.h \ | |||
| bullet/LinearMath/btConvexHull.h \ | |||
| bullet/LinearMath/btAabbUtil2.h \ | |||
| bullet/LinearMath/btGeometryUtil.h \ | |||
| bullet/LinearMath/btQuadWord.h \ | |||
| bullet/LinearMath/btPoolAllocator.h \ | |||
| bullet/LinearMath/btScalar.h \ | |||
| bullet/LinearMath/btMinMax.h \ | |||
| bullet/LinearMath/btVector3.h \ | |||
| bullet/LinearMath/btList.h \ | |||
| bullet/LinearMath/btStackAlloc.h \ | |||
| bullet/LinearMath/btMatrix3x3.h \ | |||
| bullet/LinearMath/btMotionState.h \ | |||
| bullet/LinearMath/btAlignedAllocator.h \ | |||
| bullet/LinearMath/btQuaternion.h \ | |||
| bullet/LinearMath/btAlignedObjectArray.h \ | |||
| bullet/LinearMath/btQuickprof.h \ | |||
| bullet/LinearMath/btSerializer.h \ | |||
| bullet/LinearMath/btTransformUtil.h \ | |||
| bullet/LinearMath/btTransform.h \ | |||
| bullet/LinearMath/btDefaultMotionState.h \ | |||
| bullet/LinearMath/btIDebugDraw.h \ | |||
| bullet/LinearMath/btRandom.h | |||
| bullet_sources += \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btConvexCast.cpp \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionObject.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btGhostObject.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btManifoldResult.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btUnionFind.cpp \ | |||
| bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btTetrahedronShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btShapeHull.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btCompoundShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btConeShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btMultiSphereShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btUniformScalingShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btSphereShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleBuffer.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btEmptyShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btCollisionShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btConvex2dShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexInternalShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexHullShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleCallback.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btCapsuleShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btConcaveShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btBoxShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btBox2dShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btOptimizedBvh.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btCylinderShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleMesh.cpp \ | |||
| bullet/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp \ | |||
| bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp \ | |||
| bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp \ | |||
| bullet/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp \ | |||
| bullet/BulletCollision/BroadphaseCollision/btDispatcher.cpp \ | |||
| bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp \ | |||
| bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp \ | |||
| bullet/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp \ | |||
| bullet/BulletCollision/BroadphaseCollision/btDbvt.cpp \ | |||
| bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btConvexCast.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btPointCollector.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionObject.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btGhostObject.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btBoxBoxDetector.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.h \ | |||
| bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btUnionFind.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionWorld.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btManifoldResult.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionConfiguration.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConvex2dShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleCallback.h \ | |||
| bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btCompoundShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btBoxShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btBox2dShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btMultiSphereShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btCollisionMargin.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConcaveShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btEmptyShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btUniformScalingShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btMaterial.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleInfoMap.h \ | |||
| bullet/BulletCollision/CollisionShapes/btSphereShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexPointCloudShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btCapsuleShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btCollisionShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleMeshShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btStridingMeshInterface.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleMesh.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleBuffer.h \ | |||
| bullet/BulletCollision/CollisionShapes/btShapeHull.h \ | |||
| bullet/BulletCollision/CollisionShapes/btMinkowskiSumShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btOptimizedBvh.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h \ | |||
| bullet/BulletCollision/CollisionShapes/btCylinderShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTetrahedronShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexInternalShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConeShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexHullShape.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btAxisSweep3.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btDbvt.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btDispatcher.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.h \ | |||
| bullet/BulletCollision/Gimpact/btGImpactBvh.cpp\ | |||
| bullet/BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp\ | |||
| bullet/BulletCollision/Gimpact/btTriangleShapeEx.cpp\ | |||
| bullet/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp\ | |||
| bullet/BulletCollision/Gimpact/btGImpactShape.cpp\ | |||
| bullet/BulletCollision/Gimpact/gim_box_set.cpp\ | |||
| bullet/BulletCollision/Gimpact/gim_contact.cpp\ | |||
| bullet/BulletCollision/Gimpact/gim_memory.cpp\ | |||
| bullet/BulletCollision/Gimpact/gim_tri_collision.cpp | |||
| bullet_sources += \ | |||
| bullet/BulletDynamics/Dynamics/btRigidBody.cpp \ | |||
| bullet/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp \ | |||
| bullet/BulletDynamics/Dynamics/Bullet-C-API.cpp \ | |||
| bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp \ | |||
| bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp \ | |||
| bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp \ | |||
| bullet/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp \ | |||
| bullet/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp \ | |||
| bullet/BulletDynamics/ConstraintSolver/btContactConstraint.cpp \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp \ | |||
| bullet/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp \ | |||
| bullet/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp \ | |||
| bullet/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp \ | |||
| bullet/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp \ | |||
| bullet/BulletDynamics/Vehicle/btWheelInfo.cpp \ | |||
| bullet/BulletDynamics/Vehicle/btRaycastVehicle.cpp \ | |||
| bullet/BulletDynamics/Character/btKinematicCharacterController.cpp \ | |||
| bullet/BulletDynamics/Character/btKinematicCharacterController.h \ | |||
| bullet/BulletDynamics/Character/btCharacterControllerInterface.h \ | |||
| bullet/BulletDynamics/Dynamics/btActionInterface.h \ | |||
| bullet/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h \ | |||
| bullet/BulletDynamics/Dynamics/btRigidBody.h \ | |||
| bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h \ | |||
| bullet/BulletDynamics/Dynamics/btDynamicsWorld.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSolverBody.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btConstraintSolver.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btTypedConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btContactConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btJacobianEntry.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSolverConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btHingeConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btHinge2Constraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btUniversalConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSolve2bullet/LinearConstraint.h \ | |||
| bullet/BulletDynamics/Vehicle/btVehicleRaycaster.h \ | |||
| bullet/BulletDynamics/Vehicle/btRaycastVehicle.h \ | |||
| bullet/BulletDynamics/Vehicle/btWheelInfo.h | |||
| bullet_sources += \ | |||
| bullet/BulletSoftBody/btDefaultSoftBodySolver.cpp \ | |||
| bullet/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp \ | |||
| bullet/BulletSoftBody/btSoftBody.cpp \ | |||
| bullet/BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp \ | |||
| bullet/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp \ | |||
| bullet/BulletSoftBody/btSoftRigidDynamicsWorld.cpp \ | |||
| bullet/BulletSoftBody/btSoftBodyHelpers.cpp \ | |||
| bullet/BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp \ | |||
| bullet/BulletSoftBody/btSparseSDF.h \ | |||
| bullet/BulletSoftBody/btSoftRigidCollisionAlgorithm.h \ | |||
| bullet/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h \ | |||
| bullet/BulletSoftBody/btSoftBody.h \ | |||
| bullet/BulletSoftBody/btSoftSoftCollisionAlgorithm.h \ | |||
| bullet/BulletSoftBody/btSoftBodyInternals.h \ | |||
| bullet/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h \ | |||
| bullet/BulletSoftBody/btSoftRigidDynamicsWorld.h \ | |||
| bullet/BulletSoftBody/btSoftBodyHelpers.h | |||
| bullet_sources += \ | |||
| bullet/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h \ | |||
| bullet/BulletSoftBody/btSoftBodyInternals.h \ | |||
| bullet/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h \ | |||
| bullet/BulletSoftBody/btSoftSoftCollisionAlgorithm.h \ | |||
| bullet/BulletSoftBody/btSoftBody.h \ | |||
| bullet/BulletSoftBody/btSoftBodyHelpers.h \ | |||
| bullet/BulletSoftBody/btSparseSDF.h \ | |||
| bullet/BulletSoftBody/btSoftRigidCollisionAlgorithm.h \ | |||
| bullet/BulletSoftBody/btSoftRigidDynamicsWorld.h \ | |||
| bullet/BulletDynamics/Vehicle/btRaycastVehicle.h \ | |||
| bullet/BulletDynamics/Vehicle/btWheelInfo.h \ | |||
| bullet/BulletDynamics/Vehicle/btVehicleRaycaster.h \ | |||
| bullet/BulletDynamics/Dynamics/btActionInterface.h \ | |||
| bullet/BulletDynamics/Dynamics/btRigidBody.h \ | |||
| bullet/BulletDynamics/Dynamics/btDynamicsWorld.h \ | |||
| bullet/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h \ | |||
| bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSolverConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btTypedConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btConstraintSolver.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btContactConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btJacobianEntry.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSolve2bullet/LinearConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btHingeConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btHinge2Constraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btUniversalConstraint.h \ | |||
| bullet/BulletDynamics/ConstraintSolver/btSolverBody.h \ | |||
| bullet/BulletDynamics/Character/btCharacterControllerInterface.h \ | |||
| bullet/BulletDynamics/Character/btKinematicCharacterController.h \ | |||
| bullet/BulletCollision/CollisionShapes/btShapeHull.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConcaveShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btCollisionMargin.h \ | |||
| bullet/BulletCollision/CollisionShapes/btCompoundShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexHullShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btCylinderShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleMesh.h \ | |||
| bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btUniformScalingShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexPointCloudShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTetrahedronShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btCapsuleShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btSphereShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btMultiSphereShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexInternalShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btStridingMeshInterface.h \ | |||
| bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btEmptyShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btOptimizedBvh.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleCallback.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleInfoMap.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleBuffer.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConvexShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConvex2dShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btConeShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btCollisionShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btBoxShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btBox2dShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btMinkowskiSumShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btTriangleMeshShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btMaterial.h \ | |||
| bullet/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h \ | |||
| bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btConvexCast.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btPointCollector.h \ | |||
| bullet/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btDbvt.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btDispatcher.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btAxisSweep3.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h \ | |||
| bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btUnionFind.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionConfiguration.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.h \ | |||
| bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionWorld.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btCollisionObject.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btGhostObject.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btBoxBoxDetector.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h \ | |||
| bullet/BulletCollision/CollisionDispatch/btManifoldResult.h \ | |||
| bullet/BulletCollision/Gimpact/gim_memory.h \ | |||
| bullet/BulletCollision/Gimpact/gim_clip_polygon.h \ | |||
| bullet/BulletCollision/Gimpact/gim_bitset.h \ | |||
| bullet/BulletCollision/Gimpact/gim_linear_math.h \ | |||
| bullet/BulletCollision/Gimpact/btGeometryOperations.h \ | |||
| bullet/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h \ | |||
| bullet/BulletCollision/Gimpact/btGImpactBvh.h \ | |||
| bullet/BulletCollision/Gimpact/gim_box_set.h \ | |||
| bullet/BulletCollision/Gimpact/gim_array.h \ | |||
| bullet/BulletCollision/Gimpact/btGImpactShape.h \ | |||
| bullet/BulletCollision/Gimpact/btTriangleShapeEx.h \ | |||
| bullet/BulletCollision/Gimpact/btClipPolygon.h \ | |||
| bullet/BulletCollision/Gimpact/gim_box_collision.h \ | |||
| bullet/BulletCollision/Gimpact/gim_tri_collision.h \ | |||
| bullet/BulletCollision/Gimpact/gim_geometry.h \ | |||
| bullet/BulletCollision/Gimpact/gim_math.h \ | |||
| bullet/BulletCollision/Gimpact/btQuantization.h \ | |||
| bullet/BulletCollision/Gimpact/btGImpactQuantizedBvh.h \ | |||
| bullet/BulletCollision/Gimpact/gim_geom_types.h \ | |||
| bullet/BulletCollision/Gimpact/gim_basic_geometry_operations.h \ | |||
| bullet/BulletCollision/Gimpact/gim_contact.h \ | |||
| bullet/BulletCollision/Gimpact/gim_hash_table.h \ | |||
| bullet/BulletCollision/Gimpact/gim_radixsort.h \ | |||
| bullet/BulletCollision/Gimpact/btGImpactMassUtil.h \ | |||
| bullet/BulletCollision/Gimpact/btGenericPoolAllocator.h \ | |||
| bullet/BulletCollision/Gimpact/btBoxCollision.h \ | |||
| bullet/BulletCollision/Gimpact/btContactProcessing.h \ | |||
| bullet/LinearMath/btGeometryUtil.h \ | |||
| bullet/LinearMath/btConvexHull.h \ | |||
| bullet/LinearMath/btList.h \ | |||
| bullet/LinearMath/btMatrix3x3.h \ | |||
| bullet/LinearMath/btVector3.h \ | |||
| bullet/LinearMath/btPoolAllocator.h \ | |||
| bullet/LinearMath/btScalar.h \ | |||
| bullet/LinearMath/btDefaultMotionState.h \ | |||
| bullet/LinearMath/btTransform.h \ | |||
| bullet/LinearMath/btQuadWord.h \ | |||
| bullet/LinearMath/btAabbUtil2.h \ | |||
| bullet/LinearMath/btTransformUtil.h \ | |||
| bullet/LinearMath/btRandom.h \ | |||
| bullet/LinearMath/btQuaternion.h \ | |||
| bullet/LinearMath/btMinMax.h \ | |||
| bullet/LinearMath/btMotionState.h \ | |||
| bullet/LinearMath/btIDebugDraw.h \ | |||
| bullet/LinearMath/btAlignedAllocator.h \ | |||
| bullet/LinearMath/btStackAlloc.h \ | |||
| bullet/LinearMath/btAlignedObjectArray.h \ | |||
| bullet/LinearMath/btHashMap.h \ | |||
| bullet/LinearMath/btQuickprof.h\ | |||
| bullet/LinearMath/btSerializer.h | |||
| @@ -0,0 +1,176 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| /* | |||
| Draft high-level generic physics C-API. For low-level access, use the physics SDK native API's. | |||
| Work in progress, functionality will be added on demand. | |||
| If possible, use the richer Bullet C++ API, by including "btBulletDynamicsCommon.h" | |||
| */ | |||
| #ifndef BULLET_C_API_H | |||
| #define BULLET_C_API_H | |||
| #define PL_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name | |||
| #ifdef BT_USE_DOUBLE_PRECISION | |||
| typedef double plReal; | |||
| #else | |||
| typedef float plReal; | |||
| #endif | |||
| typedef plReal plVector3[3]; | |||
| typedef plReal plQuaternion[4]; | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /** Particular physics SDK (C-API) */ | |||
| PL_DECLARE_HANDLE(plPhysicsSdkHandle); | |||
| /** Dynamics world, belonging to some physics SDK (C-API)*/ | |||
| PL_DECLARE_HANDLE(plDynamicsWorldHandle); | |||
| /** Rigid Body that can be part of a Dynamics World (C-API)*/ | |||
| PL_DECLARE_HANDLE(plRigidBodyHandle); | |||
| /** Collision Shape/Geometry, property of a Rigid Body (C-API)*/ | |||
| PL_DECLARE_HANDLE(plCollisionShapeHandle); | |||
| /** Constraint for Rigid Bodies (C-API)*/ | |||
| PL_DECLARE_HANDLE(plConstraintHandle); | |||
| /** Triangle Mesh interface (C-API)*/ | |||
| PL_DECLARE_HANDLE(plMeshInterfaceHandle); | |||
| /** Broadphase Scene/Proxy Handles (C-API)*/ | |||
| PL_DECLARE_HANDLE(plCollisionBroadphaseHandle); | |||
| PL_DECLARE_HANDLE(plBroadphaseProxyHandle); | |||
| PL_DECLARE_HANDLE(plCollisionWorldHandle); | |||
| /** | |||
| Create and Delete a Physics SDK | |||
| */ | |||
| extern plPhysicsSdkHandle plNewBulletSdk(void); //this could be also another sdk, like ODE, PhysX etc. | |||
| extern void plDeletePhysicsSdk(plPhysicsSdkHandle physicsSdk); | |||
| /** Collision World, not strictly necessary, you can also just create a Dynamics World with Rigid Bodies which internally manages the Collision World with Collision Objects */ | |||
| typedef void(*btBroadphaseCallback)(void* clientData, void* object1,void* object2); | |||
| extern plCollisionBroadphaseHandle plCreateSapBroadphase(btBroadphaseCallback beginCallback,btBroadphaseCallback endCallback); | |||
| extern void plDestroyBroadphase(plCollisionBroadphaseHandle bp); | |||
| extern plBroadphaseProxyHandle plCreateProxy(plCollisionBroadphaseHandle bp, void* clientData, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ); | |||
| extern void plDestroyProxy(plCollisionBroadphaseHandle bp, plBroadphaseProxyHandle proxyHandle); | |||
| extern void plSetBoundingBox(plBroadphaseProxyHandle proxyHandle, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ); | |||
| /* todo: add pair cache support with queries like add/remove/find pair */ | |||
| extern plCollisionWorldHandle plCreateCollisionWorld(plPhysicsSdkHandle physicsSdk); | |||
| /* todo: add/remove objects */ | |||
| /* Dynamics World */ | |||
| extern plDynamicsWorldHandle plCreateDynamicsWorld(plPhysicsSdkHandle physicsSdk); | |||
| extern void plDeleteDynamicsWorld(plDynamicsWorldHandle world); | |||
| extern void plStepSimulation(plDynamicsWorldHandle, plReal timeStep); | |||
| extern void plAddRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object); | |||
| extern void plRemoveRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object); | |||
| /* Rigid Body */ | |||
| extern plRigidBodyHandle plCreateRigidBody( void* user_data, float mass, plCollisionShapeHandle cshape ); | |||
| extern void plDeleteRigidBody(plRigidBodyHandle body); | |||
| /* Collision Shape definition */ | |||
| extern plCollisionShapeHandle plNewSphereShape(plReal radius); | |||
| extern plCollisionShapeHandle plNewBoxShape(plReal x, plReal y, plReal z); | |||
| extern plCollisionShapeHandle plNewCapsuleShape(plReal radius, plReal height); | |||
| extern plCollisionShapeHandle plNewConeShape(plReal radius, plReal height); | |||
| extern plCollisionShapeHandle plNewCylinderShape(plReal radius, plReal height); | |||
| extern plCollisionShapeHandle plNewCompoundShape(void); | |||
| extern void plAddChildShape(plCollisionShapeHandle compoundShape,plCollisionShapeHandle childShape, plVector3 childPos,plQuaternion childOrn); | |||
| extern void plDeleteShape(plCollisionShapeHandle shape); | |||
| /* Convex Meshes */ | |||
| extern plCollisionShapeHandle plNewConvexHullShape(void); | |||
| extern void plAddVertex(plCollisionShapeHandle convexHull, plReal x,plReal y,plReal z); | |||
| /* Concave static triangle meshes */ | |||
| extern plMeshInterfaceHandle plNewMeshInterface(void); | |||
| extern void plAddTriangle(plMeshInterfaceHandle meshHandle, plVector3 v0,plVector3 v1,plVector3 v2); | |||
| extern plCollisionShapeHandle plNewStaticTriangleMeshShape(plMeshInterfaceHandle); | |||
| extern void plSetScaling(plCollisionShapeHandle shape, plVector3 scaling); | |||
| /* SOLID has Response Callback/Table/Management */ | |||
| /* PhysX has Triggers, User Callbacks and filtering */ | |||
| /* ODE has the typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); */ | |||
| /* typedef void plUpdatedPositionCallback(void* userData, plRigidBodyHandle rbHandle, plVector3 pos); */ | |||
| /* typedef void plUpdatedOrientationCallback(void* userData, plRigidBodyHandle rbHandle, plQuaternion orientation); */ | |||
| /* get world transform */ | |||
| extern void plGetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix); | |||
| extern void plGetPosition(plRigidBodyHandle object,plVector3 position); | |||
| extern void plGetOrientation(plRigidBodyHandle object,plQuaternion orientation); | |||
| /* set world transform (position/orientation) */ | |||
| extern void plSetPosition(plRigidBodyHandle object, const plVector3 position); | |||
| extern void plSetOrientation(plRigidBodyHandle object, const plQuaternion orientation); | |||
| extern void plSetEuler(plReal yaw,plReal pitch,plReal roll, plQuaternion orient); | |||
| extern void plSetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix); | |||
| typedef struct plRayCastResult { | |||
| plRigidBodyHandle m_body; | |||
| plCollisionShapeHandle m_shape; | |||
| plVector3 m_positionWorld; | |||
| plVector3 m_normalWorld; | |||
| } plRayCastResult; | |||
| extern int plRayCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plRayCastResult res); | |||
| /* Sweep API */ | |||
| /* extern plRigidBodyHandle plObjectCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plVector3 hitpoint, plVector3 normal); */ | |||
| /* Continuous Collision Detection API */ | |||
| // needed for source/blender/blenkernel/intern/collision.c | |||
| double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float q2[3], float q3[3], float *pa, float *pb, float normal[3]); | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif //BULLET_C_API_H | |||
| @@ -0,0 +1,37 @@ | |||
| //Bullet Continuous Collision Detection and Physics Library | |||
| //Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| // | |||
| // btAxisSweep3 | |||
| // | |||
| // Copyright (c) 2006 Simon Hobbs | |||
| // | |||
| // This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. | |||
| // | |||
| // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: | |||
| // | |||
| // 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| // | |||
| // 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| // | |||
| // 3. This notice may not be removed or altered from any source distribution. | |||
| #include "btAxisSweep3.h" | |||
| btAxisSweep3::btAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned short int maxHandles, btOverlappingPairCache* pairCache, bool disableRaycastAccelerator) | |||
| :btAxisSweep3Internal<unsigned short int>(worldAabbMin,worldAabbMax,0xfffe,0xffff,maxHandles,pairCache,disableRaycastAccelerator) | |||
| { | |||
| // 1 handle is reserved as sentinel | |||
| btAssert(maxHandles > 1 && maxHandles < 32767); | |||
| } | |||
| bt32BitAxisSweep3::bt32BitAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned int maxHandles , btOverlappingPairCache* pairCache , bool disableRaycastAccelerator) | |||
| :btAxisSweep3Internal<unsigned int>(worldAabbMin,worldAabbMax,0xfffffffe,0x7fffffff,maxHandles,pairCache,disableRaycastAccelerator) | |||
| { | |||
| // 1 handle is reserved as sentinel | |||
| btAssert(maxHandles > 1 && maxHandles < 2147483647); | |||
| } | |||
| @@ -0,0 +1,82 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_BROADPHASE_INTERFACE_H | |||
| #define BT_BROADPHASE_INTERFACE_H | |||
| struct btDispatcherInfo; | |||
| class btDispatcher; | |||
| #include "btBroadphaseProxy.h" | |||
| class btOverlappingPairCache; | |||
| struct btBroadphaseAabbCallback | |||
| { | |||
| virtual ~btBroadphaseAabbCallback() {} | |||
| virtual bool process(const btBroadphaseProxy* proxy) = 0; | |||
| }; | |||
| struct btBroadphaseRayCallback : public btBroadphaseAabbCallback | |||
| { | |||
| ///added some cached data to accelerate ray-AABB tests | |||
| btVector3 m_rayDirectionInverse; | |||
| unsigned int m_signs[3]; | |||
| btScalar m_lambda_max; | |||
| virtual ~btBroadphaseRayCallback() {} | |||
| }; | |||
| #include "LinearMath/btVector3.h" | |||
| ///The btBroadphaseInterface class provides an interface to detect aabb-overlapping object pairs. | |||
| ///Some implementations for this broadphase interface include btAxisSweep3, bt32BitAxisSweep3 and btDbvtBroadphase. | |||
| ///The actual overlapping pair management, storage, adding and removing of pairs is dealt by the btOverlappingPairCache class. | |||
| class btBroadphaseInterface | |||
| { | |||
| public: | |||
| virtual ~btBroadphaseInterface() {} | |||
| virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy) =0; | |||
| virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher)=0; | |||
| virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher)=0; | |||
| virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const =0; | |||
| virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0), const btVector3& aabbMax = btVector3(0,0,0)) = 0; | |||
| virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) = 0; | |||
| ///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb | |||
| virtual void calculateOverlappingPairs(btDispatcher* dispatcher)=0; | |||
| virtual btOverlappingPairCache* getOverlappingPairCache()=0; | |||
| virtual const btOverlappingPairCache* getOverlappingPairCache() const =0; | |||
| ///getAabb returns the axis aligned bounding box in the 'global' coordinate frame | |||
| ///will add some transform later | |||
| virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const =0; | |||
| ///reset broadphase internal structures, to ensure determinism/reproducability | |||
| virtual void resetPool(btDispatcher* dispatcher) { (void) dispatcher; }; | |||
| virtual void printStats() = 0; | |||
| }; | |||
| #endif //BT_BROADPHASE_INTERFACE_H | |||
| @@ -0,0 +1,17 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btBroadphaseProxy.h" | |||
| @@ -0,0 +1,270 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_BROADPHASE_PROXY_H | |||
| #define BT_BROADPHASE_PROXY_H | |||
| #include "LinearMath/btScalar.h" //for SIMD_FORCE_INLINE | |||
| #include "LinearMath/btVector3.h" | |||
| #include "LinearMath/btAlignedAllocator.h" | |||
| /// btDispatcher uses these types | |||
| /// IMPORTANT NOTE:The types are ordered polyhedral, implicit convex and concave | |||
| /// to facilitate type checking | |||
| /// CUSTOM_POLYHEDRAL_SHAPE_TYPE,CUSTOM_CONVEX_SHAPE_TYPE and CUSTOM_CONCAVE_SHAPE_TYPE can be used to extend Bullet without modifying source code | |||
| enum BroadphaseNativeTypes | |||
| { | |||
| // polyhedral convex shapes | |||
| BOX_SHAPE_PROXYTYPE, | |||
| TRIANGLE_SHAPE_PROXYTYPE, | |||
| TETRAHEDRAL_SHAPE_PROXYTYPE, | |||
| CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE, | |||
| CONVEX_HULL_SHAPE_PROXYTYPE, | |||
| CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE, | |||
| CUSTOM_POLYHEDRAL_SHAPE_TYPE, | |||
| //implicit convex shapes | |||
| IMPLICIT_CONVEX_SHAPES_START_HERE, | |||
| SPHERE_SHAPE_PROXYTYPE, | |||
| MULTI_SPHERE_SHAPE_PROXYTYPE, | |||
| CAPSULE_SHAPE_PROXYTYPE, | |||
| CONE_SHAPE_PROXYTYPE, | |||
| CONVEX_SHAPE_PROXYTYPE, | |||
| CYLINDER_SHAPE_PROXYTYPE, | |||
| UNIFORM_SCALING_SHAPE_PROXYTYPE, | |||
| MINKOWSKI_SUM_SHAPE_PROXYTYPE, | |||
| MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE, | |||
| BOX_2D_SHAPE_PROXYTYPE, | |||
| CONVEX_2D_SHAPE_PROXYTYPE, | |||
| CUSTOM_CONVEX_SHAPE_TYPE, | |||
| //concave shapes | |||
| CONCAVE_SHAPES_START_HERE, | |||
| //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy! | |||
| TRIANGLE_MESH_SHAPE_PROXYTYPE, | |||
| SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE, | |||
| ///used for demo integration FAST/Swift collision library and Bullet | |||
| FAST_CONCAVE_MESH_PROXYTYPE, | |||
| //terrain | |||
| TERRAIN_SHAPE_PROXYTYPE, | |||
| ///Used for GIMPACT Trimesh integration | |||
| GIMPACT_SHAPE_PROXYTYPE, | |||
| ///Multimaterial mesh | |||
| MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE, | |||
| EMPTY_SHAPE_PROXYTYPE, | |||
| STATIC_PLANE_PROXYTYPE, | |||
| CUSTOM_CONCAVE_SHAPE_TYPE, | |||
| CONCAVE_SHAPES_END_HERE, | |||
| COMPOUND_SHAPE_PROXYTYPE, | |||
| SOFTBODY_SHAPE_PROXYTYPE, | |||
| HFFLUID_SHAPE_PROXYTYPE, | |||
| HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE, | |||
| INVALID_SHAPE_PROXYTYPE, | |||
| MAX_BROADPHASE_COLLISION_TYPES | |||
| }; | |||
| ///The btBroadphaseProxy is the main class that can be used with the Bullet broadphases. | |||
| ///It stores collision shape type information, collision filter information and a client object, typically a btCollisionObject or btRigidBody. | |||
| ATTRIBUTE_ALIGNED16(struct) btBroadphaseProxy | |||
| { | |||
| BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
| ///optional filtering to cull potential collisions | |||
| enum CollisionFilterGroups | |||
| { | |||
| DefaultFilter = 1, | |||
| StaticFilter = 2, | |||
| KinematicFilter = 4, | |||
| DebrisFilter = 8, | |||
| SensorTrigger = 16, | |||
| CharacterFilter = 32, | |||
| AllFilter = -1 //all bits sets: DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger | |||
| }; | |||
| //Usually the client btCollisionObject or Rigidbody class | |||
| void* m_clientObject; | |||
| short int m_collisionFilterGroup; | |||
| short int m_collisionFilterMask; | |||
| void* m_multiSapParentProxy; | |||
| int m_uniqueId;//m_uniqueId is introduced for paircache. could get rid of this, by calculating the address offset etc. | |||
| btVector3 m_aabbMin; | |||
| btVector3 m_aabbMax; | |||
| SIMD_FORCE_INLINE int getUid() const | |||
| { | |||
| return m_uniqueId; | |||
| } | |||
| //used for memory pools | |||
| btBroadphaseProxy() :m_clientObject(0),m_multiSapParentProxy(0) | |||
| { | |||
| } | |||
| btBroadphaseProxy(const btVector3& aabbMin,const btVector3& aabbMax,void* userPtr,short int collisionFilterGroup, short int collisionFilterMask,void* multiSapParentProxy=0) | |||
| :m_clientObject(userPtr), | |||
| m_collisionFilterGroup(collisionFilterGroup), | |||
| m_collisionFilterMask(collisionFilterMask), | |||
| m_aabbMin(aabbMin), | |||
| m_aabbMax(aabbMax) | |||
| { | |||
| m_multiSapParentProxy = multiSapParentProxy; | |||
| } | |||
| static SIMD_FORCE_INLINE bool isPolyhedral(int proxyType) | |||
| { | |||
| return (proxyType < IMPLICIT_CONVEX_SHAPES_START_HERE); | |||
| } | |||
| static SIMD_FORCE_INLINE bool isConvex(int proxyType) | |||
| { | |||
| return (proxyType < CONCAVE_SHAPES_START_HERE); | |||
| } | |||
| static SIMD_FORCE_INLINE bool isNonMoving(int proxyType) | |||
| { | |||
| return (isConcave(proxyType) && !(proxyType==GIMPACT_SHAPE_PROXYTYPE)); | |||
| } | |||
| static SIMD_FORCE_INLINE bool isConcave(int proxyType) | |||
| { | |||
| return ((proxyType > CONCAVE_SHAPES_START_HERE) && | |||
| (proxyType < CONCAVE_SHAPES_END_HERE)); | |||
| } | |||
| static SIMD_FORCE_INLINE bool isCompound(int proxyType) | |||
| { | |||
| return (proxyType == COMPOUND_SHAPE_PROXYTYPE); | |||
| } | |||
| static SIMD_FORCE_INLINE bool isSoftBody(int proxyType) | |||
| { | |||
| return (proxyType == SOFTBODY_SHAPE_PROXYTYPE); | |||
| } | |||
| static SIMD_FORCE_INLINE bool isInfinite(int proxyType) | |||
| { | |||
| return (proxyType == STATIC_PLANE_PROXYTYPE); | |||
| } | |||
| static SIMD_FORCE_INLINE bool isConvex2d(int proxyType) | |||
| { | |||
| return (proxyType == BOX_2D_SHAPE_PROXYTYPE) || (proxyType == CONVEX_2D_SHAPE_PROXYTYPE); | |||
| } | |||
| } | |||
| ; | |||
| class btCollisionAlgorithm; | |||
| struct btBroadphaseProxy; | |||
| ///The btBroadphasePair class contains a pair of aabb-overlapping objects. | |||
| ///A btDispatcher can search a btCollisionAlgorithm that performs exact/narrowphase collision detection on the actual collision shapes. | |||
| ATTRIBUTE_ALIGNED16(struct) btBroadphasePair | |||
| { | |||
| btBroadphasePair () | |||
| : | |||
| m_pProxy0(0), | |||
| m_pProxy1(0), | |||
| m_algorithm(0), | |||
| m_internalInfo1(0) | |||
| { | |||
| } | |||
| BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
| btBroadphasePair(const btBroadphasePair& other) | |||
| : m_pProxy0(other.m_pProxy0), | |||
| m_pProxy1(other.m_pProxy1), | |||
| m_algorithm(other.m_algorithm), | |||
| m_internalInfo1(other.m_internalInfo1) | |||
| { | |||
| } | |||
| btBroadphasePair(btBroadphaseProxy& proxy0,btBroadphaseProxy& proxy1) | |||
| { | |||
| //keep them sorted, so the std::set operations work | |||
| if (proxy0.m_uniqueId < proxy1.m_uniqueId) | |||
| { | |||
| m_pProxy0 = &proxy0; | |||
| m_pProxy1 = &proxy1; | |||
| } | |||
| else | |||
| { | |||
| m_pProxy0 = &proxy1; | |||
| m_pProxy1 = &proxy0; | |||
| } | |||
| m_algorithm = 0; | |||
| m_internalInfo1 = 0; | |||
| } | |||
| btBroadphaseProxy* m_pProxy0; | |||
| btBroadphaseProxy* m_pProxy1; | |||
| mutable btCollisionAlgorithm* m_algorithm; | |||
| union { void* m_internalInfo1; int m_internalTmpValue;};//don't use this data, it will be removed in future version. | |||
| }; | |||
| /* | |||
| //comparison for set operation, see Solid DT_Encounter | |||
| SIMD_FORCE_INLINE bool operator<(const btBroadphasePair& a, const btBroadphasePair& b) | |||
| { | |||
| return a.m_pProxy0 < b.m_pProxy0 || | |||
| (a.m_pProxy0 == b.m_pProxy0 && a.m_pProxy1 < b.m_pProxy1); | |||
| } | |||
| */ | |||
| class btBroadphasePairSortPredicate | |||
| { | |||
| public: | |||
| bool operator() ( const btBroadphasePair& a, const btBroadphasePair& b ) const | |||
| { | |||
| const int uidA0 = a.m_pProxy0 ? a.m_pProxy0->m_uniqueId : -1; | |||
| const int uidB0 = b.m_pProxy0 ? b.m_pProxy0->m_uniqueId : -1; | |||
| const int uidA1 = a.m_pProxy1 ? a.m_pProxy1->m_uniqueId : -1; | |||
| const int uidB1 = b.m_pProxy1 ? b.m_pProxy1->m_uniqueId : -1; | |||
| return uidA0 > uidB0 || | |||
| (a.m_pProxy0 == b.m_pProxy0 && uidA1 > uidB1) || | |||
| (a.m_pProxy0 == b.m_pProxy0 && a.m_pProxy1 == b.m_pProxy1 && a.m_algorithm > b.m_algorithm); | |||
| } | |||
| }; | |||
| SIMD_FORCE_INLINE bool operator==(const btBroadphasePair& a, const btBroadphasePair& b) | |||
| { | |||
| return (a.m_pProxy0 == b.m_pProxy0) && (a.m_pProxy1 == b.m_pProxy1); | |||
| } | |||
| #endif //BT_BROADPHASE_PROXY_H | |||
| @@ -0,0 +1,23 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btCollisionAlgorithm.h" | |||
| #include "btDispatcher.h" | |||
| btCollisionAlgorithm::btCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) | |||
| { | |||
| m_dispatcher = ci.m_dispatcher1; | |||
| } | |||
| @@ -0,0 +1,80 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_COLLISION_ALGORITHM_H | |||
| #define BT_COLLISION_ALGORITHM_H | |||
| #include "LinearMath/btScalar.h" | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| struct btBroadphaseProxy; | |||
| class btDispatcher; | |||
| class btManifoldResult; | |||
| class btCollisionObject; | |||
| struct btDispatcherInfo; | |||
| class btPersistentManifold; | |||
| typedef btAlignedObjectArray<btPersistentManifold*> btManifoldArray; | |||
| struct btCollisionAlgorithmConstructionInfo | |||
| { | |||
| btCollisionAlgorithmConstructionInfo() | |||
| :m_dispatcher1(0), | |||
| m_manifold(0) | |||
| { | |||
| } | |||
| btCollisionAlgorithmConstructionInfo(btDispatcher* dispatcher,int temp) | |||
| :m_dispatcher1(dispatcher) | |||
| { | |||
| (void)temp; | |||
| } | |||
| btDispatcher* m_dispatcher1; | |||
| btPersistentManifold* m_manifold; | |||
| // int getDispatcherId(); | |||
| }; | |||
| ///btCollisionAlgorithm is an collision interface that is compatible with the Broadphase and btDispatcher. | |||
| ///It is persistent over frames | |||
| class btCollisionAlgorithm | |||
| { | |||
| protected: | |||
| btDispatcher* m_dispatcher; | |||
| protected: | |||
| // int getDispatcherId(); | |||
| public: | |||
| btCollisionAlgorithm() {}; | |||
| btCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci); | |||
| virtual ~btCollisionAlgorithm() {}; | |||
| virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) = 0; | |||
| virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) = 0; | |||
| virtual void getAllContactManifolds(btManifoldArray& manifoldArray) = 0; | |||
| }; | |||
| #endif //BT_COLLISION_ALGORITHM_H | |||
| @@ -0,0 +1,796 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| ///btDbvtBroadphase implementation by Nathanael Presson | |||
| #include "btDbvtBroadphase.h" | |||
| // | |||
| // Profiling | |||
| // | |||
| #if DBVT_BP_PROFILE||DBVT_BP_ENABLE_BENCHMARK | |||
| #include <stdio.h> | |||
| #endif | |||
| #if DBVT_BP_PROFILE | |||
| struct ProfileScope | |||
| { | |||
| __forceinline ProfileScope(btClock& clock,unsigned long& value) : | |||
| m_clock(&clock),m_value(&value),m_base(clock.getTimeMicroseconds()) | |||
| { | |||
| } | |||
| __forceinline ~ProfileScope() | |||
| { | |||
| (*m_value)+=m_clock->getTimeMicroseconds()-m_base; | |||
| } | |||
| btClock* m_clock; | |||
| unsigned long* m_value; | |||
| unsigned long m_base; | |||
| }; | |||
| #define SPC(_value_) ProfileScope spc_scope(m_clock,_value_) | |||
| #else | |||
| #define SPC(_value_) | |||
| #endif | |||
| // | |||
| // Helpers | |||
| // | |||
| // | |||
| template <typename T> | |||
| static inline void listappend(T* item,T*& list) | |||
| { | |||
| item->links[0]=0; | |||
| item->links[1]=list; | |||
| if(list) list->links[0]=item; | |||
| list=item; | |||
| } | |||
| // | |||
| template <typename T> | |||
| static inline void listremove(T* item,T*& list) | |||
| { | |||
| if(item->links[0]) item->links[0]->links[1]=item->links[1]; else list=item->links[1]; | |||
| if(item->links[1]) item->links[1]->links[0]=item->links[0]; | |||
| } | |||
| // | |||
| template <typename T> | |||
| static inline int listcount(T* root) | |||
| { | |||
| int n=0; | |||
| while(root) { ++n;root=root->links[1]; } | |||
| return(n); | |||
| } | |||
| // | |||
| template <typename T> | |||
| static inline void clear(T& value) | |||
| { | |||
| static const struct ZeroDummy : T {} zerodummy; | |||
| value=zerodummy; | |||
| } | |||
| // | |||
| // Colliders | |||
| // | |||
| /* Tree collider */ | |||
| struct btDbvtTreeCollider : btDbvt::ICollide | |||
| { | |||
| btDbvtBroadphase* pbp; | |||
| btDbvtProxy* proxy; | |||
| btDbvtTreeCollider(btDbvtBroadphase* p) : pbp(p) {} | |||
| void Process(const btDbvtNode* na,const btDbvtNode* nb) | |||
| { | |||
| if(na!=nb) | |||
| { | |||
| btDbvtProxy* pa=(btDbvtProxy*)na->data; | |||
| btDbvtProxy* pb=(btDbvtProxy*)nb->data; | |||
| #if DBVT_BP_SORTPAIRS | |||
| if(pa->m_uniqueId>pb->m_uniqueId) | |||
| btSwap(pa,pb); | |||
| #endif | |||
| pbp->m_paircache->addOverlappingPair(pa,pb); | |||
| ++pbp->m_newpairs; | |||
| } | |||
| } | |||
| void Process(const btDbvtNode* n) | |||
| { | |||
| Process(n,proxy->leaf); | |||
| } | |||
| }; | |||
| // | |||
| // btDbvtBroadphase | |||
| // | |||
| // | |||
| btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache* paircache) | |||
| { | |||
| m_deferedcollide = false; | |||
| m_needcleanup = true; | |||
| m_releasepaircache = (paircache!=0)?false:true; | |||
| m_prediction = 0; | |||
| m_stageCurrent = 0; | |||
| m_fixedleft = 0; | |||
| m_fupdates = 1; | |||
| m_dupdates = 0; | |||
| m_cupdates = 10; | |||
| m_newpairs = 1; | |||
| m_updates_call = 0; | |||
| m_updates_done = 0; | |||
| m_updates_ratio = 0; | |||
| m_paircache = paircache? paircache : new(btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache(); | |||
| m_gid = 0; | |||
| m_pid = 0; | |||
| m_cid = 0; | |||
| for(int i=0;i<=STAGECOUNT;++i) | |||
| { | |||
| m_stageRoots[i]=0; | |||
| } | |||
| #if DBVT_BP_PROFILE | |||
| clear(m_profiling); | |||
| #endif | |||
| } | |||
| // | |||
| btDbvtBroadphase::~btDbvtBroadphase() | |||
| { | |||
| if(m_releasepaircache) | |||
| { | |||
| m_paircache->~btOverlappingPairCache(); | |||
| btAlignedFree(m_paircache); | |||
| } | |||
| } | |||
| // | |||
| btBroadphaseProxy* btDbvtBroadphase::createProxy( const btVector3& aabbMin, | |||
| const btVector3& aabbMax, | |||
| int /*shapeType*/, | |||
| void* userPtr, | |||
| short int collisionFilterGroup, | |||
| short int collisionFilterMask, | |||
| btDispatcher* /*dispatcher*/, | |||
| void* /*multiSapProxy*/) | |||
| { | |||
| btDbvtProxy* proxy=new(btAlignedAlloc(sizeof(btDbvtProxy),16)) btDbvtProxy( aabbMin,aabbMax,userPtr, | |||
| collisionFilterGroup, | |||
| collisionFilterMask); | |||
| btDbvtAabbMm aabb = btDbvtVolume::FromMM(aabbMin,aabbMax); | |||
| //bproxy->aabb = btDbvtVolume::FromMM(aabbMin,aabbMax); | |||
| proxy->stage = m_stageCurrent; | |||
| proxy->m_uniqueId = ++m_gid; | |||
| proxy->leaf = m_sets[0].insert(aabb,proxy); | |||
| listappend(proxy,m_stageRoots[m_stageCurrent]); | |||
| if(!m_deferedcollide) | |||
| { | |||
| btDbvtTreeCollider collider(this); | |||
| collider.proxy=proxy; | |||
| m_sets[0].collideTV(m_sets[0].m_root,aabb,collider); | |||
| m_sets[1].collideTV(m_sets[1].m_root,aabb,collider); | |||
| } | |||
| return(proxy); | |||
| } | |||
| // | |||
| void btDbvtBroadphase::destroyProxy( btBroadphaseProxy* absproxy, | |||
| btDispatcher* dispatcher) | |||
| { | |||
| btDbvtProxy* proxy=(btDbvtProxy*)absproxy; | |||
| if(proxy->stage==STAGECOUNT) | |||
| m_sets[1].remove(proxy->leaf); | |||
| else | |||
| m_sets[0].remove(proxy->leaf); | |||
| listremove(proxy,m_stageRoots[proxy->stage]); | |||
| m_paircache->removeOverlappingPairsContainingProxy(proxy,dispatcher); | |||
| btAlignedFree(proxy); | |||
| m_needcleanup=true; | |||
| } | |||
| void btDbvtBroadphase::getAabb(btBroadphaseProxy* absproxy,btVector3& aabbMin, btVector3& aabbMax ) const | |||
| { | |||
| btDbvtProxy* proxy=(btDbvtProxy*)absproxy; | |||
| aabbMin = proxy->m_aabbMin; | |||
| aabbMax = proxy->m_aabbMax; | |||
| } | |||
| struct BroadphaseRayTester : btDbvt::ICollide | |||
| { | |||
| btBroadphaseRayCallback& m_rayCallback; | |||
| BroadphaseRayTester(btBroadphaseRayCallback& orgCallback) | |||
| :m_rayCallback(orgCallback) | |||
| { | |||
| } | |||
| void Process(const btDbvtNode* leaf) | |||
| { | |||
| btDbvtProxy* proxy=(btDbvtProxy*)leaf->data; | |||
| m_rayCallback.process(proxy); | |||
| } | |||
| }; | |||
| void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin,const btVector3& aabbMax) | |||
| { | |||
| BroadphaseRayTester callback(rayCallback); | |||
| m_sets[0].rayTestInternal( m_sets[0].m_root, | |||
| rayFrom, | |||
| rayTo, | |||
| rayCallback.m_rayDirectionInverse, | |||
| rayCallback.m_signs, | |||
| rayCallback.m_lambda_max, | |||
| aabbMin, | |||
| aabbMax, | |||
| callback); | |||
| m_sets[1].rayTestInternal( m_sets[1].m_root, | |||
| rayFrom, | |||
| rayTo, | |||
| rayCallback.m_rayDirectionInverse, | |||
| rayCallback.m_signs, | |||
| rayCallback.m_lambda_max, | |||
| aabbMin, | |||
| aabbMax, | |||
| callback); | |||
| } | |||
| struct BroadphaseAabbTester : btDbvt::ICollide | |||
| { | |||
| btBroadphaseAabbCallback& m_aabbCallback; | |||
| BroadphaseAabbTester(btBroadphaseAabbCallback& orgCallback) | |||
| :m_aabbCallback(orgCallback) | |||
| { | |||
| } | |||
| void Process(const btDbvtNode* leaf) | |||
| { | |||
| btDbvtProxy* proxy=(btDbvtProxy*)leaf->data; | |||
| m_aabbCallback.process(proxy); | |||
| } | |||
| }; | |||
| void btDbvtBroadphase::aabbTest(const btVector3& aabbMin,const btVector3& aabbMax,btBroadphaseAabbCallback& aabbCallback) | |||
| { | |||
| BroadphaseAabbTester callback(aabbCallback); | |||
| const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(aabbMin,aabbMax); | |||
| //process all children, that overlap with the given AABB bounds | |||
| m_sets[0].collideTV(m_sets[0].m_root,bounds,callback); | |||
| m_sets[1].collideTV(m_sets[1].m_root,bounds,callback); | |||
| } | |||
| // | |||
| void btDbvtBroadphase::setAabb( btBroadphaseProxy* absproxy, | |||
| const btVector3& aabbMin, | |||
| const btVector3& aabbMax, | |||
| btDispatcher* /*dispatcher*/) | |||
| { | |||
| btDbvtProxy* proxy=(btDbvtProxy*)absproxy; | |||
| ATTRIBUTE_ALIGNED16(btDbvtVolume) aabb=btDbvtVolume::FromMM(aabbMin,aabbMax); | |||
| #if DBVT_BP_PREVENTFALSEUPDATE | |||
| if(NotEqual(aabb,proxy->leaf->volume)) | |||
| #endif | |||
| { | |||
| bool docollide=false; | |||
| if(proxy->stage==STAGECOUNT) | |||
| {/* fixed -> dynamic set */ | |||
| m_sets[1].remove(proxy->leaf); | |||
| proxy->leaf=m_sets[0].insert(aabb,proxy); | |||
| docollide=true; | |||
| } | |||
| else | |||
| {/* dynamic set */ | |||
| ++m_updates_call; | |||
| if(Intersect(proxy->leaf->volume,aabb)) | |||
| {/* Moving */ | |||
| const btVector3 delta=aabbMin-proxy->m_aabbMin; | |||
| btVector3 velocity(((proxy->m_aabbMax-proxy->m_aabbMin)/2)*m_prediction); | |||
| if(delta[0]<0) velocity[0]=-velocity[0]; | |||
| if(delta[1]<0) velocity[1]=-velocity[1]; | |||
| if(delta[2]<0) velocity[2]=-velocity[2]; | |||
| if ( | |||
| #ifdef DBVT_BP_MARGIN | |||
| m_sets[0].update(proxy->leaf,aabb,velocity,DBVT_BP_MARGIN) | |||
| #else | |||
| m_sets[0].update(proxy->leaf,aabb,velocity) | |||
| #endif | |||
| ) | |||
| { | |||
| ++m_updates_done; | |||
| docollide=true; | |||
| } | |||
| } | |||
| else | |||
| {/* Teleporting */ | |||
| m_sets[0].update(proxy->leaf,aabb); | |||
| ++m_updates_done; | |||
| docollide=true; | |||
| } | |||
| } | |||
| listremove(proxy,m_stageRoots[proxy->stage]); | |||
| proxy->m_aabbMin = aabbMin; | |||
| proxy->m_aabbMax = aabbMax; | |||
| proxy->stage = m_stageCurrent; | |||
| listappend(proxy,m_stageRoots[m_stageCurrent]); | |||
| if(docollide) | |||
| { | |||
| m_needcleanup=true; | |||
| if(!m_deferedcollide) | |||
| { | |||
| btDbvtTreeCollider collider(this); | |||
| m_sets[1].collideTTpersistentStack(m_sets[1].m_root,proxy->leaf,collider); | |||
| m_sets[0].collideTTpersistentStack(m_sets[0].m_root,proxy->leaf,collider); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // | |||
| void btDbvtBroadphase::setAabbForceUpdate( btBroadphaseProxy* absproxy, | |||
| const btVector3& aabbMin, | |||
| const btVector3& aabbMax, | |||
| btDispatcher* /*dispatcher*/) | |||
| { | |||
| btDbvtProxy* proxy=(btDbvtProxy*)absproxy; | |||
| ATTRIBUTE_ALIGNED16(btDbvtVolume) aabb=btDbvtVolume::FromMM(aabbMin,aabbMax); | |||
| bool docollide=false; | |||
| if(proxy->stage==STAGECOUNT) | |||
| {/* fixed -> dynamic set */ | |||
| m_sets[1].remove(proxy->leaf); | |||
| proxy->leaf=m_sets[0].insert(aabb,proxy); | |||
| docollide=true; | |||
| } | |||
| else | |||
| {/* dynamic set */ | |||
| ++m_updates_call; | |||
| /* Teleporting */ | |||
| m_sets[0].update(proxy->leaf,aabb); | |||
| ++m_updates_done; | |||
| docollide=true; | |||
| } | |||
| listremove(proxy,m_stageRoots[proxy->stage]); | |||
| proxy->m_aabbMin = aabbMin; | |||
| proxy->m_aabbMax = aabbMax; | |||
| proxy->stage = m_stageCurrent; | |||
| listappend(proxy,m_stageRoots[m_stageCurrent]); | |||
| if(docollide) | |||
| { | |||
| m_needcleanup=true; | |||
| if(!m_deferedcollide) | |||
| { | |||
| btDbvtTreeCollider collider(this); | |||
| m_sets[1].collideTTpersistentStack(m_sets[1].m_root,proxy->leaf,collider); | |||
| m_sets[0].collideTTpersistentStack(m_sets[0].m_root,proxy->leaf,collider); | |||
| } | |||
| } | |||
| } | |||
| // | |||
| void btDbvtBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) | |||
| { | |||
| collide(dispatcher); | |||
| #if DBVT_BP_PROFILE | |||
| if(0==(m_pid%DBVT_BP_PROFILING_RATE)) | |||
| { | |||
| printf("fixed(%u) dynamics(%u) pairs(%u)\r\n",m_sets[1].m_leaves,m_sets[0].m_leaves,m_paircache->getNumOverlappingPairs()); | |||
| unsigned int total=m_profiling.m_total; | |||
| if(total<=0) total=1; | |||
| printf("ddcollide: %u%% (%uus)\r\n",(50+m_profiling.m_ddcollide*100)/total,m_profiling.m_ddcollide/DBVT_BP_PROFILING_RATE); | |||
| printf("fdcollide: %u%% (%uus)\r\n",(50+m_profiling.m_fdcollide*100)/total,m_profiling.m_fdcollide/DBVT_BP_PROFILING_RATE); | |||
| printf("cleanup: %u%% (%uus)\r\n",(50+m_profiling.m_cleanup*100)/total,m_profiling.m_cleanup/DBVT_BP_PROFILING_RATE); | |||
| printf("total: %uus\r\n",total/DBVT_BP_PROFILING_RATE); | |||
| const unsigned long sum=m_profiling.m_ddcollide+ | |||
| m_profiling.m_fdcollide+ | |||
| m_profiling.m_cleanup; | |||
| printf("leaked: %u%% (%uus)\r\n",100-((50+sum*100)/total),(total-sum)/DBVT_BP_PROFILING_RATE); | |||
| printf("job counts: %u%%\r\n",(m_profiling.m_jobcount*100)/((m_sets[0].m_leaves+m_sets[1].m_leaves)*DBVT_BP_PROFILING_RATE)); | |||
| clear(m_profiling); | |||
| m_clock.reset(); | |||
| } | |||
| #endif | |||
| performDeferredRemoval(dispatcher); | |||
| } | |||
| void btDbvtBroadphase::performDeferredRemoval(btDispatcher* dispatcher) | |||
| { | |||
| if (m_paircache->hasDeferredRemoval()) | |||
| { | |||
| btBroadphasePairArray& overlappingPairArray = m_paircache->getOverlappingPairArray(); | |||
| //perform a sort, to find duplicates and to sort 'invalid' pairs to the end | |||
| overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); | |||
| int invalidPair = 0; | |||
| int i; | |||
| btBroadphasePair previousPair; | |||
| previousPair.m_pProxy0 = 0; | |||
| previousPair.m_pProxy1 = 0; | |||
| previousPair.m_algorithm = 0; | |||
| for (i=0;i<overlappingPairArray.size();i++) | |||
| { | |||
| btBroadphasePair& pair = overlappingPairArray[i]; | |||
| bool isDuplicate = (pair == previousPair); | |||
| previousPair = pair; | |||
| bool needsRemoval = false; | |||
| if (!isDuplicate) | |||
| { | |||
| //important to perform AABB check that is consistent with the broadphase | |||
| btDbvtProxy* pa=(btDbvtProxy*)pair.m_pProxy0; | |||
| btDbvtProxy* pb=(btDbvtProxy*)pair.m_pProxy1; | |||
| bool hasOverlap = Intersect(pa->leaf->volume,pb->leaf->volume); | |||
| if (hasOverlap) | |||
| { | |||
| needsRemoval = false; | |||
| } else | |||
| { | |||
| needsRemoval = true; | |||
| } | |||
| } else | |||
| { | |||
| //remove duplicate | |||
| needsRemoval = true; | |||
| //should have no algorithm | |||
| btAssert(!pair.m_algorithm); | |||
| } | |||
| if (needsRemoval) | |||
| { | |||
| m_paircache->cleanOverlappingPair(pair,dispatcher); | |||
| pair.m_pProxy0 = 0; | |||
| pair.m_pProxy1 = 0; | |||
| invalidPair++; | |||
| } | |||
| } | |||
| //perform a sort, to sort 'invalid' pairs to the end | |||
| overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); | |||
| overlappingPairArray.resize(overlappingPairArray.size() - invalidPair); | |||
| } | |||
| } | |||
| // | |||
| void btDbvtBroadphase::collide(btDispatcher* dispatcher) | |||
| { | |||
| /*printf("---------------------------------------------------------\n"); | |||
| printf("m_sets[0].m_leaves=%d\n",m_sets[0].m_leaves); | |||
| printf("m_sets[1].m_leaves=%d\n",m_sets[1].m_leaves); | |||
| printf("numPairs = %d\n",getOverlappingPairCache()->getNumOverlappingPairs()); | |||
| { | |||
| int i; | |||
| for (i=0;i<getOverlappingPairCache()->getNumOverlappingPairs();i++) | |||
| { | |||
| printf("pair[%d]=(%d,%d),",i,getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy0->getUid(), | |||
| getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy1->getUid()); | |||
| } | |||
| printf("\n"); | |||
| } | |||
| */ | |||
| SPC(m_profiling.m_total); | |||
| /* optimize */ | |||
| m_sets[0].optimizeIncremental(1+(m_sets[0].m_leaves*m_dupdates)/100); | |||
| if(m_fixedleft) | |||
| { | |||
| const int count=1+(m_sets[1].m_leaves*m_fupdates)/100; | |||
| m_sets[1].optimizeIncremental(1+(m_sets[1].m_leaves*m_fupdates)/100); | |||
| m_fixedleft=btMax<int>(0,m_fixedleft-count); | |||
| } | |||
| /* dynamic -> fixed set */ | |||
| m_stageCurrent=(m_stageCurrent+1)%STAGECOUNT; | |||
| btDbvtProxy* current=m_stageRoots[m_stageCurrent]; | |||
| if(current) | |||
| { | |||
| btDbvtTreeCollider collider(this); | |||
| do { | |||
| btDbvtProxy* next=current->links[1]; | |||
| listremove(current,m_stageRoots[current->stage]); | |||
| listappend(current,m_stageRoots[STAGECOUNT]); | |||
| #if DBVT_BP_ACCURATESLEEPING | |||
| m_paircache->removeOverlappingPairsContainingProxy(current,dispatcher); | |||
| collider.proxy=current; | |||
| btDbvt::collideTV(m_sets[0].m_root,current->aabb,collider); | |||
| btDbvt::collideTV(m_sets[1].m_root,current->aabb,collider); | |||
| #endif | |||
| m_sets[0].remove(current->leaf); | |||
| ATTRIBUTE_ALIGNED16(btDbvtVolume) curAabb=btDbvtVolume::FromMM(current->m_aabbMin,current->m_aabbMax); | |||
| current->leaf = m_sets[1].insert(curAabb,current); | |||
| current->stage = STAGECOUNT; | |||
| current = next; | |||
| } while(current); | |||
| m_fixedleft=m_sets[1].m_leaves; | |||
| m_needcleanup=true; | |||
| } | |||
| /* collide dynamics */ | |||
| { | |||
| btDbvtTreeCollider collider(this); | |||
| if(m_deferedcollide) | |||
| { | |||
| SPC(m_profiling.m_fdcollide); | |||
| m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[1].m_root,collider); | |||
| } | |||
| if(m_deferedcollide) | |||
| { | |||
| SPC(m_profiling.m_ddcollide); | |||
| m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[0].m_root,collider); | |||
| } | |||
| } | |||
| /* clean up */ | |||
| if(m_needcleanup) | |||
| { | |||
| SPC(m_profiling.m_cleanup); | |||
| btBroadphasePairArray& pairs=m_paircache->getOverlappingPairArray(); | |||
| if(pairs.size()>0) | |||
| { | |||
| int ni=btMin(pairs.size(),btMax<int>(m_newpairs,(pairs.size()*m_cupdates)/100)); | |||
| for(int i=0;i<ni;++i) | |||
| { | |||
| btBroadphasePair& p=pairs[(m_cid+i)%pairs.size()]; | |||
| btDbvtProxy* pa=(btDbvtProxy*)p.m_pProxy0; | |||
| btDbvtProxy* pb=(btDbvtProxy*)p.m_pProxy1; | |||
| if(!Intersect(pa->leaf->volume,pb->leaf->volume)) | |||
| { | |||
| #if DBVT_BP_SORTPAIRS | |||
| if(pa->m_uniqueId>pb->m_uniqueId) | |||
| btSwap(pa,pb); | |||
| #endif | |||
| m_paircache->removeOverlappingPair(pa,pb,dispatcher); | |||
| --ni;--i; | |||
| } | |||
| } | |||
| if(pairs.size()>0) m_cid=(m_cid+ni)%pairs.size(); else m_cid=0; | |||
| } | |||
| } | |||
| ++m_pid; | |||
| m_newpairs=1; | |||
| m_needcleanup=false; | |||
| if(m_updates_call>0) | |||
| { m_updates_ratio=m_updates_done/(btScalar)m_updates_call; } | |||
| else | |||
| { m_updates_ratio=0; } | |||
| m_updates_done/=2; | |||
| m_updates_call/=2; | |||
| } | |||
| // | |||
| void btDbvtBroadphase::optimize() | |||
| { | |||
| m_sets[0].optimizeTopDown(); | |||
| m_sets[1].optimizeTopDown(); | |||
| } | |||
| // | |||
| btOverlappingPairCache* btDbvtBroadphase::getOverlappingPairCache() | |||
| { | |||
| return(m_paircache); | |||
| } | |||
| // | |||
| const btOverlappingPairCache* btDbvtBroadphase::getOverlappingPairCache() const | |||
| { | |||
| return(m_paircache); | |||
| } | |||
| // | |||
| void btDbvtBroadphase::getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const | |||
| { | |||
| ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds; | |||
| if(!m_sets[0].empty()) | |||
| if(!m_sets[1].empty()) Merge( m_sets[0].m_root->volume, | |||
| m_sets[1].m_root->volume,bounds); | |||
| else | |||
| bounds=m_sets[0].m_root->volume; | |||
| else if(!m_sets[1].empty()) bounds=m_sets[1].m_root->volume; | |||
| else | |||
| bounds=btDbvtVolume::FromCR(btVector3(0,0,0),0); | |||
| aabbMin=bounds.Mins(); | |||
| aabbMax=bounds.Maxs(); | |||
| } | |||
| void btDbvtBroadphase::resetPool(btDispatcher* dispatcher) | |||
| { | |||
| int totalObjects = m_sets[0].m_leaves + m_sets[1].m_leaves; | |||
| if (!totalObjects) | |||
| { | |||
| //reset internal dynamic tree data structures | |||
| m_sets[0].clear(); | |||
| m_sets[1].clear(); | |||
| m_deferedcollide = false; | |||
| m_needcleanup = true; | |||
| m_stageCurrent = 0; | |||
| m_fixedleft = 0; | |||
| m_fupdates = 1; | |||
| m_dupdates = 0; | |||
| m_cupdates = 10; | |||
| m_newpairs = 1; | |||
| m_updates_call = 0; | |||
| m_updates_done = 0; | |||
| m_updates_ratio = 0; | |||
| m_gid = 0; | |||
| m_pid = 0; | |||
| m_cid = 0; | |||
| for(int i=0;i<=STAGECOUNT;++i) | |||
| { | |||
| m_stageRoots[i]=0; | |||
| } | |||
| } | |||
| } | |||
| // | |||
| void btDbvtBroadphase::printStats() | |||
| {} | |||
| // | |||
| #if DBVT_BP_ENABLE_BENCHMARK | |||
| struct btBroadphaseBenchmark | |||
| { | |||
| struct Experiment | |||
| { | |||
| const char* name; | |||
| int object_count; | |||
| int update_count; | |||
| int spawn_count; | |||
| int iterations; | |||
| btScalar speed; | |||
| btScalar amplitude; | |||
| }; | |||
| struct Object | |||
| { | |||
| btVector3 center; | |||
| btVector3 extents; | |||
| btBroadphaseProxy* proxy; | |||
| btScalar time; | |||
| void update(btScalar speed,btScalar amplitude,btBroadphaseInterface* pbi) | |||
| { | |||
| time += speed; | |||
| center[0] = btCos(time*(btScalar)2.17)*amplitude+ | |||
| btSin(time)*amplitude/2; | |||
| center[1] = btCos(time*(btScalar)1.38)*amplitude+ | |||
| btSin(time)*amplitude; | |||
| center[2] = btSin(time*(btScalar)0.777)*amplitude; | |||
| pbi->setAabb(proxy,center-extents,center+extents,0); | |||
| } | |||
| }; | |||
| static int UnsignedRand(int range=RAND_MAX-1) { return(rand()%(range+1)); } | |||
| static btScalar UnitRand() { return(UnsignedRand(16384)/(btScalar)16384); } | |||
| static void OutputTime(const char* name,btClock& c,unsigned count=0) | |||
| { | |||
| const unsigned long us=c.getTimeMicroseconds(); | |||
| const unsigned long ms=(us+500)/1000; | |||
| const btScalar sec=us/(btScalar)(1000*1000); | |||
| if(count>0) | |||
| printf("%s : %u us (%u ms), %.2f/s\r\n",name,us,ms,count/sec); | |||
| else | |||
| printf("%s : %u us (%u ms)\r\n",name,us,ms); | |||
| } | |||
| }; | |||
| void btDbvtBroadphase::benchmark(btBroadphaseInterface* pbi) | |||
| { | |||
| static const btBroadphaseBenchmark::Experiment experiments[]= | |||
| { | |||
| {"1024o.10%",1024,10,0,8192,(btScalar)0.005,(btScalar)100}, | |||
| /*{"4096o.10%",4096,10,0,8192,(btScalar)0.005,(btScalar)100}, | |||
| {"8192o.10%",8192,10,0,8192,(btScalar)0.005,(btScalar)100},*/ | |||
| }; | |||
| static const int nexperiments=sizeof(experiments)/sizeof(experiments[0]); | |||
| btAlignedObjectArray<btBroadphaseBenchmark::Object*> objects; | |||
| btClock wallclock; | |||
| /* Begin */ | |||
| for(int iexp=0;iexp<nexperiments;++iexp) | |||
| { | |||
| const btBroadphaseBenchmark::Experiment& experiment=experiments[iexp]; | |||
| const int object_count=experiment.object_count; | |||
| const int update_count=(object_count*experiment.update_count)/100; | |||
| const int spawn_count=(object_count*experiment.spawn_count)/100; | |||
| const btScalar speed=experiment.speed; | |||
| const btScalar amplitude=experiment.amplitude; | |||
| printf("Experiment #%u '%s':\r\n",iexp,experiment.name); | |||
| printf("\tObjects: %u\r\n",object_count); | |||
| printf("\tUpdate: %u\r\n",update_count); | |||
| printf("\tSpawn: %u\r\n",spawn_count); | |||
| printf("\tSpeed: %f\r\n",speed); | |||
| printf("\tAmplitude: %f\r\n",amplitude); | |||
| srand(180673); | |||
| /* Create objects */ | |||
| wallclock.reset(); | |||
| objects.reserve(object_count); | |||
| for(int i=0;i<object_count;++i) | |||
| { | |||
| btBroadphaseBenchmark::Object* po=new btBroadphaseBenchmark::Object(); | |||
| po->center[0]=btBroadphaseBenchmark::UnitRand()*50; | |||
| po->center[1]=btBroadphaseBenchmark::UnitRand()*50; | |||
| po->center[2]=btBroadphaseBenchmark::UnitRand()*50; | |||
| po->extents[0]=btBroadphaseBenchmark::UnitRand()*2+2; | |||
| po->extents[1]=btBroadphaseBenchmark::UnitRand()*2+2; | |||
| po->extents[2]=btBroadphaseBenchmark::UnitRand()*2+2; | |||
| po->time=btBroadphaseBenchmark::UnitRand()*2000; | |||
| po->proxy=pbi->createProxy(po->center-po->extents,po->center+po->extents,0,po,1,1,0,0); | |||
| objects.push_back(po); | |||
| } | |||
| btBroadphaseBenchmark::OutputTime("\tInitialization",wallclock); | |||
| /* First update */ | |||
| wallclock.reset(); | |||
| for(int i=0;i<objects.size();++i) | |||
| { | |||
| objects[i]->update(speed,amplitude,pbi); | |||
| } | |||
| btBroadphaseBenchmark::OutputTime("\tFirst update",wallclock); | |||
| /* Updates */ | |||
| wallclock.reset(); | |||
| for(int i=0;i<experiment.iterations;++i) | |||
| { | |||
| for(int j=0;j<update_count;++j) | |||
| { | |||
| objects[j]->update(speed,amplitude,pbi); | |||
| } | |||
| pbi->calculateOverlappingPairs(0); | |||
| } | |||
| btBroadphaseBenchmark::OutputTime("\tUpdate",wallclock,experiment.iterations); | |||
| /* Clean up */ | |||
| wallclock.reset(); | |||
| for(int i=0;i<objects.size();++i) | |||
| { | |||
| pbi->destroyProxy(objects[i]->proxy,0); | |||
| delete objects[i]; | |||
| } | |||
| objects.resize(0); | |||
| btBroadphaseBenchmark::OutputTime("\tRelease",wallclock); | |||
| } | |||
| } | |||
| #else | |||
| void btDbvtBroadphase::benchmark(btBroadphaseInterface*) | |||
| {} | |||
| #endif | |||
| #if DBVT_BP_PROFILE | |||
| #undef SPC | |||
| #endif | |||
| @@ -0,0 +1,146 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| ///btDbvtBroadphase implementation by Nathanael Presson | |||
| #ifndef BT_DBVT_BROADPHASE_H | |||
| #define BT_DBVT_BROADPHASE_H | |||
| #include "BulletCollision/BroadphaseCollision/btDbvt.h" | |||
| #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" | |||
| // | |||
| // Compile time config | |||
| // | |||
| #define DBVT_BP_PROFILE 0 | |||
| //#define DBVT_BP_SORTPAIRS 1 | |||
| #define DBVT_BP_PREVENTFALSEUPDATE 0 | |||
| #define DBVT_BP_ACCURATESLEEPING 0 | |||
| #define DBVT_BP_ENABLE_BENCHMARK 0 | |||
| #define DBVT_BP_MARGIN (btScalar)0.05 | |||
| #if DBVT_BP_PROFILE | |||
| #define DBVT_BP_PROFILING_RATE 256 | |||
| #include "LinearMath/btQuickprof.h" | |||
| #endif | |||
| // | |||
| // btDbvtProxy | |||
| // | |||
| struct btDbvtProxy : btBroadphaseProxy | |||
| { | |||
| /* Fields */ | |||
| //btDbvtAabbMm aabb; | |||
| btDbvtNode* leaf; | |||
| btDbvtProxy* links[2]; | |||
| int stage; | |||
| /* ctor */ | |||
| btDbvtProxy(const btVector3& aabbMin,const btVector3& aabbMax,void* userPtr,short int collisionFilterGroup, short int collisionFilterMask) : | |||
| btBroadphaseProxy(aabbMin,aabbMax,userPtr,collisionFilterGroup,collisionFilterMask) | |||
| { | |||
| links[0]=links[1]=0; | |||
| } | |||
| }; | |||
| typedef btAlignedObjectArray<btDbvtProxy*> btDbvtProxyArray; | |||
| ///The btDbvtBroadphase implements a broadphase using two dynamic AABB bounding volume hierarchies/trees (see btDbvt). | |||
| ///One tree is used for static/non-moving objects, and another tree is used for dynamic objects. Objects can move from one tree to the other. | |||
| ///This is a very fast broadphase, especially for very dynamic worlds where many objects are moving. Its insert/add and remove of objects is generally faster than the sweep and prune broadphases btAxisSweep3 and bt32BitAxisSweep3. | |||
| struct btDbvtBroadphase : btBroadphaseInterface | |||
| { | |||
| /* Config */ | |||
| enum { | |||
| DYNAMIC_SET = 0, /* Dynamic set index */ | |||
| FIXED_SET = 1, /* Fixed set index */ | |||
| STAGECOUNT = 2 /* Number of stages */ | |||
| }; | |||
| /* Fields */ | |||
| btDbvt m_sets[2]; // Dbvt sets | |||
| btDbvtProxy* m_stageRoots[STAGECOUNT+1]; // Stages list | |||
| btOverlappingPairCache* m_paircache; // Pair cache | |||
| btScalar m_prediction; // Velocity prediction | |||
| int m_stageCurrent; // Current stage | |||
| int m_fupdates; // % of fixed updates per frame | |||
| int m_dupdates; // % of dynamic updates per frame | |||
| int m_cupdates; // % of cleanup updates per frame | |||
| int m_newpairs; // Number of pairs created | |||
| int m_fixedleft; // Fixed optimization left | |||
| unsigned m_updates_call; // Number of updates call | |||
| unsigned m_updates_done; // Number of updates done | |||
| btScalar m_updates_ratio; // m_updates_done/m_updates_call | |||
| int m_pid; // Parse id | |||
| int m_cid; // Cleanup index | |||
| int m_gid; // Gen id | |||
| bool m_releasepaircache; // Release pair cache on delete | |||
| bool m_deferedcollide; // Defere dynamic/static collision to collide call | |||
| bool m_needcleanup; // Need to run cleanup? | |||
| #if DBVT_BP_PROFILE | |||
| btClock m_clock; | |||
| struct { | |||
| unsigned long m_total; | |||
| unsigned long m_ddcollide; | |||
| unsigned long m_fdcollide; | |||
| unsigned long m_cleanup; | |||
| unsigned long m_jobcount; | |||
| } m_profiling; | |||
| #endif | |||
| /* Methods */ | |||
| btDbvtBroadphase(btOverlappingPairCache* paircache=0); | |||
| ~btDbvtBroadphase(); | |||
| void collide(btDispatcher* dispatcher); | |||
| void optimize(); | |||
| /* btBroadphaseInterface Implementation */ | |||
| btBroadphaseProxy* createProxy(const btVector3& aabbMin,const btVector3& aabbMax,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy); | |||
| virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
| virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher); | |||
| virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0), const btVector3& aabbMax = btVector3(0,0,0)); | |||
| virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback); | |||
| virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; | |||
| virtual void calculateOverlappingPairs(btDispatcher* dispatcher); | |||
| virtual btOverlappingPairCache* getOverlappingPairCache(); | |||
| virtual const btOverlappingPairCache* getOverlappingPairCache() const; | |||
| virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const; | |||
| virtual void printStats(); | |||
| ///reset broadphase internal structures, to ensure determinism/reproducability | |||
| virtual void resetPool(btDispatcher* dispatcher); | |||
| void performDeferredRemoval(btDispatcher* dispatcher); | |||
| void setVelocityPrediction(btScalar prediction) | |||
| { | |||
| m_prediction = prediction; | |||
| } | |||
| btScalar getVelocityPrediction() const | |||
| { | |||
| return m_prediction; | |||
| } | |||
| ///this setAabbForceUpdate is similar to setAabb but always forces the aabb update. | |||
| ///it is not part of the btBroadphaseInterface but specific to btDbvtBroadphase. | |||
| ///it bypasses certain optimizations that prevent aabb updates (when the aabb shrinks), see | |||
| ///http://code.google.com/p/bullet/issues/detail?id=223 | |||
| void setAabbForceUpdate( btBroadphaseProxy* absproxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* /*dispatcher*/); | |||
| static void benchmark(btBroadphaseInterface*); | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,22 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btDispatcher.h" | |||
| btDispatcher::~btDispatcher() | |||
| { | |||
| } | |||
| @@ -0,0 +1,110 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_DISPATCHER_H | |||
| #define BT_DISPATCHER_H | |||
| #include "LinearMath/btScalar.h" | |||
| class btCollisionAlgorithm; | |||
| struct btBroadphaseProxy; | |||
| class btRigidBody; | |||
| class btCollisionObject; | |||
| class btOverlappingPairCache; | |||
| class btPersistentManifold; | |||
| class btStackAlloc; | |||
| class btPoolAllocator; | |||
| struct btDispatcherInfo | |||
| { | |||
| enum DispatchFunc | |||
| { | |||
| DISPATCH_DISCRETE = 1, | |||
| DISPATCH_CONTINUOUS | |||
| }; | |||
| btDispatcherInfo() | |||
| :m_timeStep(btScalar(0.)), | |||
| m_stepCount(0), | |||
| m_dispatchFunc(DISPATCH_DISCRETE), | |||
| m_timeOfImpact(btScalar(1.)), | |||
| m_useContinuous(true), | |||
| m_debugDraw(0), | |||
| m_enableSatConvex(false), | |||
| m_enableSPU(true), | |||
| m_useEpa(true), | |||
| m_allowedCcdPenetration(btScalar(0.04)), | |||
| m_useConvexConservativeDistanceUtil(false), | |||
| m_convexConservativeDistanceThreshold(0.0f), | |||
| m_stackAllocator(0) | |||
| { | |||
| } | |||
| btScalar m_timeStep; | |||
| int m_stepCount; | |||
| int m_dispatchFunc; | |||
| mutable btScalar m_timeOfImpact; | |||
| bool m_useContinuous; | |||
| class btIDebugDraw* m_debugDraw; | |||
| bool m_enableSatConvex; | |||
| bool m_enableSPU; | |||
| bool m_useEpa; | |||
| btScalar m_allowedCcdPenetration; | |||
| bool m_useConvexConservativeDistanceUtil; | |||
| btScalar m_convexConservativeDistanceThreshold; | |||
| btStackAlloc* m_stackAllocator; | |||
| }; | |||
| ///The btDispatcher interface class can be used in combination with broadphase to dispatch calculations for overlapping pairs. | |||
| ///For example for pairwise collision detection, calculating contact points stored in btPersistentManifold or user callbacks (game logic). | |||
| class btDispatcher | |||
| { | |||
| public: | |||
| virtual ~btDispatcher() ; | |||
| virtual btCollisionAlgorithm* findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold=0) = 0; | |||
| virtual btPersistentManifold* getNewManifold(void* body0,void* body1)=0; | |||
| virtual void releaseManifold(btPersistentManifold* manifold)=0; | |||
| virtual void clearManifold(btPersistentManifold* manifold)=0; | |||
| virtual bool needsCollision(btCollisionObject* body0,btCollisionObject* body1) = 0; | |||
| virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1)=0; | |||
| virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) =0; | |||
| virtual int getNumManifolds() const = 0; | |||
| virtual btPersistentManifold* getManifoldByIndexInternal(int index) = 0; | |||
| virtual btPersistentManifold** getInternalManifoldPointer() = 0; | |||
| virtual btPoolAllocator* getInternalManifoldPool() = 0; | |||
| virtual const btPoolAllocator* getInternalManifoldPool() const = 0; | |||
| virtual void* allocateCollisionAlgorithm(int size) = 0; | |||
| virtual void freeCollisionAlgorithm(void* ptr) = 0; | |||
| }; | |||
| #endif //BT_DISPATCHER_H | |||
| @@ -0,0 +1,489 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btMultiSapBroadphase.h" | |||
| #include "btSimpleBroadphase.h" | |||
| #include "LinearMath/btAabbUtil2.h" | |||
| #include "btQuantizedBvh.h" | |||
| /// btSapBroadphaseArray m_sapBroadphases; | |||
| /// btOverlappingPairCache* m_overlappingPairs; | |||
| extern int gOverlappingPairs; | |||
| /* | |||
| class btMultiSapSortedOverlappingPairCache : public btSortedOverlappingPairCache | |||
| { | |||
| public: | |||
| virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) | |||
| { | |||
| return btSortedOverlappingPairCache::addOverlappingPair((btBroadphaseProxy*)proxy0->m_multiSapParentProxy,(btBroadphaseProxy*)proxy1->m_multiSapParentProxy); | |||
| } | |||
| }; | |||
| */ | |||
| btMultiSapBroadphase::btMultiSapBroadphase(int /*maxProxies*/,btOverlappingPairCache* pairCache) | |||
| :m_overlappingPairs(pairCache), | |||
| m_optimizedAabbTree(0), | |||
| m_ownsPairCache(false), | |||
| m_invalidPair(0) | |||
| { | |||
| if (!m_overlappingPairs) | |||
| { | |||
| m_ownsPairCache = true; | |||
| void* mem = btAlignedAlloc(sizeof(btSortedOverlappingPairCache),16); | |||
| m_overlappingPairs = new (mem)btSortedOverlappingPairCache(); | |||
| } | |||
| struct btMultiSapOverlapFilterCallback : public btOverlapFilterCallback | |||
| { | |||
| virtual ~btMultiSapOverlapFilterCallback() | |||
| {} | |||
| // return true when pairs need collision | |||
| virtual bool needBroadphaseCollision(btBroadphaseProxy* childProxy0,btBroadphaseProxy* childProxy1) const | |||
| { | |||
| btBroadphaseProxy* multiProxy0 = (btBroadphaseProxy*)childProxy0->m_multiSapParentProxy; | |||
| btBroadphaseProxy* multiProxy1 = (btBroadphaseProxy*)childProxy1->m_multiSapParentProxy; | |||
| bool collides = (multiProxy0->m_collisionFilterGroup & multiProxy1->m_collisionFilterMask) != 0; | |||
| collides = collides && (multiProxy1->m_collisionFilterGroup & multiProxy0->m_collisionFilterMask); | |||
| return collides; | |||
| } | |||
| }; | |||
| void* mem = btAlignedAlloc(sizeof(btMultiSapOverlapFilterCallback),16); | |||
| m_filterCallback = new (mem)btMultiSapOverlapFilterCallback(); | |||
| m_overlappingPairs->setOverlapFilterCallback(m_filterCallback); | |||
| // mem = btAlignedAlloc(sizeof(btSimpleBroadphase),16); | |||
| // m_simpleBroadphase = new (mem) btSimpleBroadphase(maxProxies,m_overlappingPairs); | |||
| } | |||
| btMultiSapBroadphase::~btMultiSapBroadphase() | |||
| { | |||
| if (m_ownsPairCache) | |||
| { | |||
| m_overlappingPairs->~btOverlappingPairCache(); | |||
| btAlignedFree(m_overlappingPairs); | |||
| } | |||
| } | |||
| void btMultiSapBroadphase::buildTree(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax) | |||
| { | |||
| m_optimizedAabbTree = new btQuantizedBvh(); | |||
| m_optimizedAabbTree->setQuantizationValues(bvhAabbMin,bvhAabbMax); | |||
| QuantizedNodeArray& nodes = m_optimizedAabbTree->getLeafNodeArray(); | |||
| for (int i=0;i<m_sapBroadphases.size();i++) | |||
| { | |||
| btQuantizedBvhNode node; | |||
| btVector3 aabbMin,aabbMax; | |||
| m_sapBroadphases[i]->getBroadphaseAabb(aabbMin,aabbMax); | |||
| m_optimizedAabbTree->quantize(&node.m_quantizedAabbMin[0],aabbMin,0); | |||
| m_optimizedAabbTree->quantize(&node.m_quantizedAabbMax[0],aabbMax,1); | |||
| int partId = 0; | |||
| node.m_escapeIndexOrTriangleIndex = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | i; | |||
| nodes.push_back(node); | |||
| } | |||
| m_optimizedAabbTree->buildInternal(); | |||
| } | |||
| btBroadphaseProxy* btMultiSapBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* /*ignoreMe*/) | |||
| { | |||
| //void* ignoreMe -> we could think of recursive multi-sap, if someone is interested | |||
| void* mem = btAlignedAlloc(sizeof(btMultiSapProxy),16); | |||
| btMultiSapProxy* proxy = new (mem)btMultiSapProxy(aabbMin, aabbMax,shapeType,userPtr, collisionFilterGroup,collisionFilterMask); | |||
| m_multiSapProxies.push_back(proxy); | |||
| ///this should deal with inserting/removal into child broadphases | |||
| setAabb(proxy,aabbMin,aabbMax,dispatcher); | |||
| return proxy; | |||
| } | |||
| void btMultiSapBroadphase::destroyProxy(btBroadphaseProxy* /*proxy*/,btDispatcher* /*dispatcher*/) | |||
| { | |||
| ///not yet | |||
| btAssert(0); | |||
| } | |||
| void btMultiSapBroadphase::addToChildBroadphase(btMultiSapProxy* parentMultiSapProxy, btBroadphaseProxy* childProxy, btBroadphaseInterface* childBroadphase) | |||
| { | |||
| void* mem = btAlignedAlloc(sizeof(btBridgeProxy),16); | |||
| btBridgeProxy* bridgeProxyRef = new(mem) btBridgeProxy; | |||
| bridgeProxyRef->m_childProxy = childProxy; | |||
| bridgeProxyRef->m_childBroadphase = childBroadphase; | |||
| parentMultiSapProxy->m_bridgeProxies.push_back(bridgeProxyRef); | |||
| } | |||
| bool boxIsContainedWithinBox(const btVector3& amin,const btVector3& amax,const btVector3& bmin,const btVector3& bmax); | |||
| bool boxIsContainedWithinBox(const btVector3& amin,const btVector3& amax,const btVector3& bmin,const btVector3& bmax) | |||
| { | |||
| return | |||
| amin.getX() >= bmin.getX() && amax.getX() <= bmax.getX() && | |||
| amin.getY() >= bmin.getY() && amax.getY() <= bmax.getY() && | |||
| amin.getZ() >= bmin.getZ() && amax.getZ() <= bmax.getZ(); | |||
| } | |||
| void btMultiSapBroadphase::getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const | |||
| { | |||
| btMultiSapProxy* multiProxy = static_cast<btMultiSapProxy*>(proxy); | |||
| aabbMin = multiProxy->m_aabbMin; | |||
| aabbMax = multiProxy->m_aabbMax; | |||
| } | |||
| void btMultiSapBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin,const btVector3& aabbMax) | |||
| { | |||
| for (int i=0;i<m_multiSapProxies.size();i++) | |||
| { | |||
| rayCallback.process(m_multiSapProxies[i]); | |||
| } | |||
| } | |||
| //#include <stdio.h> | |||
| void btMultiSapBroadphase::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher) | |||
| { | |||
| btMultiSapProxy* multiProxy = static_cast<btMultiSapProxy*>(proxy); | |||
| multiProxy->m_aabbMin = aabbMin; | |||
| multiProxy->m_aabbMax = aabbMax; | |||
| // bool fullyContained = false; | |||
| // bool alreadyInSimple = false; | |||
| struct MyNodeOverlapCallback : public btNodeOverlapCallback | |||
| { | |||
| btMultiSapBroadphase* m_multiSap; | |||
| btMultiSapProxy* m_multiProxy; | |||
| btDispatcher* m_dispatcher; | |||
| MyNodeOverlapCallback(btMultiSapBroadphase* multiSap,btMultiSapProxy* multiProxy,btDispatcher* dispatcher) | |||
| :m_multiSap(multiSap), | |||
| m_multiProxy(multiProxy), | |||
| m_dispatcher(dispatcher) | |||
| { | |||
| } | |||
| virtual void processNode(int /*nodeSubPart*/, int broadphaseIndex) | |||
| { | |||
| btBroadphaseInterface* childBroadphase = m_multiSap->getBroadphaseArray()[broadphaseIndex]; | |||
| int containingBroadphaseIndex = -1; | |||
| //already found? | |||
| for (int i=0;i<m_multiProxy->m_bridgeProxies.size();i++) | |||
| { | |||
| if (m_multiProxy->m_bridgeProxies[i]->m_childBroadphase == childBroadphase) | |||
| { | |||
| containingBroadphaseIndex = i; | |||
| break; | |||
| } | |||
| } | |||
| if (containingBroadphaseIndex<0) | |||
| { | |||
| //add it | |||
| btBroadphaseProxy* childProxy = childBroadphase->createProxy(m_multiProxy->m_aabbMin,m_multiProxy->m_aabbMax,m_multiProxy->m_shapeType,m_multiProxy->m_clientObject,m_multiProxy->m_collisionFilterGroup,m_multiProxy->m_collisionFilterMask, m_dispatcher,m_multiProxy); | |||
| m_multiSap->addToChildBroadphase(m_multiProxy,childProxy,childBroadphase); | |||
| } | |||
| } | |||
| }; | |||
| MyNodeOverlapCallback myNodeCallback(this,multiProxy,dispatcher); | |||
| if (m_optimizedAabbTree) | |||
| m_optimizedAabbTree->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax); | |||
| int i; | |||
| for ( i=0;i<multiProxy->m_bridgeProxies.size();i++) | |||
| { | |||
| btVector3 worldAabbMin,worldAabbMax; | |||
| multiProxy->m_bridgeProxies[i]->m_childBroadphase->getBroadphaseAabb(worldAabbMin,worldAabbMax); | |||
| bool overlapsBroadphase = TestAabbAgainstAabb2(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax); | |||
| if (!overlapsBroadphase) | |||
| { | |||
| //remove it now | |||
| btBridgeProxy* bridgeProxy = multiProxy->m_bridgeProxies[i]; | |||
| btBroadphaseProxy* childProxy = bridgeProxy->m_childProxy; | |||
| bridgeProxy->m_childBroadphase->destroyProxy(childProxy,dispatcher); | |||
| multiProxy->m_bridgeProxies.swap( i,multiProxy->m_bridgeProxies.size()-1); | |||
| multiProxy->m_bridgeProxies.pop_back(); | |||
| } | |||
| } | |||
| /* | |||
| if (1) | |||
| { | |||
| //find broadphase that contain this multiProxy | |||
| int numChildBroadphases = getBroadphaseArray().size(); | |||
| for (int i=0;i<numChildBroadphases;i++) | |||
| { | |||
| btBroadphaseInterface* childBroadphase = getBroadphaseArray()[i]; | |||
| btVector3 worldAabbMin,worldAabbMax; | |||
| childBroadphase->getBroadphaseAabb(worldAabbMin,worldAabbMax); | |||
| bool overlapsBroadphase = TestAabbAgainstAabb2(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax); | |||
| // fullyContained = fullyContained || boxIsContainedWithinBox(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax); | |||
| int containingBroadphaseIndex = -1; | |||
| //if already contains this | |||
| for (int i=0;i<multiProxy->m_bridgeProxies.size();i++) | |||
| { | |||
| if (multiProxy->m_bridgeProxies[i]->m_childBroadphase == childBroadphase) | |||
| { | |||
| containingBroadphaseIndex = i; | |||
| } | |||
| alreadyInSimple = alreadyInSimple || (multiProxy->m_bridgeProxies[i]->m_childBroadphase == m_simpleBroadphase); | |||
| } | |||
| if (overlapsBroadphase) | |||
| { | |||
| if (containingBroadphaseIndex<0) | |||
| { | |||
| btBroadphaseProxy* childProxy = childBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher); | |||
| childProxy->m_multiSapParentProxy = multiProxy; | |||
| addToChildBroadphase(multiProxy,childProxy,childBroadphase); | |||
| } | |||
| } else | |||
| { | |||
| if (containingBroadphaseIndex>=0) | |||
| { | |||
| //remove | |||
| btBridgeProxy* bridgeProxy = multiProxy->m_bridgeProxies[containingBroadphaseIndex]; | |||
| btBroadphaseProxy* childProxy = bridgeProxy->m_childProxy; | |||
| bridgeProxy->m_childBroadphase->destroyProxy(childProxy,dispatcher); | |||
| multiProxy->m_bridgeProxies.swap( containingBroadphaseIndex,multiProxy->m_bridgeProxies.size()-1); | |||
| multiProxy->m_bridgeProxies.pop_back(); | |||
| } | |||
| } | |||
| } | |||
| ///If we are in no other child broadphase, stick the proxy in the global 'simple' broadphase (brute force) | |||
| ///hopefully we don't end up with many entries here (can assert/provide feedback on stats) | |||
| if (0)//!multiProxy->m_bridgeProxies.size()) | |||
| { | |||
| ///we don't pass the userPtr but our multisap proxy. We need to patch this, before processing an actual collision | |||
| ///this is needed to be able to calculate the aabb overlap | |||
| btBroadphaseProxy* childProxy = m_simpleBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher); | |||
| childProxy->m_multiSapParentProxy = multiProxy; | |||
| addToChildBroadphase(multiProxy,childProxy,m_simpleBroadphase); | |||
| } | |||
| } | |||
| if (!multiProxy->m_bridgeProxies.size()) | |||
| { | |||
| ///we don't pass the userPtr but our multisap proxy. We need to patch this, before processing an actual collision | |||
| ///this is needed to be able to calculate the aabb overlap | |||
| btBroadphaseProxy* childProxy = m_simpleBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher); | |||
| childProxy->m_multiSapParentProxy = multiProxy; | |||
| addToChildBroadphase(multiProxy,childProxy,m_simpleBroadphase); | |||
| } | |||
| */ | |||
| //update | |||
| for ( i=0;i<multiProxy->m_bridgeProxies.size();i++) | |||
| { | |||
| btBridgeProxy* bridgeProxyRef = multiProxy->m_bridgeProxies[i]; | |||
| bridgeProxyRef->m_childBroadphase->setAabb(bridgeProxyRef->m_childProxy,aabbMin,aabbMax,dispatcher); | |||
| } | |||
| } | |||
| bool stopUpdating=false; | |||
| class btMultiSapBroadphasePairSortPredicate | |||
| { | |||
| public: | |||
| bool operator() ( const btBroadphasePair& a1, const btBroadphasePair& b1 ) const | |||
| { | |||
| btMultiSapBroadphase::btMultiSapProxy* aProxy0 = a1.m_pProxy0 ? (btMultiSapBroadphase::btMultiSapProxy*)a1.m_pProxy0->m_multiSapParentProxy : 0; | |||
| btMultiSapBroadphase::btMultiSapProxy* aProxy1 = a1.m_pProxy1 ? (btMultiSapBroadphase::btMultiSapProxy*)a1.m_pProxy1->m_multiSapParentProxy : 0; | |||
| btMultiSapBroadphase::btMultiSapProxy* bProxy0 = b1.m_pProxy0 ? (btMultiSapBroadphase::btMultiSapProxy*)b1.m_pProxy0->m_multiSapParentProxy : 0; | |||
| btMultiSapBroadphase::btMultiSapProxy* bProxy1 = b1.m_pProxy1 ? (btMultiSapBroadphase::btMultiSapProxy*)b1.m_pProxy1->m_multiSapParentProxy : 0; | |||
| return aProxy0 > bProxy0 || | |||
| (aProxy0 == bProxy0 && aProxy1 > bProxy1) || | |||
| (aProxy0 == bProxy0 && aProxy1 == bProxy1 && a1.m_algorithm > b1.m_algorithm); | |||
| } | |||
| }; | |||
| ///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb | |||
| void btMultiSapBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) | |||
| { | |||
| // m_simpleBroadphase->calculateOverlappingPairs(dispatcher); | |||
| if (!stopUpdating && getOverlappingPairCache()->hasDeferredRemoval()) | |||
| { | |||
| btBroadphasePairArray& overlappingPairArray = getOverlappingPairCache()->getOverlappingPairArray(); | |||
| // quicksort(overlappingPairArray,0,overlappingPairArray.size()); | |||
| overlappingPairArray.quickSort(btMultiSapBroadphasePairSortPredicate()); | |||
| //perform a sort, to find duplicates and to sort 'invalid' pairs to the end | |||
| // overlappingPairArray.heapSort(btMultiSapBroadphasePairSortPredicate()); | |||
| overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); | |||
| m_invalidPair = 0; | |||
| int i; | |||
| btBroadphasePair previousPair; | |||
| previousPair.m_pProxy0 = 0; | |||
| previousPair.m_pProxy1 = 0; | |||
| previousPair.m_algorithm = 0; | |||
| for (i=0;i<overlappingPairArray.size();i++) | |||
| { | |||
| btBroadphasePair& pair = overlappingPairArray[i]; | |||
| btMultiSapProxy* aProxy0 = pair.m_pProxy0 ? (btMultiSapProxy*)pair.m_pProxy0->m_multiSapParentProxy : 0; | |||
| btMultiSapProxy* aProxy1 = pair.m_pProxy1 ? (btMultiSapProxy*)pair.m_pProxy1->m_multiSapParentProxy : 0; | |||
| btMultiSapProxy* bProxy0 = previousPair.m_pProxy0 ? (btMultiSapProxy*)previousPair.m_pProxy0->m_multiSapParentProxy : 0; | |||
| btMultiSapProxy* bProxy1 = previousPair.m_pProxy1 ? (btMultiSapProxy*)previousPair.m_pProxy1->m_multiSapParentProxy : 0; | |||
| bool isDuplicate = (aProxy0 == bProxy0) && (aProxy1 == bProxy1); | |||
| previousPair = pair; | |||
| bool needsRemoval = false; | |||
| if (!isDuplicate) | |||
| { | |||
| bool hasOverlap = testAabbOverlap(pair.m_pProxy0,pair.m_pProxy1); | |||
| if (hasOverlap) | |||
| { | |||
| needsRemoval = false;//callback->processOverlap(pair); | |||
| } else | |||
| { | |||
| needsRemoval = true; | |||
| } | |||
| } else | |||
| { | |||
| //remove duplicate | |||
| needsRemoval = true; | |||
| //should have no algorithm | |||
| btAssert(!pair.m_algorithm); | |||
| } | |||
| if (needsRemoval) | |||
| { | |||
| getOverlappingPairCache()->cleanOverlappingPair(pair,dispatcher); | |||
| // m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); | |||
| // m_overlappingPairArray.pop_back(); | |||
| pair.m_pProxy0 = 0; | |||
| pair.m_pProxy1 = 0; | |||
| m_invalidPair++; | |||
| gOverlappingPairs--; | |||
| } | |||
| } | |||
| ///if you don't like to skip the invalid pairs in the array, execute following code: | |||
| #define CLEAN_INVALID_PAIRS 1 | |||
| #ifdef CLEAN_INVALID_PAIRS | |||
| //perform a sort, to sort 'invalid' pairs to the end | |||
| //overlappingPairArray.heapSort(btMultiSapBroadphasePairSortPredicate()); | |||
| overlappingPairArray.quickSort(btMultiSapBroadphasePairSortPredicate()); | |||
| overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); | |||
| m_invalidPair = 0; | |||
| #endif//CLEAN_INVALID_PAIRS | |||
| //printf("overlappingPairArray.size()=%d\n",overlappingPairArray.size()); | |||
| } | |||
| } | |||
| bool btMultiSapBroadphase::testAabbOverlap(btBroadphaseProxy* childProxy0,btBroadphaseProxy* childProxy1) | |||
| { | |||
| btMultiSapProxy* multiSapProxy0 = (btMultiSapProxy*)childProxy0->m_multiSapParentProxy; | |||
| btMultiSapProxy* multiSapProxy1 = (btMultiSapProxy*)childProxy1->m_multiSapParentProxy; | |||
| return TestAabbAgainstAabb2(multiSapProxy0->m_aabbMin,multiSapProxy0->m_aabbMax, | |||
| multiSapProxy1->m_aabbMin,multiSapProxy1->m_aabbMax); | |||
| } | |||
| void btMultiSapBroadphase::printStats() | |||
| { | |||
| /* printf("---------------------------------\n"); | |||
| printf("btMultiSapBroadphase.h\n"); | |||
| printf("numHandles = %d\n",m_multiSapProxies.size()); | |||
| //find broadphase that contain this multiProxy | |||
| int numChildBroadphases = getBroadphaseArray().size(); | |||
| for (int i=0;i<numChildBroadphases;i++) | |||
| { | |||
| btBroadphaseInterface* childBroadphase = getBroadphaseArray()[i]; | |||
| childBroadphase->printStats(); | |||
| } | |||
| */ | |||
| } | |||
| void btMultiSapBroadphase::resetPool(btDispatcher* dispatcher) | |||
| { | |||
| // not yet | |||
| } | |||
| @@ -0,0 +1,151 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_MULTI_SAP_BROADPHASE | |||
| #define BT_MULTI_SAP_BROADPHASE | |||
| #include "btBroadphaseInterface.h" | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| #include "btOverlappingPairCache.h" | |||
| class btBroadphaseInterface; | |||
| class btSimpleBroadphase; | |||
| typedef btAlignedObjectArray<btBroadphaseInterface*> btSapBroadphaseArray; | |||
| ///The btMultiSapBroadphase is a research project, not recommended to use in production. Use btAxisSweep3 or btDbvtBroadphase instead. | |||
| ///The btMultiSapBroadphase is a broadphase that contains multiple SAP broadphases. | |||
| ///The user can add SAP broadphases that cover the world. A btBroadphaseProxy can be in multiple child broadphases at the same time. | |||
| ///A btQuantizedBvh acceleration structures finds overlapping SAPs for each btBroadphaseProxy. | |||
| ///See http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=328 | |||
| ///and http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1329 | |||
| class btMultiSapBroadphase :public btBroadphaseInterface | |||
| { | |||
| btSapBroadphaseArray m_sapBroadphases; | |||
| btSimpleBroadphase* m_simpleBroadphase; | |||
| btOverlappingPairCache* m_overlappingPairs; | |||
| class btQuantizedBvh* m_optimizedAabbTree; | |||
| bool m_ownsPairCache; | |||
| btOverlapFilterCallback* m_filterCallback; | |||
| int m_invalidPair; | |||
| struct btBridgeProxy | |||
| { | |||
| btBroadphaseProxy* m_childProxy; | |||
| btBroadphaseInterface* m_childBroadphase; | |||
| }; | |||
| public: | |||
| struct btMultiSapProxy : public btBroadphaseProxy | |||
| { | |||
| ///array with all the entries that this proxy belongs to | |||
| btAlignedObjectArray<btBridgeProxy*> m_bridgeProxies; | |||
| btVector3 m_aabbMin; | |||
| btVector3 m_aabbMax; | |||
| int m_shapeType; | |||
| /* void* m_userPtr; | |||
| short int m_collisionFilterGroup; | |||
| short int m_collisionFilterMask; | |||
| */ | |||
| btMultiSapProxy(const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask) | |||
| :btBroadphaseProxy(aabbMin,aabbMax,userPtr,collisionFilterGroup,collisionFilterMask), | |||
| m_aabbMin(aabbMin), | |||
| m_aabbMax(aabbMax), | |||
| m_shapeType(shapeType) | |||
| { | |||
| m_multiSapParentProxy =this; | |||
| } | |||
| }; | |||
| protected: | |||
| btAlignedObjectArray<btMultiSapProxy*> m_multiSapProxies; | |||
| public: | |||
| btMultiSapBroadphase(int maxProxies = 16384,btOverlappingPairCache* pairCache=0); | |||
| btSapBroadphaseArray& getBroadphaseArray() | |||
| { | |||
| return m_sapBroadphases; | |||
| } | |||
| const btSapBroadphaseArray& getBroadphaseArray() const | |||
| { | |||
| return m_sapBroadphases; | |||
| } | |||
| virtual ~btMultiSapBroadphase(); | |||
| virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy); | |||
| virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
| virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher); | |||
| virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; | |||
| virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin=btVector3(0,0,0),const btVector3& aabbMax=btVector3(0,0,0)); | |||
| void addToChildBroadphase(btMultiSapProxy* parentMultiSapProxy, btBroadphaseProxy* childProxy, btBroadphaseInterface* childBroadphase); | |||
| ///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb | |||
| virtual void calculateOverlappingPairs(btDispatcher* dispatcher); | |||
| bool testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); | |||
| virtual btOverlappingPairCache* getOverlappingPairCache() | |||
| { | |||
| return m_overlappingPairs; | |||
| } | |||
| virtual const btOverlappingPairCache* getOverlappingPairCache() const | |||
| { | |||
| return m_overlappingPairs; | |||
| } | |||
| ///getAabb returns the axis aligned bounding box in the 'global' coordinate frame | |||
| ///will add some transform later | |||
| virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const | |||
| { | |||
| aabbMin.setValue(-BT_LARGE_FLOAT,-BT_LARGE_FLOAT,-BT_LARGE_FLOAT); | |||
| aabbMax.setValue(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT); | |||
| } | |||
| void buildTree(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax); | |||
| virtual void printStats(); | |||
| void quicksort (btBroadphasePairArray& a, int lo, int hi); | |||
| ///reset broadphase internal structures, to ensure determinism/reproducability | |||
| virtual void resetPool(btDispatcher* dispatcher); | |||
| }; | |||
| #endif //BT_MULTI_SAP_BROADPHASE | |||
| @@ -0,0 +1,633 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btOverlappingPairCache.h" | |||
| #include "btDispatcher.h" | |||
| #include "btCollisionAlgorithm.h" | |||
| #include "LinearMath/btAabbUtil2.h" | |||
| #include <stdio.h> | |||
| int gOverlappingPairs = 0; | |||
| int gRemovePairs =0; | |||
| int gAddedPairs =0; | |||
| int gFindPairs =0; | |||
| btHashedOverlappingPairCache::btHashedOverlappingPairCache(): | |||
| m_overlapFilterCallback(0), | |||
| m_blockedForChanges(false), | |||
| m_ghostPairCallback(0) | |||
| { | |||
| int initialAllocatedSize= 2; | |||
| m_overlappingPairArray.reserve(initialAllocatedSize); | |||
| growTables(); | |||
| } | |||
| btHashedOverlappingPairCache::~btHashedOverlappingPairCache() | |||
| { | |||
| } | |||
| void btHashedOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher) | |||
| { | |||
| if (pair.m_algorithm) | |||
| { | |||
| { | |||
| pair.m_algorithm->~btCollisionAlgorithm(); | |||
| dispatcher->freeCollisionAlgorithm(pair.m_algorithm); | |||
| pair.m_algorithm=0; | |||
| } | |||
| } | |||
| } | |||
| void btHashedOverlappingPairCache::cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher) | |||
| { | |||
| class CleanPairCallback : public btOverlapCallback | |||
| { | |||
| btBroadphaseProxy* m_cleanProxy; | |||
| btOverlappingPairCache* m_pairCache; | |||
| btDispatcher* m_dispatcher; | |||
| public: | |||
| CleanPairCallback(btBroadphaseProxy* cleanProxy,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) | |||
| :m_cleanProxy(cleanProxy), | |||
| m_pairCache(pairCache), | |||
| m_dispatcher(dispatcher) | |||
| { | |||
| } | |||
| virtual bool processOverlap(btBroadphasePair& pair) | |||
| { | |||
| if ((pair.m_pProxy0 == m_cleanProxy) || | |||
| (pair.m_pProxy1 == m_cleanProxy)) | |||
| { | |||
| m_pairCache->cleanOverlappingPair(pair,m_dispatcher); | |||
| } | |||
| return false; | |||
| } | |||
| }; | |||
| CleanPairCallback cleanPairs(proxy,this,dispatcher); | |||
| processAllOverlappingPairs(&cleanPairs,dispatcher); | |||
| } | |||
| void btHashedOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher) | |||
| { | |||
| class RemovePairCallback : public btOverlapCallback | |||
| { | |||
| btBroadphaseProxy* m_obsoleteProxy; | |||
| public: | |||
| RemovePairCallback(btBroadphaseProxy* obsoleteProxy) | |||
| :m_obsoleteProxy(obsoleteProxy) | |||
| { | |||
| } | |||
| virtual bool processOverlap(btBroadphasePair& pair) | |||
| { | |||
| return ((pair.m_pProxy0 == m_obsoleteProxy) || | |||
| (pair.m_pProxy1 == m_obsoleteProxy)); | |||
| } | |||
| }; | |||
| RemovePairCallback removeCallback(proxy); | |||
| processAllOverlappingPairs(&removeCallback,dispatcher); | |||
| } | |||
| btBroadphasePair* btHashedOverlappingPairCache::findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) | |||
| { | |||
| gFindPairs++; | |||
| if(proxy0->m_uniqueId>proxy1->m_uniqueId) | |||
| btSwap(proxy0,proxy1); | |||
| int proxyId1 = proxy0->getUid(); | |||
| int proxyId2 = proxy1->getUid(); | |||
| /*if (proxyId1 > proxyId2) | |||
| btSwap(proxyId1, proxyId2);*/ | |||
| int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1), static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1)); | |||
| if (hash >= m_hashTable.size()) | |||
| { | |||
| return NULL; | |||
| } | |||
| int index = m_hashTable[hash]; | |||
| while (index != BT_NULL_PAIR && equalsPair(m_overlappingPairArray[index], proxyId1, proxyId2) == false) | |||
| { | |||
| index = m_next[index]; | |||
| } | |||
| if (index == BT_NULL_PAIR) | |||
| { | |||
| return NULL; | |||
| } | |||
| btAssert(index < m_overlappingPairArray.size()); | |||
| return &m_overlappingPairArray[index]; | |||
| } | |||
| //#include <stdio.h> | |||
| void btHashedOverlappingPairCache::growTables() | |||
| { | |||
| int newCapacity = m_overlappingPairArray.capacity(); | |||
| if (m_hashTable.size() < newCapacity) | |||
| { | |||
| //grow hashtable and next table | |||
| int curHashtableSize = m_hashTable.size(); | |||
| m_hashTable.resize(newCapacity); | |||
| m_next.resize(newCapacity); | |||
| int i; | |||
| for (i= 0; i < newCapacity; ++i) | |||
| { | |||
| m_hashTable[i] = BT_NULL_PAIR; | |||
| } | |||
| for (i = 0; i < newCapacity; ++i) | |||
| { | |||
| m_next[i] = BT_NULL_PAIR; | |||
| } | |||
| for(i=0;i<curHashtableSize;i++) | |||
| { | |||
| const btBroadphasePair& pair = m_overlappingPairArray[i]; | |||
| int proxyId1 = pair.m_pProxy0->getUid(); | |||
| int proxyId2 = pair.m_pProxy1->getUid(); | |||
| /*if (proxyId1 > proxyId2) | |||
| btSwap(proxyId1, proxyId2);*/ | |||
| int hashValue = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1)); // New hash value with new mask | |||
| m_next[i] = m_hashTable[hashValue]; | |||
| m_hashTable[hashValue] = i; | |||
| } | |||
| } | |||
| } | |||
| btBroadphasePair* btHashedOverlappingPairCache::internalAddPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) | |||
| { | |||
| if(proxy0->m_uniqueId>proxy1->m_uniqueId) | |||
| btSwap(proxy0,proxy1); | |||
| int proxyId1 = proxy0->getUid(); | |||
| int proxyId2 = proxy1->getUid(); | |||
| /*if (proxyId1 > proxyId2) | |||
| btSwap(proxyId1, proxyId2);*/ | |||
| int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1)); // New hash value with new mask | |||
| btBroadphasePair* pair = internalFindPair(proxy0, proxy1, hash); | |||
| if (pair != NULL) | |||
| { | |||
| return pair; | |||
| } | |||
| /*for(int i=0;i<m_overlappingPairArray.size();++i) | |||
| { | |||
| if( (m_overlappingPairArray[i].m_pProxy0==proxy0)&& | |||
| (m_overlappingPairArray[i].m_pProxy1==proxy1)) | |||
| { | |||
| printf("Adding duplicated %u<>%u\r\n",proxyId1,proxyId2); | |||
| internalFindPair(proxy0, proxy1, hash); | |||
| } | |||
| }*/ | |||
| int count = m_overlappingPairArray.size(); | |||
| int oldCapacity = m_overlappingPairArray.capacity(); | |||
| void* mem = &m_overlappingPairArray.expandNonInitializing(); | |||
| //this is where we add an actual pair, so also call the 'ghost' | |||
| if (m_ghostPairCallback) | |||
| m_ghostPairCallback->addOverlappingPair(proxy0,proxy1); | |||
| int newCapacity = m_overlappingPairArray.capacity(); | |||
| if (oldCapacity < newCapacity) | |||
| { | |||
| growTables(); | |||
| //hash with new capacity | |||
| hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1)); | |||
| } | |||
| pair = new (mem) btBroadphasePair(*proxy0,*proxy1); | |||
| // pair->m_pProxy0 = proxy0; | |||
| // pair->m_pProxy1 = proxy1; | |||
| pair->m_algorithm = 0; | |||
| pair->m_internalTmpValue = 0; | |||
| m_next[count] = m_hashTable[hash]; | |||
| m_hashTable[hash] = count; | |||
| return pair; | |||
| } | |||
| void* btHashedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1,btDispatcher* dispatcher) | |||
| { | |||
| gRemovePairs++; | |||
| if(proxy0->m_uniqueId>proxy1->m_uniqueId) | |||
| btSwap(proxy0,proxy1); | |||
| int proxyId1 = proxy0->getUid(); | |||
| int proxyId2 = proxy1->getUid(); | |||
| /*if (proxyId1 > proxyId2) | |||
| btSwap(proxyId1, proxyId2);*/ | |||
| int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1),static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity()-1)); | |||
| btBroadphasePair* pair = internalFindPair(proxy0, proxy1, hash); | |||
| if (pair == NULL) | |||
| { | |||
| return 0; | |||
| } | |||
| cleanOverlappingPair(*pair,dispatcher); | |||
| void* userData = pair->m_internalInfo1; | |||
| btAssert(pair->m_pProxy0->getUid() == proxyId1); | |||
| btAssert(pair->m_pProxy1->getUid() == proxyId2); | |||
| int pairIndex = int(pair - &m_overlappingPairArray[0]); | |||
| btAssert(pairIndex < m_overlappingPairArray.size()); | |||
| // Remove the pair from the hash table. | |||
| int index = m_hashTable[hash]; | |||
| btAssert(index != BT_NULL_PAIR); | |||
| int previous = BT_NULL_PAIR; | |||
| while (index != pairIndex) | |||
| { | |||
| previous = index; | |||
| index = m_next[index]; | |||
| } | |||
| if (previous != BT_NULL_PAIR) | |||
| { | |||
| btAssert(m_next[previous] == pairIndex); | |||
| m_next[previous] = m_next[pairIndex]; | |||
| } | |||
| else | |||
| { | |||
| m_hashTable[hash] = m_next[pairIndex]; | |||
| } | |||
| // We now move the last pair into spot of the | |||
| // pair being removed. We need to fix the hash | |||
| // table indices to support the move. | |||
| int lastPairIndex = m_overlappingPairArray.size() - 1; | |||
| if (m_ghostPairCallback) | |||
| m_ghostPairCallback->removeOverlappingPair(proxy0, proxy1,dispatcher); | |||
| // If the removed pair is the last pair, we are done. | |||
| if (lastPairIndex == pairIndex) | |||
| { | |||
| m_overlappingPairArray.pop_back(); | |||
| return userData; | |||
| } | |||
| // Remove the last pair from the hash table. | |||
| const btBroadphasePair* last = &m_overlappingPairArray[lastPairIndex]; | |||
| /* missing swap here too, Nat. */ | |||
| int lastHash = static_cast<int>(getHash(static_cast<unsigned int>(last->m_pProxy0->getUid()), static_cast<unsigned int>(last->m_pProxy1->getUid())) & (m_overlappingPairArray.capacity()-1)); | |||
| index = m_hashTable[lastHash]; | |||
| btAssert(index != BT_NULL_PAIR); | |||
| previous = BT_NULL_PAIR; | |||
| while (index != lastPairIndex) | |||
| { | |||
| previous = index; | |||
| index = m_next[index]; | |||
| } | |||
| if (previous != BT_NULL_PAIR) | |||
| { | |||
| btAssert(m_next[previous] == lastPairIndex); | |||
| m_next[previous] = m_next[lastPairIndex]; | |||
| } | |||
| else | |||
| { | |||
| m_hashTable[lastHash] = m_next[lastPairIndex]; | |||
| } | |||
| // Copy the last pair into the remove pair's spot. | |||
| m_overlappingPairArray[pairIndex] = m_overlappingPairArray[lastPairIndex]; | |||
| // Insert the last pair into the hash table | |||
| m_next[pairIndex] = m_hashTable[lastHash]; | |||
| m_hashTable[lastHash] = pairIndex; | |||
| m_overlappingPairArray.pop_back(); | |||
| return userData; | |||
| } | |||
| //#include <stdio.h> | |||
| void btHashedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher) | |||
| { | |||
| int i; | |||
| // printf("m_overlappingPairArray.size()=%d\n",m_overlappingPairArray.size()); | |||
| for (i=0;i<m_overlappingPairArray.size();) | |||
| { | |||
| btBroadphasePair* pair = &m_overlappingPairArray[i]; | |||
| if (callback->processOverlap(*pair)) | |||
| { | |||
| removeOverlappingPair(pair->m_pProxy0,pair->m_pProxy1,dispatcher); | |||
| gOverlappingPairs--; | |||
| } else | |||
| { | |||
| i++; | |||
| } | |||
| } | |||
| } | |||
| void btHashedOverlappingPairCache::sortOverlappingPairs(btDispatcher* dispatcher) | |||
| { | |||
| ///need to keep hashmap in sync with pair address, so rebuild all | |||
| btBroadphasePairArray tmpPairs; | |||
| int i; | |||
| for (i=0;i<m_overlappingPairArray.size();i++) | |||
| { | |||
| tmpPairs.push_back(m_overlappingPairArray[i]); | |||
| } | |||
| for (i=0;i<tmpPairs.size();i++) | |||
| { | |||
| removeOverlappingPair(tmpPairs[i].m_pProxy0,tmpPairs[i].m_pProxy1,dispatcher); | |||
| } | |||
| for (i = 0; i < m_next.size(); i++) | |||
| { | |||
| m_next[i] = BT_NULL_PAIR; | |||
| } | |||
| tmpPairs.quickSort(btBroadphasePairSortPredicate()); | |||
| for (i=0;i<tmpPairs.size();i++) | |||
| { | |||
| addOverlappingPair(tmpPairs[i].m_pProxy0,tmpPairs[i].m_pProxy1); | |||
| } | |||
| } | |||
| void* btSortedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1, btDispatcher* dispatcher ) | |||
| { | |||
| if (!hasDeferredRemoval()) | |||
| { | |||
| btBroadphasePair findPair(*proxy0,*proxy1); | |||
| int findIndex = m_overlappingPairArray.findLinearSearch(findPair); | |||
| if (findIndex < m_overlappingPairArray.size()) | |||
| { | |||
| gOverlappingPairs--; | |||
| btBroadphasePair& pair = m_overlappingPairArray[findIndex]; | |||
| void* userData = pair.m_internalInfo1; | |||
| cleanOverlappingPair(pair,dispatcher); | |||
| if (m_ghostPairCallback) | |||
| m_ghostPairCallback->removeOverlappingPair(proxy0, proxy1,dispatcher); | |||
| m_overlappingPairArray.swap(findIndex,m_overlappingPairArray.capacity()-1); | |||
| m_overlappingPairArray.pop_back(); | |||
| return userData; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| btBroadphasePair* btSortedOverlappingPairCache::addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) | |||
| { | |||
| //don't add overlap with own | |||
| btAssert(proxy0 != proxy1); | |||
| if (!needsBroadphaseCollision(proxy0,proxy1)) | |||
| return 0; | |||
| void* mem = &m_overlappingPairArray.expandNonInitializing(); | |||
| btBroadphasePair* pair = new (mem) btBroadphasePair(*proxy0,*proxy1); | |||
| gOverlappingPairs++; | |||
| gAddedPairs++; | |||
| if (m_ghostPairCallback) | |||
| m_ghostPairCallback->addOverlappingPair(proxy0, proxy1); | |||
| return pair; | |||
| } | |||
| ///this findPair becomes really slow. Either sort the list to speedup the query, or | |||
| ///use a different solution. It is mainly used for Removing overlapping pairs. Removal could be delayed. | |||
| ///we could keep a linked list in each proxy, and store pair in one of the proxies (with lowest memory address) | |||
| ///Also we can use a 2D bitmap, which can be useful for a future GPU implementation | |||
| btBroadphasePair* btSortedOverlappingPairCache::findPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) | |||
| { | |||
| if (!needsBroadphaseCollision(proxy0,proxy1)) | |||
| return 0; | |||
| btBroadphasePair tmpPair(*proxy0,*proxy1); | |||
| int findIndex = m_overlappingPairArray.findLinearSearch(tmpPair); | |||
| if (findIndex < m_overlappingPairArray.size()) | |||
| { | |||
| //btAssert(it != m_overlappingPairSet.end()); | |||
| btBroadphasePair* pair = &m_overlappingPairArray[findIndex]; | |||
| return pair; | |||
| } | |||
| return 0; | |||
| } | |||
| //#include <stdio.h> | |||
| void btSortedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher) | |||
| { | |||
| int i; | |||
| for (i=0;i<m_overlappingPairArray.size();) | |||
| { | |||
| btBroadphasePair* pair = &m_overlappingPairArray[i]; | |||
| if (callback->processOverlap(*pair)) | |||
| { | |||
| cleanOverlappingPair(*pair,dispatcher); | |||
| pair->m_pProxy0 = 0; | |||
| pair->m_pProxy1 = 0; | |||
| m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); | |||
| m_overlappingPairArray.pop_back(); | |||
| gOverlappingPairs--; | |||
| } else | |||
| { | |||
| i++; | |||
| } | |||
| } | |||
| } | |||
| btSortedOverlappingPairCache::btSortedOverlappingPairCache(): | |||
| m_blockedForChanges(false), | |||
| m_hasDeferredRemoval(true), | |||
| m_overlapFilterCallback(0), | |||
| m_ghostPairCallback(0) | |||
| { | |||
| int initialAllocatedSize= 2; | |||
| m_overlappingPairArray.reserve(initialAllocatedSize); | |||
| } | |||
| btSortedOverlappingPairCache::~btSortedOverlappingPairCache() | |||
| { | |||
| } | |||
| void btSortedOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher) | |||
| { | |||
| if (pair.m_algorithm) | |||
| { | |||
| { | |||
| pair.m_algorithm->~btCollisionAlgorithm(); | |||
| dispatcher->freeCollisionAlgorithm(pair.m_algorithm); | |||
| pair.m_algorithm=0; | |||
| gRemovePairs--; | |||
| } | |||
| } | |||
| } | |||
| void btSortedOverlappingPairCache::cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher) | |||
| { | |||
| class CleanPairCallback : public btOverlapCallback | |||
| { | |||
| btBroadphaseProxy* m_cleanProxy; | |||
| btOverlappingPairCache* m_pairCache; | |||
| btDispatcher* m_dispatcher; | |||
| public: | |||
| CleanPairCallback(btBroadphaseProxy* cleanProxy,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) | |||
| :m_cleanProxy(cleanProxy), | |||
| m_pairCache(pairCache), | |||
| m_dispatcher(dispatcher) | |||
| { | |||
| } | |||
| virtual bool processOverlap(btBroadphasePair& pair) | |||
| { | |||
| if ((pair.m_pProxy0 == m_cleanProxy) || | |||
| (pair.m_pProxy1 == m_cleanProxy)) | |||
| { | |||
| m_pairCache->cleanOverlappingPair(pair,m_dispatcher); | |||
| } | |||
| return false; | |||
| } | |||
| }; | |||
| CleanPairCallback cleanPairs(proxy,this,dispatcher); | |||
| processAllOverlappingPairs(&cleanPairs,dispatcher); | |||
| } | |||
| void btSortedOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher) | |||
| { | |||
| class RemovePairCallback : public btOverlapCallback | |||
| { | |||
| btBroadphaseProxy* m_obsoleteProxy; | |||
| public: | |||
| RemovePairCallback(btBroadphaseProxy* obsoleteProxy) | |||
| :m_obsoleteProxy(obsoleteProxy) | |||
| { | |||
| } | |||
| virtual bool processOverlap(btBroadphasePair& pair) | |||
| { | |||
| return ((pair.m_pProxy0 == m_obsoleteProxy) || | |||
| (pair.m_pProxy1 == m_obsoleteProxy)); | |||
| } | |||
| }; | |||
| RemovePairCallback removeCallback(proxy); | |||
| processAllOverlappingPairs(&removeCallback,dispatcher); | |||
| } | |||
| void btSortedOverlappingPairCache::sortOverlappingPairs(btDispatcher* dispatcher) | |||
| { | |||
| //should already be sorted | |||
| } | |||
| @@ -0,0 +1,469 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_OVERLAPPING_PAIR_CACHE_H | |||
| #define BT_OVERLAPPING_PAIR_CACHE_H | |||
| #include "btBroadphaseInterface.h" | |||
| #include "btBroadphaseProxy.h" | |||
| #include "btOverlappingPairCallback.h" | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| class btDispatcher; | |||
| typedef btAlignedObjectArray<btBroadphasePair> btBroadphasePairArray; | |||
| struct btOverlapCallback | |||
| { | |||
| virtual ~btOverlapCallback() | |||
| {} | |||
| //return true for deletion of the pair | |||
| virtual bool processOverlap(btBroadphasePair& pair) = 0; | |||
| }; | |||
| struct btOverlapFilterCallback | |||
| { | |||
| virtual ~btOverlapFilterCallback() | |||
| {} | |||
| // return true when pairs need collision | |||
| virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const = 0; | |||
| }; | |||
| extern int gRemovePairs; | |||
| extern int gAddedPairs; | |||
| extern int gFindPairs; | |||
| const int BT_NULL_PAIR=0xffffffff; | |||
| ///The btOverlappingPairCache provides an interface for overlapping pair management (add, remove, storage), used by the btBroadphaseInterface broadphases. | |||
| ///The btHashedOverlappingPairCache and btSortedOverlappingPairCache classes are two implementations. | |||
| class btOverlappingPairCache : public btOverlappingPairCallback | |||
| { | |||
| public: | |||
| virtual ~btOverlappingPairCache() {} // this is needed so we can get to the derived class destructor | |||
| virtual btBroadphasePair* getOverlappingPairArrayPtr() = 0; | |||
| virtual const btBroadphasePair* getOverlappingPairArrayPtr() const = 0; | |||
| virtual btBroadphasePairArray& getOverlappingPairArray() = 0; | |||
| virtual void cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher) = 0; | |||
| virtual int getNumOverlappingPairs() const = 0; | |||
| virtual void cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher) = 0; | |||
| virtual void setOverlapFilterCallback(btOverlapFilterCallback* callback) = 0; | |||
| virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher) = 0; | |||
| virtual btBroadphasePair* findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) = 0; | |||
| virtual bool hasDeferredRemoval() = 0; | |||
| virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback)=0; | |||
| virtual void sortOverlappingPairs(btDispatcher* dispatcher) = 0; | |||
| }; | |||
| /// Hash-space based Pair Cache, thanks to Erin Catto, Box2D, http://www.box2d.org, and Pierre Terdiman, Codercorner, http://codercorner.com | |||
| class btHashedOverlappingPairCache : public btOverlappingPairCache | |||
| { | |||
| btBroadphasePairArray m_overlappingPairArray; | |||
| btOverlapFilterCallback* m_overlapFilterCallback; | |||
| bool m_blockedForChanges; | |||
| public: | |||
| btHashedOverlappingPairCache(); | |||
| virtual ~btHashedOverlappingPairCache(); | |||
| void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
| virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher); | |||
| SIMD_FORCE_INLINE bool needsBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const | |||
| { | |||
| if (m_overlapFilterCallback) | |||
| return m_overlapFilterCallback->needBroadphaseCollision(proxy0,proxy1); | |||
| bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; | |||
| collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); | |||
| return collides; | |||
| } | |||
| // Add a pair and return the new pair. If the pair already exists, | |||
| // no new pair is created and the old one is returned. | |||
| virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) | |||
| { | |||
| gAddedPairs++; | |||
| if (!needsBroadphaseCollision(proxy0,proxy1)) | |||
| return 0; | |||
| return internalAddPair(proxy0,proxy1); | |||
| } | |||
| void cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
| virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher); | |||
| virtual btBroadphasePair* getOverlappingPairArrayPtr() | |||
| { | |||
| return &m_overlappingPairArray[0]; | |||
| } | |||
| const btBroadphasePair* getOverlappingPairArrayPtr() const | |||
| { | |||
| return &m_overlappingPairArray[0]; | |||
| } | |||
| btBroadphasePairArray& getOverlappingPairArray() | |||
| { | |||
| return m_overlappingPairArray; | |||
| } | |||
| const btBroadphasePairArray& getOverlappingPairArray() const | |||
| { | |||
| return m_overlappingPairArray; | |||
| } | |||
| void cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher); | |||
| btBroadphasePair* findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1); | |||
| int GetCount() const { return m_overlappingPairArray.size(); } | |||
| // btBroadphasePair* GetPairs() { return m_pairs; } | |||
| btOverlapFilterCallback* getOverlapFilterCallback() | |||
| { | |||
| return m_overlapFilterCallback; | |||
| } | |||
| void setOverlapFilterCallback(btOverlapFilterCallback* callback) | |||
| { | |||
| m_overlapFilterCallback = callback; | |||
| } | |||
| int getNumOverlappingPairs() const | |||
| { | |||
| return m_overlappingPairArray.size(); | |||
| } | |||
| private: | |||
| btBroadphasePair* internalAddPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); | |||
| void growTables(); | |||
| SIMD_FORCE_INLINE bool equalsPair(const btBroadphasePair& pair, int proxyId1, int proxyId2) | |||
| { | |||
| return pair.m_pProxy0->getUid() == proxyId1 && pair.m_pProxy1->getUid() == proxyId2; | |||
| } | |||
| /* | |||
| // Thomas Wang's hash, see: http://www.concentric.net/~Ttwang/tech/inthash.htm | |||
| // This assumes proxyId1 and proxyId2 are 16-bit. | |||
| SIMD_FORCE_INLINE int getHash(int proxyId1, int proxyId2) | |||
| { | |||
| int key = (proxyId2 << 16) | proxyId1; | |||
| key = ~key + (key << 15); | |||
| key = key ^ (key >> 12); | |||
| key = key + (key << 2); | |||
| key = key ^ (key >> 4); | |||
| key = key * 2057; | |||
| key = key ^ (key >> 16); | |||
| return key; | |||
| } | |||
| */ | |||
| SIMD_FORCE_INLINE unsigned int getHash(unsigned int proxyId1, unsigned int proxyId2) | |||
| { | |||
| int key = static_cast<int>(((unsigned int)proxyId1) | (((unsigned int)proxyId2) <<16)); | |||
| // Thomas Wang's hash | |||
| key += ~(key << 15); | |||
| key ^= (key >> 10); | |||
| key += (key << 3); | |||
| key ^= (key >> 6); | |||
| key += ~(key << 11); | |||
| key ^= (key >> 16); | |||
| return static_cast<unsigned int>(key); | |||
| } | |||
| SIMD_FORCE_INLINE btBroadphasePair* internalFindPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1, int hash) | |||
| { | |||
| int proxyId1 = proxy0->getUid(); | |||
| int proxyId2 = proxy1->getUid(); | |||
| #if 0 // wrong, 'equalsPair' use unsorted uids, copy-past devil striked again. Nat. | |||
| if (proxyId1 > proxyId2) | |||
| btSwap(proxyId1, proxyId2); | |||
| #endif | |||
| int index = m_hashTable[hash]; | |||
| while( index != BT_NULL_PAIR && equalsPair(m_overlappingPairArray[index], proxyId1, proxyId2) == false) | |||
| { | |||
| index = m_next[index]; | |||
| } | |||
| if ( index == BT_NULL_PAIR ) | |||
| { | |||
| return NULL; | |||
| } | |||
| btAssert(index < m_overlappingPairArray.size()); | |||
| return &m_overlappingPairArray[index]; | |||
| } | |||
| virtual bool hasDeferredRemoval() | |||
| { | |||
| return false; | |||
| } | |||
| virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback) | |||
| { | |||
| m_ghostPairCallback = ghostPairCallback; | |||
| } | |||
| virtual void sortOverlappingPairs(btDispatcher* dispatcher); | |||
| protected: | |||
| btAlignedObjectArray<int> m_hashTable; | |||
| btAlignedObjectArray<int> m_next; | |||
| btOverlappingPairCallback* m_ghostPairCallback; | |||
| }; | |||
| ///btSortedOverlappingPairCache maintains the objects with overlapping AABB | |||
| ///Typically managed by the Broadphase, Axis3Sweep or btSimpleBroadphase | |||
| class btSortedOverlappingPairCache : public btOverlappingPairCache | |||
| { | |||
| protected: | |||
| //avoid brute-force finding all the time | |||
| btBroadphasePairArray m_overlappingPairArray; | |||
| //during the dispatch, check that user doesn't destroy/create proxy | |||
| bool m_blockedForChanges; | |||
| ///by default, do the removal during the pair traversal | |||
| bool m_hasDeferredRemoval; | |||
| //if set, use the callback instead of the built in filter in needBroadphaseCollision | |||
| btOverlapFilterCallback* m_overlapFilterCallback; | |||
| btOverlappingPairCallback* m_ghostPairCallback; | |||
| public: | |||
| btSortedOverlappingPairCache(); | |||
| virtual ~btSortedOverlappingPairCache(); | |||
| virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher); | |||
| void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher); | |||
| void cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher); | |||
| btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); | |||
| btBroadphasePair* findPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); | |||
| void cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
| void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
| inline bool needsBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const | |||
| { | |||
| if (m_overlapFilterCallback) | |||
| return m_overlapFilterCallback->needBroadphaseCollision(proxy0,proxy1); | |||
| bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; | |||
| collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); | |||
| return collides; | |||
| } | |||
| btBroadphasePairArray& getOverlappingPairArray() | |||
| { | |||
| return m_overlappingPairArray; | |||
| } | |||
| const btBroadphasePairArray& getOverlappingPairArray() const | |||
| { | |||
| return m_overlappingPairArray; | |||
| } | |||
| btBroadphasePair* getOverlappingPairArrayPtr() | |||
| { | |||
| return &m_overlappingPairArray[0]; | |||
| } | |||
| const btBroadphasePair* getOverlappingPairArrayPtr() const | |||
| { | |||
| return &m_overlappingPairArray[0]; | |||
| } | |||
| int getNumOverlappingPairs() const | |||
| { | |||
| return m_overlappingPairArray.size(); | |||
| } | |||
| btOverlapFilterCallback* getOverlapFilterCallback() | |||
| { | |||
| return m_overlapFilterCallback; | |||
| } | |||
| void setOverlapFilterCallback(btOverlapFilterCallback* callback) | |||
| { | |||
| m_overlapFilterCallback = callback; | |||
| } | |||
| virtual bool hasDeferredRemoval() | |||
| { | |||
| return m_hasDeferredRemoval; | |||
| } | |||
| virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback) | |||
| { | |||
| m_ghostPairCallback = ghostPairCallback; | |||
| } | |||
| virtual void sortOverlappingPairs(btDispatcher* dispatcher); | |||
| }; | |||
| ///btNullPairCache skips add/removal of overlapping pairs. Userful for benchmarking and unit testing. | |||
| class btNullPairCache : public btOverlappingPairCache | |||
| { | |||
| btBroadphasePairArray m_overlappingPairArray; | |||
| public: | |||
| virtual btBroadphasePair* getOverlappingPairArrayPtr() | |||
| { | |||
| return &m_overlappingPairArray[0]; | |||
| } | |||
| const btBroadphasePair* getOverlappingPairArrayPtr() const | |||
| { | |||
| return &m_overlappingPairArray[0]; | |||
| } | |||
| btBroadphasePairArray& getOverlappingPairArray() | |||
| { | |||
| return m_overlappingPairArray; | |||
| } | |||
| virtual void cleanOverlappingPair(btBroadphasePair& /*pair*/,btDispatcher* /*dispatcher*/) | |||
| { | |||
| } | |||
| virtual int getNumOverlappingPairs() const | |||
| { | |||
| return 0; | |||
| } | |||
| virtual void cleanProxyFromPairs(btBroadphaseProxy* /*proxy*/,btDispatcher* /*dispatcher*/) | |||
| { | |||
| } | |||
| virtual void setOverlapFilterCallback(btOverlapFilterCallback* /*callback*/) | |||
| { | |||
| } | |||
| virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* /*dispatcher*/) | |||
| { | |||
| } | |||
| virtual btBroadphasePair* findPair(btBroadphaseProxy* /*proxy0*/, btBroadphaseProxy* /*proxy1*/) | |||
| { | |||
| return 0; | |||
| } | |||
| virtual bool hasDeferredRemoval() | |||
| { | |||
| return true; | |||
| } | |||
| virtual void setInternalGhostPairCallback(btOverlappingPairCallback* /* ghostPairCallback */) | |||
| { | |||
| } | |||
| virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* /*proxy0*/,btBroadphaseProxy* /*proxy1*/) | |||
| { | |||
| return 0; | |||
| } | |||
| virtual void* removeOverlappingPair(btBroadphaseProxy* /*proxy0*/,btBroadphaseProxy* /*proxy1*/,btDispatcher* /*dispatcher*/) | |||
| { | |||
| return 0; | |||
| } | |||
| virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* /*proxy0*/,btDispatcher* /*dispatcher*/) | |||
| { | |||
| } | |||
| virtual void sortOverlappingPairs(btDispatcher* dispatcher) | |||
| { | |||
| (void) dispatcher; | |||
| } | |||
| }; | |||
| #endif //BT_OVERLAPPING_PAIR_CACHE_H | |||
| @@ -0,0 +1,40 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef OVERLAPPING_PAIR_CALLBACK_H | |||
| #define OVERLAPPING_PAIR_CALLBACK_H | |||
| class btDispatcher; | |||
| struct btBroadphasePair; | |||
| ///The btOverlappingPairCallback class is an additional optional broadphase user callback for adding/removing overlapping pairs, similar interface to btOverlappingPairCache. | |||
| class btOverlappingPairCallback | |||
| { | |||
| public: | |||
| virtual ~btOverlappingPairCallback() | |||
| { | |||
| } | |||
| virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) = 0; | |||
| virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher) = 0; | |||
| virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy0,btDispatcher* dispatcher) = 0; | |||
| }; | |||
| #endif //OVERLAPPING_PAIR_CALLBACK_H | |||
| @@ -0,0 +1,579 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_QUANTIZED_BVH_H | |||
| #define BT_QUANTIZED_BVH_H | |||
| class btSerializer; | |||
| //#define DEBUG_CHECK_DEQUANTIZATION 1 | |||
| #ifdef DEBUG_CHECK_DEQUANTIZATION | |||
| #ifdef __SPU__ | |||
| #define printf spu_printf | |||
| #endif //__SPU__ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #endif //DEBUG_CHECK_DEQUANTIZATION | |||
| #include "LinearMath/btVector3.h" | |||
| #include "LinearMath/btAlignedAllocator.h" | |||
| #ifdef BT_USE_DOUBLE_PRECISION | |||
| #define btQuantizedBvhData btQuantizedBvhDoubleData | |||
| #define btOptimizedBvhNodeData btOptimizedBvhNodeDoubleData | |||
| #define btQuantizedBvhDataName "btQuantizedBvhDoubleData" | |||
| #else | |||
| #define btQuantizedBvhData btQuantizedBvhFloatData | |||
| #define btOptimizedBvhNodeData btOptimizedBvhNodeFloatData | |||
| #define btQuantizedBvhDataName "btQuantizedBvhFloatData" | |||
| #endif | |||
| //http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrf__m128.asp | |||
| //Note: currently we have 16 bytes per quantized node | |||
| #define MAX_SUBTREE_SIZE_IN_BYTES 2048 | |||
| // 10 gives the potential for 1024 parts, with at most 2^21 (2097152) (minus one | |||
| // actually) triangles each (since the sign bit is reserved | |||
| #define MAX_NUM_PARTS_IN_BITS 10 | |||
| ///btQuantizedBvhNode is a compressed aabb node, 16 bytes. | |||
| ///Node can be used for leafnode or internal node. Leafnodes can point to 32-bit triangle index (non-negative range). | |||
| ATTRIBUTE_ALIGNED16 (struct) btQuantizedBvhNode | |||
| { | |||
| BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
| //12 bytes | |||
| unsigned short int m_quantizedAabbMin[3]; | |||
| unsigned short int m_quantizedAabbMax[3]; | |||
| //4 bytes | |||
| int m_escapeIndexOrTriangleIndex; | |||
| bool isLeafNode() const | |||
| { | |||
| //skipindex is negative (internal node), triangleindex >=0 (leafnode) | |||
| return (m_escapeIndexOrTriangleIndex >= 0); | |||
| } | |||
| int getEscapeIndex() const | |||
| { | |||
| btAssert(!isLeafNode()); | |||
| return -m_escapeIndexOrTriangleIndex; | |||
| } | |||
| int getTriangleIndex() const | |||
| { | |||
| btAssert(isLeafNode()); | |||
| // Get only the lower bits where the triangle index is stored | |||
| return (m_escapeIndexOrTriangleIndex&~((~0)<<(31-MAX_NUM_PARTS_IN_BITS))); | |||
| } | |||
| int getPartId() const | |||
| { | |||
| btAssert(isLeafNode()); | |||
| // Get only the highest bits where the part index is stored | |||
| return (m_escapeIndexOrTriangleIndex>>(31-MAX_NUM_PARTS_IN_BITS)); | |||
| } | |||
| } | |||
| ; | |||
| /// btOptimizedBvhNode contains both internal and leaf node information. | |||
| /// Total node size is 44 bytes / node. You can use the compressed version of 16 bytes. | |||
| ATTRIBUTE_ALIGNED16 (struct) btOptimizedBvhNode | |||
| { | |||
| BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
| //32 bytes | |||
| btVector3 m_aabbMinOrg; | |||
| btVector3 m_aabbMaxOrg; | |||
| //4 | |||
| int m_escapeIndex; | |||
| //8 | |||
| //for child nodes | |||
| int m_subPart; | |||
| int m_triangleIndex; | |||
| //pad the size to 64 bytes | |||
| char m_padding[20]; | |||
| }; | |||
| ///btBvhSubtreeInfo provides info to gather a subtree of limited size | |||
| ATTRIBUTE_ALIGNED16(class) btBvhSubtreeInfo | |||
| { | |||
| public: | |||
| BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
| //12 bytes | |||
| unsigned short int m_quantizedAabbMin[3]; | |||
| unsigned short int m_quantizedAabbMax[3]; | |||
| //4 bytes, points to the root of the subtree | |||
| int m_rootNodeIndex; | |||
| //4 bytes | |||
| int m_subtreeSize; | |||
| int m_padding[3]; | |||
| btBvhSubtreeInfo() | |||
| { | |||
| //memset(&m_padding[0], 0, sizeof(m_padding)); | |||
| } | |||
| void setAabbFromQuantizeNode(const btQuantizedBvhNode& quantizedNode) | |||
| { | |||
| m_quantizedAabbMin[0] = quantizedNode.m_quantizedAabbMin[0]; | |||
| m_quantizedAabbMin[1] = quantizedNode.m_quantizedAabbMin[1]; | |||
| m_quantizedAabbMin[2] = quantizedNode.m_quantizedAabbMin[2]; | |||
| m_quantizedAabbMax[0] = quantizedNode.m_quantizedAabbMax[0]; | |||
| m_quantizedAabbMax[1] = quantizedNode.m_quantizedAabbMax[1]; | |||
| m_quantizedAabbMax[2] = quantizedNode.m_quantizedAabbMax[2]; | |||
| } | |||
| } | |||
| ; | |||
| class btNodeOverlapCallback | |||
| { | |||
| public: | |||
| virtual ~btNodeOverlapCallback() {}; | |||
| virtual void processNode(int subPart, int triangleIndex) = 0; | |||
| }; | |||
| #include "LinearMath/btAlignedAllocator.h" | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| ///for code readability: | |||
| typedef btAlignedObjectArray<btOptimizedBvhNode> NodeArray; | |||
| typedef btAlignedObjectArray<btQuantizedBvhNode> QuantizedNodeArray; | |||
| typedef btAlignedObjectArray<btBvhSubtreeInfo> BvhSubtreeInfoArray; | |||
| ///The btQuantizedBvh class stores an AABB tree that can be quickly traversed on CPU and Cell SPU. | |||
| ///It is used by the btBvhTriangleMeshShape as midphase, and by the btMultiSapBroadphase. | |||
| ///It is recommended to use quantization for better performance and lower memory requirements. | |||
| ATTRIBUTE_ALIGNED16(class) btQuantizedBvh | |||
| { | |||
| public: | |||
| enum btTraversalMode | |||
| { | |||
| TRAVERSAL_STACKLESS = 0, | |||
| TRAVERSAL_STACKLESS_CACHE_FRIENDLY, | |||
| TRAVERSAL_RECURSIVE | |||
| }; | |||
| protected: | |||
| btVector3 m_bvhAabbMin; | |||
| btVector3 m_bvhAabbMax; | |||
| btVector3 m_bvhQuantization; | |||
| int m_bulletVersion; //for serialization versioning. It could also be used to detect endianess. | |||
| int m_curNodeIndex; | |||
| //quantization data | |||
| bool m_useQuantization; | |||
| NodeArray m_leafNodes; | |||
| NodeArray m_contiguousNodes; | |||
| QuantizedNodeArray m_quantizedLeafNodes; | |||
| QuantizedNodeArray m_quantizedContiguousNodes; | |||
| btTraversalMode m_traversalMode; | |||
| BvhSubtreeInfoArray m_SubtreeHeaders; | |||
| //This is only used for serialization so we don't have to add serialization directly to btAlignedObjectArray | |||
| mutable int m_subtreeHeaderCount; | |||
| ///two versions, one for quantized and normal nodes. This allows code-reuse while maintaining readability (no template/macro!) | |||
| ///this might be refactored into a virtual, it is usually not calculated at run-time | |||
| void setInternalNodeAabbMin(int nodeIndex, const btVector3& aabbMin) | |||
| { | |||
| if (m_useQuantization) | |||
| { | |||
| quantize(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] ,aabbMin,0); | |||
| } else | |||
| { | |||
| m_contiguousNodes[nodeIndex].m_aabbMinOrg = aabbMin; | |||
| } | |||
| } | |||
| void setInternalNodeAabbMax(int nodeIndex,const btVector3& aabbMax) | |||
| { | |||
| if (m_useQuantization) | |||
| { | |||
| quantize(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0],aabbMax,1); | |||
| } else | |||
| { | |||
| m_contiguousNodes[nodeIndex].m_aabbMaxOrg = aabbMax; | |||
| } | |||
| } | |||
| btVector3 getAabbMin(int nodeIndex) const | |||
| { | |||
| if (m_useQuantization) | |||
| { | |||
| return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMin[0]); | |||
| } | |||
| //non-quantized | |||
| return m_leafNodes[nodeIndex].m_aabbMinOrg; | |||
| } | |||
| btVector3 getAabbMax(int nodeIndex) const | |||
| { | |||
| if (m_useQuantization) | |||
| { | |||
| return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMax[0]); | |||
| } | |||
| //non-quantized | |||
| return m_leafNodes[nodeIndex].m_aabbMaxOrg; | |||
| } | |||
| void setInternalNodeEscapeIndex(int nodeIndex, int escapeIndex) | |||
| { | |||
| if (m_useQuantization) | |||
| { | |||
| m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = -escapeIndex; | |||
| } | |||
| else | |||
| { | |||
| m_contiguousNodes[nodeIndex].m_escapeIndex = escapeIndex; | |||
| } | |||
| } | |||
| void mergeInternalNodeAabb(int nodeIndex,const btVector3& newAabbMin,const btVector3& newAabbMax) | |||
| { | |||
| if (m_useQuantization) | |||
| { | |||
| unsigned short int quantizedAabbMin[3]; | |||
| unsigned short int quantizedAabbMax[3]; | |||
| quantize(quantizedAabbMin,newAabbMin,0); | |||
| quantize(quantizedAabbMax,newAabbMax,1); | |||
| for (int i=0;i<3;i++) | |||
| { | |||
| if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] > quantizedAabbMin[i]) | |||
| m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] = quantizedAabbMin[i]; | |||
| if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] < quantizedAabbMax[i]) | |||
| m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] = quantizedAabbMax[i]; | |||
| } | |||
| } else | |||
| { | |||
| //non-quantized | |||
| m_contiguousNodes[nodeIndex].m_aabbMinOrg.setMin(newAabbMin); | |||
| m_contiguousNodes[nodeIndex].m_aabbMaxOrg.setMax(newAabbMax); | |||
| } | |||
| } | |||
| void swapLeafNodes(int firstIndex,int secondIndex); | |||
| void assignInternalNodeFromLeafNode(int internalNode,int leafNodeIndex); | |||
| protected: | |||
| void buildTree (int startIndex,int endIndex); | |||
| int calcSplittingAxis(int startIndex,int endIndex); | |||
| int sortAndCalcSplittingIndex(int startIndex,int endIndex,int splitAxis); | |||
| void walkStacklessTree(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const; | |||
| void walkStacklessQuantizedTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex,int endNodeIndex) const; | |||
| void walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,int startNodeIndex,int endNodeIndex) const; | |||
| void walkStacklessTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex,int endNodeIndex) const; | |||
| ///tree traversal designed for small-memory processors like PS3 SPU | |||
| void walkStacklessQuantizedTreeCacheFriendly(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const; | |||
| ///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal | |||
| void walkRecursiveQuantizedTreeAgainstQueryAabb(const btQuantizedBvhNode* currentNode,btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const; | |||
| ///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal | |||
| void walkRecursiveQuantizedTreeAgainstQuantizedTree(const btQuantizedBvhNode* treeNodeA,const btQuantizedBvhNode* treeNodeB,btNodeOverlapCallback* nodeCallback) const; | |||
| void updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex); | |||
| public: | |||
| BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
| btQuantizedBvh(); | |||
| virtual ~btQuantizedBvh(); | |||
| ///***************************************** expert/internal use only ************************* | |||
| void setQuantizationValues(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,btScalar quantizationMargin=btScalar(1.0)); | |||
| QuantizedNodeArray& getLeafNodeArray() { return m_quantizedLeafNodes; } | |||
| ///buildInternal is expert use only: assumes that setQuantizationValues and LeafNodeArray are initialized | |||
| void buildInternal(); | |||
| ///***************************************** expert/internal use only ************************* | |||
| void reportAabbOverlappingNodex(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const; | |||
| void reportRayOverlappingNodex (btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget) const; | |||
| void reportBoxCastOverlappingNodex(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin,const btVector3& aabbMax) const; | |||
| SIMD_FORCE_INLINE void quantize(unsigned short* out, const btVector3& point,int isMax) const | |||
| { | |||
| btAssert(m_useQuantization); | |||
| btAssert(point.getX() <= m_bvhAabbMax.getX()); | |||
| btAssert(point.getY() <= m_bvhAabbMax.getY()); | |||
| btAssert(point.getZ() <= m_bvhAabbMax.getZ()); | |||
| btAssert(point.getX() >= m_bvhAabbMin.getX()); | |||
| btAssert(point.getY() >= m_bvhAabbMin.getY()); | |||
| btAssert(point.getZ() >= m_bvhAabbMin.getZ()); | |||
| btVector3 v = (point - m_bvhAabbMin) * m_bvhQuantization; | |||
| ///Make sure rounding is done in a way that unQuantize(quantizeWithClamp(...)) is conservative | |||
| ///end-points always set the first bit, so that they are sorted properly (so that neighbouring AABBs overlap properly) | |||
| ///@todo: double-check this | |||
| if (isMax) | |||
| { | |||
| out[0] = (unsigned short) (((unsigned short)(v.getX()+btScalar(1.)) | 1)); | |||
| out[1] = (unsigned short) (((unsigned short)(v.getY()+btScalar(1.)) | 1)); | |||
| out[2] = (unsigned short) (((unsigned short)(v.getZ()+btScalar(1.)) | 1)); | |||
| } else | |||
| { | |||
| out[0] = (unsigned short) (((unsigned short)(v.getX()) & 0xfffe)); | |||
| out[1] = (unsigned short) (((unsigned short)(v.getY()) & 0xfffe)); | |||
| out[2] = (unsigned short) (((unsigned short)(v.getZ()) & 0xfffe)); | |||
| } | |||
| #ifdef DEBUG_CHECK_DEQUANTIZATION | |||
| btVector3 newPoint = unQuantize(out); | |||
| if (isMax) | |||
| { | |||
| if (newPoint.getX() < point.getX()) | |||
| { | |||
| printf("unconservative X, diffX = %f, oldX=%f,newX=%f\n",newPoint.getX()-point.getX(), newPoint.getX(),point.getX()); | |||
| } | |||
| if (newPoint.getY() < point.getY()) | |||
| { | |||
| printf("unconservative Y, diffY = %f, oldY=%f,newY=%f\n",newPoint.getY()-point.getY(), newPoint.getY(),point.getY()); | |||
| } | |||
| if (newPoint.getZ() < point.getZ()) | |||
| { | |||
| printf("unconservative Z, diffZ = %f, oldZ=%f,newZ=%f\n",newPoint.getZ()-point.getZ(), newPoint.getZ(),point.getZ()); | |||
| } | |||
| } else | |||
| { | |||
| if (newPoint.getX() > point.getX()) | |||
| { | |||
| printf("unconservative X, diffX = %f, oldX=%f,newX=%f\n",newPoint.getX()-point.getX(), newPoint.getX(),point.getX()); | |||
| } | |||
| if (newPoint.getY() > point.getY()) | |||
| { | |||
| printf("unconservative Y, diffY = %f, oldY=%f,newY=%f\n",newPoint.getY()-point.getY(), newPoint.getY(),point.getY()); | |||
| } | |||
| if (newPoint.getZ() > point.getZ()) | |||
| { | |||
| printf("unconservative Z, diffZ = %f, oldZ=%f,newZ=%f\n",newPoint.getZ()-point.getZ(), newPoint.getZ(),point.getZ()); | |||
| } | |||
| } | |||
| #endif //DEBUG_CHECK_DEQUANTIZATION | |||
| } | |||
| SIMD_FORCE_INLINE void quantizeWithClamp(unsigned short* out, const btVector3& point2,int isMax) const | |||
| { | |||
| btAssert(m_useQuantization); | |||
| btVector3 clampedPoint(point2); | |||
| clampedPoint.setMax(m_bvhAabbMin); | |||
| clampedPoint.setMin(m_bvhAabbMax); | |||
| quantize(out,clampedPoint,isMax); | |||
| } | |||
| SIMD_FORCE_INLINE btVector3 unQuantize(const unsigned short* vecIn) const | |||
| { | |||
| btVector3 vecOut; | |||
| vecOut.setValue( | |||
| (btScalar)(vecIn[0]) / (m_bvhQuantization.getX()), | |||
| (btScalar)(vecIn[1]) / (m_bvhQuantization.getY()), | |||
| (btScalar)(vecIn[2]) / (m_bvhQuantization.getZ())); | |||
| vecOut += m_bvhAabbMin; | |||
| return vecOut; | |||
| } | |||
| ///setTraversalMode let's you choose between stackless, recursive or stackless cache friendly tree traversal. Note this is only implemented for quantized trees. | |||
| void setTraversalMode(btTraversalMode traversalMode) | |||
| { | |||
| m_traversalMode = traversalMode; | |||
| } | |||
| SIMD_FORCE_INLINE QuantizedNodeArray& getQuantizedNodeArray() | |||
| { | |||
| return m_quantizedContiguousNodes; | |||
| } | |||
| SIMD_FORCE_INLINE BvhSubtreeInfoArray& getSubtreeInfoArray() | |||
| { | |||
| return m_SubtreeHeaders; | |||
| } | |||
| //////////////////////////////////////////////////////////////////// | |||
| /////Calculate space needed to store BVH for serialization | |||
| unsigned calculateSerializeBufferSize() const; | |||
| /// Data buffer MUST be 16 byte aligned | |||
| virtual bool serialize(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian) const; | |||
| ///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place' | |||
| static btQuantizedBvh *deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian); | |||
| static unsigned int getAlignmentSerializationPadding(); | |||
| ////////////////////////////////////////////////////////////////////// | |||
| virtual int calculateSerializeBufferSizeNew() const; | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
| virtual void deSerializeFloat(struct btQuantizedBvhFloatData& quantizedBvhFloatData); | |||
| virtual void deSerializeDouble(struct btQuantizedBvhDoubleData& quantizedBvhDoubleData); | |||
| //////////////////////////////////////////////////////////////////// | |||
| SIMD_FORCE_INLINE bool isQuantized() | |||
| { | |||
| return m_useQuantization; | |||
| } | |||
| private: | |||
| // Special "copy" constructor that allows for in-place deserialization | |||
| // Prevents btVector3's default constructor from being called, but doesn't inialize much else | |||
| // ownsMemory should most likely be false if deserializing, and if you are not, don't call this (it also changes the function signature, which we need) | |||
| btQuantizedBvh(btQuantizedBvh &other, bool ownsMemory); | |||
| } | |||
| ; | |||
| struct btBvhSubtreeInfoData | |||
| { | |||
| int m_rootNodeIndex; | |||
| int m_subtreeSize; | |||
| unsigned short m_quantizedAabbMin[3]; | |||
| unsigned short m_quantizedAabbMax[3]; | |||
| }; | |||
| struct btOptimizedBvhNodeFloatData | |||
| { | |||
| btVector3FloatData m_aabbMinOrg; | |||
| btVector3FloatData m_aabbMaxOrg; | |||
| int m_escapeIndex; | |||
| int m_subPart; | |||
| int m_triangleIndex; | |||
| char m_pad[4]; | |||
| }; | |||
| struct btOptimizedBvhNodeDoubleData | |||
| { | |||
| btVector3DoubleData m_aabbMinOrg; | |||
| btVector3DoubleData m_aabbMaxOrg; | |||
| int m_escapeIndex; | |||
| int m_subPart; | |||
| int m_triangleIndex; | |||
| char m_pad[4]; | |||
| }; | |||
| struct btQuantizedBvhNodeData | |||
| { | |||
| unsigned short m_quantizedAabbMin[3]; | |||
| unsigned short m_quantizedAabbMax[3]; | |||
| int m_escapeIndexOrTriangleIndex; | |||
| }; | |||
| struct btQuantizedBvhFloatData | |||
| { | |||
| btVector3FloatData m_bvhAabbMin; | |||
| btVector3FloatData m_bvhAabbMax; | |||
| btVector3FloatData m_bvhQuantization; | |||
| int m_curNodeIndex; | |||
| int m_useQuantization; | |||
| int m_numContiguousLeafNodes; | |||
| int m_numQuantizedContiguousNodes; | |||
| btOptimizedBvhNodeFloatData *m_contiguousNodesPtr; | |||
| btQuantizedBvhNodeData *m_quantizedContiguousNodesPtr; | |||
| btBvhSubtreeInfoData *m_subTreeInfoPtr; | |||
| int m_traversalMode; | |||
| int m_numSubtreeHeaders; | |||
| }; | |||
| struct btQuantizedBvhDoubleData | |||
| { | |||
| btVector3DoubleData m_bvhAabbMin; | |||
| btVector3DoubleData m_bvhAabbMax; | |||
| btVector3DoubleData m_bvhQuantization; | |||
| int m_curNodeIndex; | |||
| int m_useQuantization; | |||
| int m_numContiguousLeafNodes; | |||
| int m_numQuantizedContiguousNodes; | |||
| btOptimizedBvhNodeDoubleData *m_contiguousNodesPtr; | |||
| btQuantizedBvhNodeData *m_quantizedContiguousNodesPtr; | |||
| int m_traversalMode; | |||
| int m_numSubtreeHeaders; | |||
| btBvhSubtreeInfoData *m_subTreeInfoPtr; | |||
| }; | |||
| SIMD_FORCE_INLINE int btQuantizedBvh::calculateSerializeBufferSizeNew() const | |||
| { | |||
| return sizeof(btQuantizedBvhData); | |||
| } | |||
| #endif //BT_QUANTIZED_BVH_H | |||
| @@ -0,0 +1,349 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btSimpleBroadphase.h" | |||
| #include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
| #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" | |||
| #include "LinearMath/btVector3.h" | |||
| #include "LinearMath/btTransform.h" | |||
| #include "LinearMath/btMatrix3x3.h" | |||
| #include "LinearMath/btAabbUtil2.h" | |||
| #include <new> | |||
| extern int gOverlappingPairs; | |||
| void btSimpleBroadphase::validate() | |||
| { | |||
| for (int i=0;i<m_numHandles;i++) | |||
| { | |||
| for (int j=i+1;j<m_numHandles;j++) | |||
| { | |||
| btAssert(&m_pHandles[i] != &m_pHandles[j]); | |||
| } | |||
| } | |||
| } | |||
| btSimpleBroadphase::btSimpleBroadphase(int maxProxies, btOverlappingPairCache* overlappingPairCache) | |||
| :m_pairCache(overlappingPairCache), | |||
| m_ownsPairCache(false), | |||
| m_invalidPair(0) | |||
| { | |||
| if (!overlappingPairCache) | |||
| { | |||
| void* mem = btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16); | |||
| m_pairCache = new (mem)btHashedOverlappingPairCache(); | |||
| m_ownsPairCache = true; | |||
| } | |||
| // allocate handles buffer and put all handles on free list | |||
| m_pHandlesRawPtr = btAlignedAlloc(sizeof(btSimpleBroadphaseProxy)*maxProxies,16); | |||
| m_pHandles = new(m_pHandlesRawPtr) btSimpleBroadphaseProxy[maxProxies]; | |||
| m_maxHandles = maxProxies; | |||
| m_numHandles = 0; | |||
| m_firstFreeHandle = 0; | |||
| m_LastHandleIndex = -1; | |||
| { | |||
| for (int i = m_firstFreeHandle; i < maxProxies; i++) | |||
| { | |||
| m_pHandles[i].SetNextFree(i + 1); | |||
| m_pHandles[i].m_uniqueId = i+2;//any UID will do, we just avoid too trivial values (0,1) for debugging purposes | |||
| } | |||
| m_pHandles[maxProxies - 1].SetNextFree(0); | |||
| } | |||
| } | |||
| btSimpleBroadphase::~btSimpleBroadphase() | |||
| { | |||
| btAlignedFree(m_pHandlesRawPtr); | |||
| if (m_ownsPairCache) | |||
| { | |||
| m_pairCache->~btOverlappingPairCache(); | |||
| btAlignedFree(m_pairCache); | |||
| } | |||
| } | |||
| btBroadphaseProxy* btSimpleBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* /*dispatcher*/,void* multiSapProxy) | |||
| { | |||
| if (m_numHandles >= m_maxHandles) | |||
| { | |||
| btAssert(0); | |||
| return 0; //should never happen, but don't let the game crash ;-) | |||
| } | |||
| btAssert(aabbMin[0]<= aabbMax[0] && aabbMin[1]<= aabbMax[1] && aabbMin[2]<= aabbMax[2]); | |||
| int newHandleIndex = allocHandle(); | |||
| btSimpleBroadphaseProxy* proxy = new (&m_pHandles[newHandleIndex])btSimpleBroadphaseProxy(aabbMin,aabbMax,shapeType,userPtr,collisionFilterGroup,collisionFilterMask,multiSapProxy); | |||
| return proxy; | |||
| } | |||
| class RemovingOverlapCallback : public btOverlapCallback | |||
| { | |||
| protected: | |||
| virtual bool processOverlap(btBroadphasePair& pair) | |||
| { | |||
| (void)pair; | |||
| btAssert(0); | |||
| return false; | |||
| } | |||
| }; | |||
| class RemovePairContainingProxy | |||
| { | |||
| btBroadphaseProxy* m_targetProxy; | |||
| public: | |||
| virtual ~RemovePairContainingProxy() | |||
| { | |||
| } | |||
| protected: | |||
| virtual bool processOverlap(btBroadphasePair& pair) | |||
| { | |||
| btSimpleBroadphaseProxy* proxy0 = static_cast<btSimpleBroadphaseProxy*>(pair.m_pProxy0); | |||
| btSimpleBroadphaseProxy* proxy1 = static_cast<btSimpleBroadphaseProxy*>(pair.m_pProxy1); | |||
| return ((m_targetProxy == proxy0 || m_targetProxy == proxy1)); | |||
| }; | |||
| }; | |||
| void btSimpleBroadphase::destroyProxy(btBroadphaseProxy* proxyOrg,btDispatcher* dispatcher) | |||
| { | |||
| btSimpleBroadphaseProxy* proxy0 = static_cast<btSimpleBroadphaseProxy*>(proxyOrg); | |||
| freeHandle(proxy0); | |||
| m_pairCache->removeOverlappingPairsContainingProxy(proxyOrg,dispatcher); | |||
| //validate(); | |||
| } | |||
| void btSimpleBroadphase::getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const | |||
| { | |||
| const btSimpleBroadphaseProxy* sbp = getSimpleProxyFromProxy(proxy); | |||
| aabbMin = sbp->m_aabbMin; | |||
| aabbMax = sbp->m_aabbMax; | |||
| } | |||
| void btSimpleBroadphase::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* /*dispatcher*/) | |||
| { | |||
| btSimpleBroadphaseProxy* sbp = getSimpleProxyFromProxy(proxy); | |||
| sbp->m_aabbMin = aabbMin; | |||
| sbp->m_aabbMax = aabbMax; | |||
| } | |||
| void btSimpleBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin,const btVector3& aabbMax) | |||
| { | |||
| for (int i=0; i <= m_LastHandleIndex; i++) | |||
| { | |||
| btSimpleBroadphaseProxy* proxy = &m_pHandles[i]; | |||
| if(!proxy->m_clientObject) | |||
| { | |||
| continue; | |||
| } | |||
| rayCallback.process(proxy); | |||
| } | |||
| } | |||
| void btSimpleBroadphase::aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) | |||
| { | |||
| for (int i=0; i <= m_LastHandleIndex; i++) | |||
| { | |||
| btSimpleBroadphaseProxy* proxy = &m_pHandles[i]; | |||
| if(!proxy->m_clientObject) | |||
| { | |||
| continue; | |||
| } | |||
| if (TestAabbAgainstAabb2(aabbMin,aabbMax,proxy->m_aabbMin,proxy->m_aabbMax)) | |||
| { | |||
| callback.process(proxy); | |||
| } | |||
| } | |||
| } | |||
| bool btSimpleBroadphase::aabbOverlap(btSimpleBroadphaseProxy* proxy0,btSimpleBroadphaseProxy* proxy1) | |||
| { | |||
| return proxy0->m_aabbMin[0] <= proxy1->m_aabbMax[0] && proxy1->m_aabbMin[0] <= proxy0->m_aabbMax[0] && | |||
| proxy0->m_aabbMin[1] <= proxy1->m_aabbMax[1] && proxy1->m_aabbMin[1] <= proxy0->m_aabbMax[1] && | |||
| proxy0->m_aabbMin[2] <= proxy1->m_aabbMax[2] && proxy1->m_aabbMin[2] <= proxy0->m_aabbMax[2]; | |||
| } | |||
| //then remove non-overlapping ones | |||
| class CheckOverlapCallback : public btOverlapCallback | |||
| { | |||
| public: | |||
| virtual bool processOverlap(btBroadphasePair& pair) | |||
| { | |||
| return (!btSimpleBroadphase::aabbOverlap(static_cast<btSimpleBroadphaseProxy*>(pair.m_pProxy0),static_cast<btSimpleBroadphaseProxy*>(pair.m_pProxy1))); | |||
| } | |||
| }; | |||
| void btSimpleBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) | |||
| { | |||
| //first check for new overlapping pairs | |||
| int i,j; | |||
| if (m_numHandles >= 0) | |||
| { | |||
| int new_largest_index = -1; | |||
| for (i=0; i <= m_LastHandleIndex; i++) | |||
| { | |||
| btSimpleBroadphaseProxy* proxy0 = &m_pHandles[i]; | |||
| if(!proxy0->m_clientObject) | |||
| { | |||
| continue; | |||
| } | |||
| new_largest_index = i; | |||
| for (j=i+1; j <= m_LastHandleIndex; j++) | |||
| { | |||
| btSimpleBroadphaseProxy* proxy1 = &m_pHandles[j]; | |||
| btAssert(proxy0 != proxy1); | |||
| if(!proxy1->m_clientObject) | |||
| { | |||
| continue; | |||
| } | |||
| btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0); | |||
| btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1); | |||
| if (aabbOverlap(p0,p1)) | |||
| { | |||
| if ( !m_pairCache->findPair(proxy0,proxy1)) | |||
| { | |||
| m_pairCache->addOverlappingPair(proxy0,proxy1); | |||
| } | |||
| } else | |||
| { | |||
| if (!m_pairCache->hasDeferredRemoval()) | |||
| { | |||
| if ( m_pairCache->findPair(proxy0,proxy1)) | |||
| { | |||
| m_pairCache->removeOverlappingPair(proxy0,proxy1,dispatcher); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| m_LastHandleIndex = new_largest_index; | |||
| if (m_ownsPairCache && m_pairCache->hasDeferredRemoval()) | |||
| { | |||
| btBroadphasePairArray& overlappingPairArray = m_pairCache->getOverlappingPairArray(); | |||
| //perform a sort, to find duplicates and to sort 'invalid' pairs to the end | |||
| overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); | |||
| overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); | |||
| m_invalidPair = 0; | |||
| btBroadphasePair previousPair; | |||
| previousPair.m_pProxy0 = 0; | |||
| previousPair.m_pProxy1 = 0; | |||
| previousPair.m_algorithm = 0; | |||
| for (i=0;i<overlappingPairArray.size();i++) | |||
| { | |||
| btBroadphasePair& pair = overlappingPairArray[i]; | |||
| bool isDuplicate = (pair == previousPair); | |||
| previousPair = pair; | |||
| bool needsRemoval = false; | |||
| if (!isDuplicate) | |||
| { | |||
| bool hasOverlap = testAabbOverlap(pair.m_pProxy0,pair.m_pProxy1); | |||
| if (hasOverlap) | |||
| { | |||
| needsRemoval = false;//callback->processOverlap(pair); | |||
| } else | |||
| { | |||
| needsRemoval = true; | |||
| } | |||
| } else | |||
| { | |||
| //remove duplicate | |||
| needsRemoval = true; | |||
| //should have no algorithm | |||
| btAssert(!pair.m_algorithm); | |||
| } | |||
| if (needsRemoval) | |||
| { | |||
| m_pairCache->cleanOverlappingPair(pair,dispatcher); | |||
| // m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); | |||
| // m_overlappingPairArray.pop_back(); | |||
| pair.m_pProxy0 = 0; | |||
| pair.m_pProxy1 = 0; | |||
| m_invalidPair++; | |||
| gOverlappingPairs--; | |||
| } | |||
| } | |||
| ///if you don't like to skip the invalid pairs in the array, execute following code: | |||
| #define CLEAN_INVALID_PAIRS 1 | |||
| #ifdef CLEAN_INVALID_PAIRS | |||
| //perform a sort, to sort 'invalid' pairs to the end | |||
| overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); | |||
| overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); | |||
| m_invalidPair = 0; | |||
| #endif//CLEAN_INVALID_PAIRS | |||
| } | |||
| } | |||
| } | |||
| bool btSimpleBroadphase::testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) | |||
| { | |||
| btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0); | |||
| btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1); | |||
| return aabbOverlap(p0,p1); | |||
| } | |||
| void btSimpleBroadphase::resetPool(btDispatcher* dispatcher) | |||
| { | |||
| //not yet | |||
| } | |||
| @@ -0,0 +1,171 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_SIMPLE_BROADPHASE_H | |||
| #define BT_SIMPLE_BROADPHASE_H | |||
| #include "btOverlappingPairCache.h" | |||
| struct btSimpleBroadphaseProxy : public btBroadphaseProxy | |||
| { | |||
| int m_nextFree; | |||
| // int m_handleId; | |||
| btSimpleBroadphaseProxy() {}; | |||
| btSimpleBroadphaseProxy(const btVector3& minpt,const btVector3& maxpt,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,void* multiSapProxy) | |||
| :btBroadphaseProxy(minpt,maxpt,userPtr,collisionFilterGroup,collisionFilterMask,multiSapProxy) | |||
| { | |||
| (void)shapeType; | |||
| } | |||
| SIMD_FORCE_INLINE void SetNextFree(int next) {m_nextFree = next;} | |||
| SIMD_FORCE_INLINE int GetNextFree() const {return m_nextFree;} | |||
| }; | |||
| ///The SimpleBroadphase is just a unit-test for btAxisSweep3, bt32BitAxisSweep3, or btDbvtBroadphase, so use those classes instead. | |||
| ///It is a brute force aabb culling broadphase based on O(n^2) aabb checks | |||
| class btSimpleBroadphase : public btBroadphaseInterface | |||
| { | |||
| protected: | |||
| int m_numHandles; // number of active handles | |||
| int m_maxHandles; // max number of handles | |||
| int m_LastHandleIndex; | |||
| btSimpleBroadphaseProxy* m_pHandles; // handles pool | |||
| void* m_pHandlesRawPtr; | |||
| int m_firstFreeHandle; // free handles list | |||
| int allocHandle() | |||
| { | |||
| btAssert(m_numHandles < m_maxHandles); | |||
| int freeHandle = m_firstFreeHandle; | |||
| m_firstFreeHandle = m_pHandles[freeHandle].GetNextFree(); | |||
| m_numHandles++; | |||
| if(freeHandle > m_LastHandleIndex) | |||
| { | |||
| m_LastHandleIndex = freeHandle; | |||
| } | |||
| return freeHandle; | |||
| } | |||
| void freeHandle(btSimpleBroadphaseProxy* proxy) | |||
| { | |||
| int handle = int(proxy-m_pHandles); | |||
| btAssert(handle >= 0 && handle < m_maxHandles); | |||
| if(handle == m_LastHandleIndex) | |||
| { | |||
| m_LastHandleIndex--; | |||
| } | |||
| proxy->SetNextFree(m_firstFreeHandle); | |||
| m_firstFreeHandle = handle; | |||
| proxy->m_clientObject = 0; | |||
| m_numHandles--; | |||
| } | |||
| btOverlappingPairCache* m_pairCache; | |||
| bool m_ownsPairCache; | |||
| int m_invalidPair; | |||
| inline btSimpleBroadphaseProxy* getSimpleProxyFromProxy(btBroadphaseProxy* proxy) | |||
| { | |||
| btSimpleBroadphaseProxy* proxy0 = static_cast<btSimpleBroadphaseProxy*>(proxy); | |||
| return proxy0; | |||
| } | |||
| inline const btSimpleBroadphaseProxy* getSimpleProxyFromProxy(btBroadphaseProxy* proxy) const | |||
| { | |||
| const btSimpleBroadphaseProxy* proxy0 = static_cast<const btSimpleBroadphaseProxy*>(proxy); | |||
| return proxy0; | |||
| } | |||
| ///reset broadphase internal structures, to ensure determinism/reproducability | |||
| virtual void resetPool(btDispatcher* dispatcher); | |||
| void validate(); | |||
| protected: | |||
| public: | |||
| btSimpleBroadphase(int maxProxies=16384,btOverlappingPairCache* overlappingPairCache=0); | |||
| virtual ~btSimpleBroadphase(); | |||
| static bool aabbOverlap(btSimpleBroadphaseProxy* proxy0,btSimpleBroadphaseProxy* proxy1); | |||
| virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy); | |||
| virtual void calculateOverlappingPairs(btDispatcher* dispatcher); | |||
| virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); | |||
| virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher); | |||
| virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; | |||
| virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0),const btVector3& aabbMax=btVector3(0,0,0)); | |||
| virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback); | |||
| btOverlappingPairCache* getOverlappingPairCache() | |||
| { | |||
| return m_pairCache; | |||
| } | |||
| const btOverlappingPairCache* getOverlappingPairCache() const | |||
| { | |||
| return m_pairCache; | |||
| } | |||
| bool testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); | |||
| ///getAabb returns the axis aligned bounding box in the 'global' coordinate frame | |||
| ///will add some transform later | |||
| virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const | |||
| { | |||
| aabbMin.setValue(-BT_LARGE_FLOAT,-BT_LARGE_FLOAT,-BT_LARGE_FLOAT); | |||
| aabbMax.setValue(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT); | |||
| } | |||
| virtual void printStats() | |||
| { | |||
| // printf("btSimpleBroadphase.h\n"); | |||
| // printf("numHandles = %d, maxHandles = %d\n",m_numHandles,m_maxHandles); | |||
| } | |||
| }; | |||
| #endif //BT_SIMPLE_BROADPHASE_H | |||
| @@ -0,0 +1,201 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "LinearMath/btScalar.h" | |||
| #include "SphereTriangleDetector.h" | |||
| #include "BulletCollision/CollisionShapes/btTriangleShape.h" | |||
| #include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
| SphereTriangleDetector::SphereTriangleDetector(btSphereShape* sphere,btTriangleShape* triangle,btScalar contactBreakingThreshold) | |||
| :m_sphere(sphere), | |||
| m_triangle(triangle), | |||
| m_contactBreakingThreshold(contactBreakingThreshold) | |||
| { | |||
| } | |||
| void SphereTriangleDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults) | |||
| { | |||
| (void)debugDraw; | |||
| const btTransform& transformA = input.m_transformA; | |||
| const btTransform& transformB = input.m_transformB; | |||
| btVector3 point,normal; | |||
| btScalar timeOfImpact = btScalar(1.); | |||
| btScalar depth = btScalar(0.); | |||
| // output.m_distance = btScalar(BT_LARGE_FLOAT); | |||
| //move sphere into triangle space | |||
| btTransform sphereInTr = transformB.inverseTimes(transformA); | |||
| if (collide(sphereInTr.getOrigin(),point,normal,depth,timeOfImpact,m_contactBreakingThreshold)) | |||
| { | |||
| if (swapResults) | |||
| { | |||
| btVector3 normalOnB = transformB.getBasis()*normal; | |||
| btVector3 normalOnA = -normalOnB; | |||
| btVector3 pointOnA = transformB*point+normalOnB*depth; | |||
| output.addContactPoint(normalOnA,pointOnA,depth); | |||
| } else | |||
| { | |||
| output.addContactPoint(transformB.getBasis()*normal,transformB*point,depth); | |||
| } | |||
| } | |||
| } | |||
| // See also geometrictools.com | |||
| // Basic idea: D = |p - (lo + t0*lv)| where t0 = lv . (p - lo) / lv . lv | |||
| btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest); | |||
| btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest) { | |||
| btVector3 diff = p - from; | |||
| btVector3 v = to - from; | |||
| btScalar t = v.dot(diff); | |||
| if (t > 0) { | |||
| btScalar dotVV = v.dot(v); | |||
| if (t < dotVV) { | |||
| t /= dotVV; | |||
| diff -= t*v; | |||
| } else { | |||
| t = 1; | |||
| diff -= v; | |||
| } | |||
| } else | |||
| t = 0; | |||
| nearest = from + t*v; | |||
| return diff.dot(diff); | |||
| } | |||
| bool SphereTriangleDetector::facecontains(const btVector3 &p,const btVector3* vertices,btVector3& normal) { | |||
| btVector3 lp(p); | |||
| btVector3 lnormal(normal); | |||
| return pointInTriangle(vertices, lnormal, &lp); | |||
| } | |||
| bool SphereTriangleDetector::collide(const btVector3& sphereCenter,btVector3 &point, btVector3& resultNormal, btScalar& depth, btScalar &timeOfImpact, btScalar contactBreakingThreshold) | |||
| { | |||
| const btVector3* vertices = &m_triangle->getVertexPtr(0); | |||
| btScalar radius = m_sphere->getRadius(); | |||
| btScalar radiusWithThreshold = radius + contactBreakingThreshold; | |||
| btVector3 normal = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]); | |||
| normal.normalize(); | |||
| btVector3 p1ToCentre = sphereCenter - vertices[0]; | |||
| btScalar distanceFromPlane = p1ToCentre.dot(normal); | |||
| if (distanceFromPlane < btScalar(0.)) | |||
| { | |||
| //triangle facing the other way | |||
| distanceFromPlane *= btScalar(-1.); | |||
| normal *= btScalar(-1.); | |||
| } | |||
| bool isInsideContactPlane = distanceFromPlane < radiusWithThreshold; | |||
| // Check for contact / intersection | |||
| bool hasContact = false; | |||
| btVector3 contactPoint; | |||
| if (isInsideContactPlane) { | |||
| if (facecontains(sphereCenter,vertices,normal)) { | |||
| // Inside the contact wedge - touches a point on the shell plane | |||
| hasContact = true; | |||
| contactPoint = sphereCenter - normal*distanceFromPlane; | |||
| } else { | |||
| // Could be inside one of the contact capsules | |||
| btScalar contactCapsuleRadiusSqr = radiusWithThreshold*radiusWithThreshold; | |||
| btVector3 nearestOnEdge; | |||
| for (int i = 0; i < m_triangle->getNumEdges(); i++) { | |||
| btVector3 pa; | |||
| btVector3 pb; | |||
| m_triangle->getEdge(i,pa,pb); | |||
| btScalar distanceSqr = SegmentSqrDistance(pa,pb,sphereCenter, nearestOnEdge); | |||
| if (distanceSqr < contactCapsuleRadiusSqr) { | |||
| // Yep, we're inside a capsule | |||
| hasContact = true; | |||
| contactPoint = nearestOnEdge; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| if (hasContact) { | |||
| btVector3 contactToCentre = sphereCenter - contactPoint; | |||
| btScalar distanceSqr = contactToCentre.length2(); | |||
| if (distanceSqr < radiusWithThreshold*radiusWithThreshold) | |||
| { | |||
| if (distanceSqr>SIMD_EPSILON) | |||
| { | |||
| btScalar distance = btSqrt(distanceSqr); | |||
| resultNormal = contactToCentre; | |||
| resultNormal.normalize(); | |||
| point = contactPoint; | |||
| depth = -(radius-distance); | |||
| } else | |||
| { | |||
| btScalar distance = 0.f; | |||
| resultNormal = normal; | |||
| point = contactPoint; | |||
| depth = -radius; | |||
| } | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| bool SphereTriangleDetector::pointInTriangle(const btVector3 vertices[], const btVector3 &normal, btVector3 *p ) | |||
| { | |||
| const btVector3* p1 = &vertices[0]; | |||
| const btVector3* p2 = &vertices[1]; | |||
| const btVector3* p3 = &vertices[2]; | |||
| btVector3 edge1( *p2 - *p1 ); | |||
| btVector3 edge2( *p3 - *p2 ); | |||
| btVector3 edge3( *p1 - *p3 ); | |||
| btVector3 p1_to_p( *p - *p1 ); | |||
| btVector3 p2_to_p( *p - *p2 ); | |||
| btVector3 p3_to_p( *p - *p3 ); | |||
| btVector3 edge1_normal( edge1.cross(normal)); | |||
| btVector3 edge2_normal( edge2.cross(normal)); | |||
| btVector3 edge3_normal( edge3.cross(normal)); | |||
| btScalar r1, r2, r3; | |||
| r1 = edge1_normal.dot( p1_to_p ); | |||
| r2 = edge2_normal.dot( p2_to_p ); | |||
| r3 = edge3_normal.dot( p3_to_p ); | |||
| if ( ( r1 > 0 && r2 > 0 && r3 > 0 ) || | |||
| ( r1 <= 0 && r2 <= 0 && r3 <= 0 ) ) | |||
| return true; | |||
| return false; | |||
| } | |||
| @@ -0,0 +1,51 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_SPHERE_TRIANGLE_DETECTOR_H | |||
| #define BT_SPHERE_TRIANGLE_DETECTOR_H | |||
| #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" | |||
| class btSphereShape; | |||
| class btTriangleShape; | |||
| /// sphere-triangle to match the btDiscreteCollisionDetectorInterface | |||
| struct SphereTriangleDetector : public btDiscreteCollisionDetectorInterface | |||
| { | |||
| virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults=false); | |||
| SphereTriangleDetector(btSphereShape* sphere,btTriangleShape* triangle, btScalar contactBreakingThreshold); | |||
| virtual ~SphereTriangleDetector() {}; | |||
| bool collide(const btVector3& sphereCenter,btVector3 &point, btVector3& resultNormal, btScalar& depth, btScalar &timeOfImpact, btScalar contactBreakingThreshold); | |||
| private: | |||
| bool pointInTriangle(const btVector3 vertices[], const btVector3 &normal, btVector3 *p ); | |||
| bool facecontains(const btVector3 &p,const btVector3* vertices,btVector3& normal); | |||
| btSphereShape* m_sphere; | |||
| btTriangleShape* m_triangle; | |||
| btScalar m_contactBreakingThreshold; | |||
| }; | |||
| #endif //BT_SPHERE_TRIANGLE_DETECTOR_H | |||
| @@ -0,0 +1,47 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btActivatingCollisionAlgorithm.h" | |||
| #include "btCollisionDispatcher.h" | |||
| #include "btCollisionObject.h" | |||
| btActivatingCollisionAlgorithm::btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci) | |||
| :btCollisionAlgorithm(ci) | |||
| //, | |||
| //m_colObj0(0), | |||
| //m_colObj1(0) | |||
| { | |||
| } | |||
| btActivatingCollisionAlgorithm::btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* colObj0,btCollisionObject* colObj1) | |||
| :btCollisionAlgorithm(ci) | |||
| //, | |||
| //m_colObj0(0), | |||
| //m_colObj1(0) | |||
| { | |||
| // if (ci.m_dispatcher1->needsCollision(colObj0,colObj1)) | |||
| // { | |||
| // m_colObj0 = colObj0; | |||
| // m_colObj1 = colObj1; | |||
| // | |||
| // m_colObj0->activate(); | |||
| // m_colObj1->activate(); | |||
| // } | |||
| } | |||
| btActivatingCollisionAlgorithm::~btActivatingCollisionAlgorithm() | |||
| { | |||
| // m_colObj0->activate(); | |||
| // m_colObj1->activate(); | |||
| } | |||
| @@ -0,0 +1,36 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef __BT_ACTIVATING_COLLISION_ALGORITHM_H | |||
| #define __BT_ACTIVATING_COLLISION_ALGORITHM_H | |||
| #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" | |||
| ///This class is not enabled yet (work-in-progress) to more aggressively activate objects. | |||
| class btActivatingCollisionAlgorithm : public btCollisionAlgorithm | |||
| { | |||
| // btCollisionObject* m_colObj0; | |||
| // btCollisionObject* m_colObj1; | |||
| public: | |||
| btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci); | |||
| btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* colObj0,btCollisionObject* colObj1); | |||
| virtual ~btActivatingCollisionAlgorithm(); | |||
| }; | |||
| #endif //__BT_ACTIVATING_COLLISION_ALGORITHM_H | |||
| @@ -0,0 +1,435 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| * The b2CollidePolygons routines are Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| ///btBox2dBox2dCollisionAlgorithm, with modified b2CollidePolygons routines from the Box2D library. | |||
| ///The modifications include: switching from b2Vec to btVector3, redefinition of b2Dot, b2Cross | |||
| #include "btBox2dBox2dCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
| #include "BulletCollision/CollisionShapes/btBoxShape.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| #include "BulletCollision/CollisionDispatch/btBoxBoxDetector.h" | |||
| #include "BulletCollision/CollisionShapes/btBox2dShape.h" | |||
| #define USE_PERSISTENT_CONTACTS 1 | |||
| btBox2dBox2dCollisionAlgorithm::btBox2dBox2dCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* obj0,btCollisionObject* obj1) | |||
| : btActivatingCollisionAlgorithm(ci,obj0,obj1), | |||
| m_ownManifold(false), | |||
| m_manifoldPtr(mf) | |||
| { | |||
| if (!m_manifoldPtr && m_dispatcher->needsCollision(obj0,obj1)) | |||
| { | |||
| m_manifoldPtr = m_dispatcher->getNewManifold(obj0,obj1); | |||
| m_ownManifold = true; | |||
| } | |||
| } | |||
| btBox2dBox2dCollisionAlgorithm::~btBox2dBox2dCollisionAlgorithm() | |||
| { | |||
| if (m_ownManifold) | |||
| { | |||
| if (m_manifoldPtr) | |||
| m_dispatcher->releaseManifold(m_manifoldPtr); | |||
| } | |||
| } | |||
| void b2CollidePolygons(btManifoldResult* manifold, const btBox2dShape* polyA, const btTransform& xfA, const btBox2dShape* polyB, const btTransform& xfB); | |||
| //#include <stdio.h> | |||
| void btBox2dBox2dCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| if (!m_manifoldPtr) | |||
| return; | |||
| btCollisionObject* col0 = body0; | |||
| btCollisionObject* col1 = body1; | |||
| btBox2dShape* box0 = (btBox2dShape*)col0->getCollisionShape(); | |||
| btBox2dShape* box1 = (btBox2dShape*)col1->getCollisionShape(); | |||
| resultOut->setPersistentManifold(m_manifoldPtr); | |||
| b2CollidePolygons(resultOut,box0,col0->getWorldTransform(),box1,col1->getWorldTransform()); | |||
| // refreshContactPoints is only necessary when using persistent contact points. otherwise all points are newly added | |||
| if (m_ownManifold) | |||
| { | |||
| resultOut->refreshContactPoints(); | |||
| } | |||
| } | |||
| btScalar btBox2dBox2dCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* /*body0*/,btCollisionObject* /*body1*/,const btDispatcherInfo& /*dispatchInfo*/,btManifoldResult* /*resultOut*/) | |||
| { | |||
| //not yet | |||
| return 1.f; | |||
| } | |||
| struct ClipVertex | |||
| { | |||
| btVector3 v; | |||
| int id; | |||
| //b2ContactID id; | |||
| //b2ContactID id; | |||
| }; | |||
| #define b2Dot(a,b) (a).dot(b) | |||
| #define b2Mul(a,b) (a)*(b) | |||
| #define b2MulT(a,b) (a).transpose()*(b) | |||
| #define b2Cross(a,b) (a).cross(b) | |||
| #define btCrossS(a,s) btVector3(s * a.getY(), -s * a.getX(),0.f) | |||
| int b2_maxManifoldPoints =2; | |||
| static int ClipSegmentToLine(ClipVertex vOut[2], ClipVertex vIn[2], | |||
| const btVector3& normal, btScalar offset) | |||
| { | |||
| // Start with no output points | |||
| int numOut = 0; | |||
| // Calculate the distance of end points to the line | |||
| btScalar distance0 = b2Dot(normal, vIn[0].v) - offset; | |||
| btScalar distance1 = b2Dot(normal, vIn[1].v) - offset; | |||
| // If the points are behind the plane | |||
| if (distance0 <= 0.0f) vOut[numOut++] = vIn[0]; | |||
| if (distance1 <= 0.0f) vOut[numOut++] = vIn[1]; | |||
| // If the points are on different sides of the plane | |||
| if (distance0 * distance1 < 0.0f) | |||
| { | |||
| // Find intersection point of edge and plane | |||
| btScalar interp = distance0 / (distance0 - distance1); | |||
| vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v); | |||
| if (distance0 > 0.0f) | |||
| { | |||
| vOut[numOut].id = vIn[0].id; | |||
| } | |||
| else | |||
| { | |||
| vOut[numOut].id = vIn[1].id; | |||
| } | |||
| ++numOut; | |||
| } | |||
| return numOut; | |||
| } | |||
| // Find the separation between poly1 and poly2 for a give edge normal on poly1. | |||
| static btScalar EdgeSeparation(const btBox2dShape* poly1, const btTransform& xf1, int edge1, | |||
| const btBox2dShape* poly2, const btTransform& xf2) | |||
| { | |||
| const btVector3* vertices1 = poly1->getVertices(); | |||
| const btVector3* normals1 = poly1->getNormals(); | |||
| int count2 = poly2->getVertexCount(); | |||
| const btVector3* vertices2 = poly2->getVertices(); | |||
| btAssert(0 <= edge1 && edge1 < poly1->getVertexCount()); | |||
| // Convert normal from poly1's frame into poly2's frame. | |||
| btVector3 normal1World = b2Mul(xf1.getBasis(), normals1[edge1]); | |||
| btVector3 normal1 = b2MulT(xf2.getBasis(), normal1World); | |||
| // Find support vertex on poly2 for -normal. | |||
| int index = 0; | |||
| btScalar minDot = BT_LARGE_FLOAT; | |||
| for (int i = 0; i < count2; ++i) | |||
| { | |||
| btScalar dot = b2Dot(vertices2[i], normal1); | |||
| if (dot < minDot) | |||
| { | |||
| minDot = dot; | |||
| index = i; | |||
| } | |||
| } | |||
| btVector3 v1 = b2Mul(xf1, vertices1[edge1]); | |||
| btVector3 v2 = b2Mul(xf2, vertices2[index]); | |||
| btScalar separation = b2Dot(v2 - v1, normal1World); | |||
| return separation; | |||
| } | |||
| // Find the max separation between poly1 and poly2 using edge normals from poly1. | |||
| static btScalar FindMaxSeparation(int* edgeIndex, | |||
| const btBox2dShape* poly1, const btTransform& xf1, | |||
| const btBox2dShape* poly2, const btTransform& xf2) | |||
| { | |||
| int count1 = poly1->getVertexCount(); | |||
| const btVector3* normals1 = poly1->getNormals(); | |||
| // Vector pointing from the centroid of poly1 to the centroid of poly2. | |||
| btVector3 d = b2Mul(xf2, poly2->getCentroid()) - b2Mul(xf1, poly1->getCentroid()); | |||
| btVector3 dLocal1 = b2MulT(xf1.getBasis(), d); | |||
| // Find edge normal on poly1 that has the largest projection onto d. | |||
| int edge = 0; | |||
| btScalar maxDot = -BT_LARGE_FLOAT; | |||
| for (int i = 0; i < count1; ++i) | |||
| { | |||
| btScalar dot = b2Dot(normals1[i], dLocal1); | |||
| if (dot > maxDot) | |||
| { | |||
| maxDot = dot; | |||
| edge = i; | |||
| } | |||
| } | |||
| // Get the separation for the edge normal. | |||
| btScalar s = EdgeSeparation(poly1, xf1, edge, poly2, xf2); | |||
| if (s > 0.0f) | |||
| { | |||
| return s; | |||
| } | |||
| // Check the separation for the previous edge normal. | |||
| int prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; | |||
| btScalar sPrev = EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); | |||
| if (sPrev > 0.0f) | |||
| { | |||
| return sPrev; | |||
| } | |||
| // Check the separation for the next edge normal. | |||
| int nextEdge = edge + 1 < count1 ? edge + 1 : 0; | |||
| btScalar sNext = EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); | |||
| if (sNext > 0.0f) | |||
| { | |||
| return sNext; | |||
| } | |||
| // Find the best edge and the search direction. | |||
| int bestEdge; | |||
| btScalar bestSeparation; | |||
| int increment; | |||
| if (sPrev > s && sPrev > sNext) | |||
| { | |||
| increment = -1; | |||
| bestEdge = prevEdge; | |||
| bestSeparation = sPrev; | |||
| } | |||
| else if (sNext > s) | |||
| { | |||
| increment = 1; | |||
| bestEdge = nextEdge; | |||
| bestSeparation = sNext; | |||
| } | |||
| else | |||
| { | |||
| *edgeIndex = edge; | |||
| return s; | |||
| } | |||
| // Perform a local search for the best edge normal. | |||
| for ( ; ; ) | |||
| { | |||
| if (increment == -1) | |||
| edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; | |||
| else | |||
| edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0; | |||
| s = EdgeSeparation(poly1, xf1, edge, poly2, xf2); | |||
| if (s > 0.0f) | |||
| { | |||
| return s; | |||
| } | |||
| if (s > bestSeparation) | |||
| { | |||
| bestEdge = edge; | |||
| bestSeparation = s; | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| *edgeIndex = bestEdge; | |||
| return bestSeparation; | |||
| } | |||
| static void FindIncidentEdge(ClipVertex c[2], | |||
| const btBox2dShape* poly1, const btTransform& xf1, int edge1, | |||
| const btBox2dShape* poly2, const btTransform& xf2) | |||
| { | |||
| const btVector3* normals1 = poly1->getNormals(); | |||
| int count2 = poly2->getVertexCount(); | |||
| const btVector3* vertices2 = poly2->getVertices(); | |||
| const btVector3* normals2 = poly2->getNormals(); | |||
| btAssert(0 <= edge1 && edge1 < poly1->getVertexCount()); | |||
| // Get the normal of the reference edge in poly2's frame. | |||
| btVector3 normal1 = b2MulT(xf2.getBasis(), b2Mul(xf1.getBasis(), normals1[edge1])); | |||
| // Find the incident edge on poly2. | |||
| int index = 0; | |||
| btScalar minDot = BT_LARGE_FLOAT; | |||
| for (int i = 0; i < count2; ++i) | |||
| { | |||
| btScalar dot = b2Dot(normal1, normals2[i]); | |||
| if (dot < minDot) | |||
| { | |||
| minDot = dot; | |||
| index = i; | |||
| } | |||
| } | |||
| // Build the clip vertices for the incident edge. | |||
| int i1 = index; | |||
| int i2 = i1 + 1 < count2 ? i1 + 1 : 0; | |||
| c[0].v = b2Mul(xf2, vertices2[i1]); | |||
| // c[0].id.features.referenceEdge = (unsigned char)edge1; | |||
| // c[0].id.features.incidentEdge = (unsigned char)i1; | |||
| // c[0].id.features.incidentVertex = 0; | |||
| c[1].v = b2Mul(xf2, vertices2[i2]); | |||
| // c[1].id.features.referenceEdge = (unsigned char)edge1; | |||
| // c[1].id.features.incidentEdge = (unsigned char)i2; | |||
| // c[1].id.features.incidentVertex = 1; | |||
| } | |||
| // Find edge normal of max separation on A - return if separating axis is found | |||
| // Find edge normal of max separation on B - return if separation axis is found | |||
| // Choose reference edge as min(minA, minB) | |||
| // Find incident edge | |||
| // Clip | |||
| // The normal points from 1 to 2 | |||
| void b2CollidePolygons(btManifoldResult* manifold, | |||
| const btBox2dShape* polyA, const btTransform& xfA, | |||
| const btBox2dShape* polyB, const btTransform& xfB) | |||
| { | |||
| int edgeA = 0; | |||
| btScalar separationA = FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB); | |||
| if (separationA > 0.0f) | |||
| return; | |||
| int edgeB = 0; | |||
| btScalar separationB = FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA); | |||
| if (separationB > 0.0f) | |||
| return; | |||
| const btBox2dShape* poly1; // reference poly | |||
| const btBox2dShape* poly2; // incident poly | |||
| btTransform xf1, xf2; | |||
| int edge1; // reference edge | |||
| unsigned char flip; | |||
| const btScalar k_relativeTol = 0.98f; | |||
| const btScalar k_absoluteTol = 0.001f; | |||
| // TODO_ERIN use "radius" of poly for absolute tolerance. | |||
| if (separationB > k_relativeTol * separationA + k_absoluteTol) | |||
| { | |||
| poly1 = polyB; | |||
| poly2 = polyA; | |||
| xf1 = xfB; | |||
| xf2 = xfA; | |||
| edge1 = edgeB; | |||
| flip = 1; | |||
| } | |||
| else | |||
| { | |||
| poly1 = polyA; | |||
| poly2 = polyB; | |||
| xf1 = xfA; | |||
| xf2 = xfB; | |||
| edge1 = edgeA; | |||
| flip = 0; | |||
| } | |||
| ClipVertex incidentEdge[2]; | |||
| FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); | |||
| int count1 = poly1->getVertexCount(); | |||
| const btVector3* vertices1 = poly1->getVertices(); | |||
| btVector3 v11 = vertices1[edge1]; | |||
| btVector3 v12 = edge1 + 1 < count1 ? vertices1[edge1+1] : vertices1[0]; | |||
| btVector3 dv = v12 - v11; | |||
| btVector3 sideNormal = b2Mul(xf1.getBasis(), v12 - v11); | |||
| sideNormal.normalize(); | |||
| btVector3 frontNormal = btCrossS(sideNormal, 1.0f); | |||
| v11 = b2Mul(xf1, v11); | |||
| v12 = b2Mul(xf1, v12); | |||
| btScalar frontOffset = b2Dot(frontNormal, v11); | |||
| btScalar sideOffset1 = -b2Dot(sideNormal, v11); | |||
| btScalar sideOffset2 = b2Dot(sideNormal, v12); | |||
| // Clip incident edge against extruded edge1 side edges. | |||
| ClipVertex clipPoints1[2]; | |||
| clipPoints1[0].v.setValue(0,0,0); | |||
| clipPoints1[1].v.setValue(0,0,0); | |||
| ClipVertex clipPoints2[2]; | |||
| clipPoints2[0].v.setValue(0,0,0); | |||
| clipPoints2[1].v.setValue(0,0,0); | |||
| int np; | |||
| // Clip to box side 1 | |||
| np = ClipSegmentToLine(clipPoints1, incidentEdge, -sideNormal, sideOffset1); | |||
| if (np < 2) | |||
| return; | |||
| // Clip to negative box side 1 | |||
| np = ClipSegmentToLine(clipPoints2, clipPoints1, sideNormal, sideOffset2); | |||
| if (np < 2) | |||
| { | |||
| return; | |||
| } | |||
| // Now clipPoints2 contains the clipped points. | |||
| btVector3 manifoldNormal = flip ? -frontNormal : frontNormal; | |||
| int pointCount = 0; | |||
| for (int i = 0; i < b2_maxManifoldPoints; ++i) | |||
| { | |||
| btScalar separation = b2Dot(frontNormal, clipPoints2[i].v) - frontOffset; | |||
| if (separation <= 0.0f) | |||
| { | |||
| //b2ManifoldPoint* cp = manifold->points + pointCount; | |||
| //btScalar separation = separation; | |||
| //cp->localPoint1 = b2MulT(xfA, clipPoints2[i].v); | |||
| //cp->localPoint2 = b2MulT(xfB, clipPoints2[i].v); | |||
| manifold->addContactPoint(-manifoldNormal,clipPoints2[i].v,separation); | |||
| // cp->id = clipPoints2[i].id; | |||
| // cp->id.features.flip = flip; | |||
| ++pointCount; | |||
| } | |||
| } | |||
| // manifold->pointCount = pointCount;} | |||
| } | |||
| @@ -0,0 +1,66 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_BOX_2D_BOX_2D__COLLISION_ALGORITHM_H | |||
| #define BT_BOX_2D_BOX_2D__COLLISION_ALGORITHM_H | |||
| #include "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
| class btPersistentManifold; | |||
| ///box-box collision detection | |||
| class btBox2dBox2dCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
| { | |||
| bool m_ownManifold; | |||
| btPersistentManifold* m_manifoldPtr; | |||
| public: | |||
| btBox2dBox2dCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) | |||
| : btActivatingCollisionAlgorithm(ci) {} | |||
| virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| btBox2dBox2dCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); | |||
| virtual ~btBox2dBox2dCollisionAlgorithm(); | |||
| virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
| { | |||
| if (m_manifoldPtr && m_ownManifold) | |||
| { | |||
| manifoldArray.push_back(m_manifoldPtr); | |||
| } | |||
| } | |||
| struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| int bbsize = sizeof(btBox2dBox2dCollisionAlgorithm); | |||
| void* ptr = ci.m_dispatcher1->allocateCollisionAlgorithm(bbsize); | |||
| return new(ptr) btBox2dBox2dCollisionAlgorithm(0,ci,body0,body1); | |||
| } | |||
| }; | |||
| }; | |||
| #endif //BT_BOX_2D_BOX_2D__COLLISION_ALGORITHM_H | |||
| @@ -0,0 +1,85 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btBoxBoxCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
| #include "BulletCollision/CollisionShapes/btBoxShape.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| #include "btBoxBoxDetector.h" | |||
| #define USE_PERSISTENT_CONTACTS 1 | |||
| btBoxBoxCollisionAlgorithm::btBoxBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* obj0,btCollisionObject* obj1) | |||
| : btActivatingCollisionAlgorithm(ci,obj0,obj1), | |||
| m_ownManifold(false), | |||
| m_manifoldPtr(mf) | |||
| { | |||
| if (!m_manifoldPtr && m_dispatcher->needsCollision(obj0,obj1)) | |||
| { | |||
| m_manifoldPtr = m_dispatcher->getNewManifold(obj0,obj1); | |||
| m_ownManifold = true; | |||
| } | |||
| } | |||
| btBoxBoxCollisionAlgorithm::~btBoxBoxCollisionAlgorithm() | |||
| { | |||
| if (m_ownManifold) | |||
| { | |||
| if (m_manifoldPtr) | |||
| m_dispatcher->releaseManifold(m_manifoldPtr); | |||
| } | |||
| } | |||
| void btBoxBoxCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| if (!m_manifoldPtr) | |||
| return; | |||
| btCollisionObject* col0 = body0; | |||
| btCollisionObject* col1 = body1; | |||
| btBoxShape* box0 = (btBoxShape*)col0->getCollisionShape(); | |||
| btBoxShape* box1 = (btBoxShape*)col1->getCollisionShape(); | |||
| /// report a contact. internally this will be kept persistent, and contact reduction is done | |||
| resultOut->setPersistentManifold(m_manifoldPtr); | |||
| #ifndef USE_PERSISTENT_CONTACTS | |||
| m_manifoldPtr->clearManifold(); | |||
| #endif //USE_PERSISTENT_CONTACTS | |||
| btDiscreteCollisionDetectorInterface::ClosestPointInput input; | |||
| input.m_maximumDistanceSquared = BT_LARGE_FLOAT; | |||
| input.m_transformA = body0->getWorldTransform(); | |||
| input.m_transformB = body1->getWorldTransform(); | |||
| btBoxBoxDetector detector(box0,box1); | |||
| detector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); | |||
| #ifdef USE_PERSISTENT_CONTACTS | |||
| // refreshContactPoints is only necessary when using persistent contact points. otherwise all points are newly added | |||
| if (m_ownManifold) | |||
| { | |||
| resultOut->refreshContactPoints(); | |||
| } | |||
| #endif //USE_PERSISTENT_CONTACTS | |||
| } | |||
| btScalar btBoxBoxCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* /*body0*/,btCollisionObject* /*body1*/,const btDispatcherInfo& /*dispatchInfo*/,btManifoldResult* /*resultOut*/) | |||
| { | |||
| //not yet | |||
| return 1.f; | |||
| } | |||
| @@ -0,0 +1,66 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_BOX_BOX__COLLISION_ALGORITHM_H | |||
| #define BT_BOX_BOX__COLLISION_ALGORITHM_H | |||
| #include "btActivatingCollisionAlgorithm.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
| class btPersistentManifold; | |||
| ///box-box collision detection | |||
| class btBoxBoxCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
| { | |||
| bool m_ownManifold; | |||
| btPersistentManifold* m_manifoldPtr; | |||
| public: | |||
| btBoxBoxCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) | |||
| : btActivatingCollisionAlgorithm(ci) {} | |||
| virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| btBoxBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); | |||
| virtual ~btBoxBoxCollisionAlgorithm(); | |||
| virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
| { | |||
| if (m_manifoldPtr && m_ownManifold) | |||
| { | |||
| manifoldArray.push_back(m_manifoldPtr); | |||
| } | |||
| } | |||
| struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| int bbsize = sizeof(btBoxBoxCollisionAlgorithm); | |||
| void* ptr = ci.m_dispatcher1->allocateCollisionAlgorithm(bbsize); | |||
| return new(ptr) btBoxBoxCollisionAlgorithm(0,ci,body0,body1); | |||
| } | |||
| }; | |||
| }; | |||
| #endif //BT_BOX_BOX__COLLISION_ALGORITHM_H | |||
| @@ -0,0 +1,718 @@ | |||
| /* | |||
| * Box-Box collision detection re-distributed under the ZLib license with permission from Russell L. Smith | |||
| * Original version is from Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. | |||
| * All rights reserved. Email: russ@q12.org Web: www.q12.org | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Bullet is Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| ///ODE box-box collision detection is adapted to work with Bullet | |||
| #include "btBoxBoxDetector.h" | |||
| #include "BulletCollision/CollisionShapes/btBoxShape.h" | |||
| #include <float.h> | |||
| #include <string.h> | |||
| btBoxBoxDetector::btBoxBoxDetector(btBoxShape* box1,btBoxShape* box2) | |||
| : m_box1(box1), | |||
| m_box2(box2) | |||
| { | |||
| } | |||
| // given two boxes (p1,R1,side1) and (p2,R2,side2), collide them together and | |||
| // generate contact points. this returns 0 if there is no contact otherwise | |||
| // it returns the number of contacts generated. | |||
| // `normal' returns the contact normal. | |||
| // `depth' returns the maximum penetration depth along that normal. | |||
| // `return_code' returns a number indicating the type of contact that was | |||
| // detected: | |||
| // 1,2,3 = box 2 intersects with a face of box 1 | |||
| // 4,5,6 = box 1 intersects with a face of box 2 | |||
| // 7..15 = edge-edge contact | |||
| // `maxc' is the maximum number of contacts allowed to be generated, i.e. | |||
| // the size of the `contact' array. | |||
| // `contact' and `skip' are the contact array information provided to the | |||
| // collision functions. this function only fills in the position and depth | |||
| // fields. | |||
| struct dContactGeom; | |||
| #define dDOTpq(a,b,p,q) ((a)[0]*(b)[0] + (a)[p]*(b)[q] + (a)[2*(p)]*(b)[2*(q)]) | |||
| #define dInfinity FLT_MAX | |||
| /*PURE_INLINE btScalar dDOT (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,1); } | |||
| PURE_INLINE btScalar dDOT13 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,3); } | |||
| PURE_INLINE btScalar dDOT31 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,3,1); } | |||
| PURE_INLINE btScalar dDOT33 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,3,3); } | |||
| */ | |||
| static btScalar dDOT (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,1); } | |||
| static btScalar dDOT44 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,4,4); } | |||
| static btScalar dDOT41 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,4,1); } | |||
| static btScalar dDOT14 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,4); } | |||
| #define dMULTIPLYOP1_331(A,op,B,C) \ | |||
| {\ | |||
| (A)[0] op dDOT41((B),(C)); \ | |||
| (A)[1] op dDOT41((B+1),(C)); \ | |||
| (A)[2] op dDOT41((B+2),(C)); \ | |||
| } | |||
| #define dMULTIPLYOP0_331(A,op,B,C) \ | |||
| { \ | |||
| (A)[0] op dDOT((B),(C)); \ | |||
| (A)[1] op dDOT((B+4),(C)); \ | |||
| (A)[2] op dDOT((B+8),(C)); \ | |||
| } | |||
| #define dMULTIPLY1_331(A,B,C) dMULTIPLYOP1_331(A,=,B,C) | |||
| #define dMULTIPLY0_331(A,B,C) dMULTIPLYOP0_331(A,=,B,C) | |||
| typedef btScalar dMatrix3[4*3]; | |||
| void dLineClosestApproach (const btVector3& pa, const btVector3& ua, | |||
| const btVector3& pb, const btVector3& ub, | |||
| btScalar *alpha, btScalar *beta); | |||
| void dLineClosestApproach (const btVector3& pa, const btVector3& ua, | |||
| const btVector3& pb, const btVector3& ub, | |||
| btScalar *alpha, btScalar *beta) | |||
| { | |||
| btVector3 p; | |||
| p[0] = pb[0] - pa[0]; | |||
| p[1] = pb[1] - pa[1]; | |||
| p[2] = pb[2] - pa[2]; | |||
| btScalar uaub = dDOT(ua,ub); | |||
| btScalar q1 = dDOT(ua,p); | |||
| btScalar q2 = -dDOT(ub,p); | |||
| btScalar d = 1-uaub*uaub; | |||
| if (d <= btScalar(0.0001f)) { | |||
| // @@@ this needs to be made more robust | |||
| *alpha = 0; | |||
| *beta = 0; | |||
| } | |||
| else { | |||
| d = 1.f/d; | |||
| *alpha = (q1 + uaub*q2)*d; | |||
| *beta = (uaub*q1 + q2)*d; | |||
| } | |||
| } | |||
| // find all the intersection points between the 2D rectangle with vertices | |||
| // at (+/-h[0],+/-h[1]) and the 2D quadrilateral with vertices (p[0],p[1]), | |||
| // (p[2],p[3]),(p[4],p[5]),(p[6],p[7]). | |||
| // | |||
| // the intersection points are returned as x,y pairs in the 'ret' array. | |||
| // the number of intersection points is returned by the function (this will | |||
| // be in the range 0 to 8). | |||
| static int intersectRectQuad2 (btScalar h[2], btScalar p[8], btScalar ret[16]) | |||
| { | |||
| // q (and r) contain nq (and nr) coordinate points for the current (and | |||
| // chopped) polygons | |||
| int nq=4,nr=0; | |||
| btScalar buffer[16]; | |||
| btScalar *q = p; | |||
| btScalar *r = ret; | |||
| for (int dir=0; dir <= 1; dir++) { | |||
| // direction notation: xy[0] = x axis, xy[1] = y axis | |||
| for (int sign=-1; sign <= 1; sign += 2) { | |||
| // chop q along the line xy[dir] = sign*h[dir] | |||
| btScalar *pq = q; | |||
| btScalar *pr = r; | |||
| nr = 0; | |||
| for (int i=nq; i > 0; i--) { | |||
| // go through all points in q and all lines between adjacent points | |||
| if (sign*pq[dir] < h[dir]) { | |||
| // this point is inside the chopping line | |||
| pr[0] = pq[0]; | |||
| pr[1] = pq[1]; | |||
| pr += 2; | |||
| nr++; | |||
| if (nr & 8) { | |||
| q = r; | |||
| goto done; | |||
| } | |||
| } | |||
| btScalar *nextq = (i > 1) ? pq+2 : q; | |||
| if ((sign*pq[dir] < h[dir]) ^ (sign*nextq[dir] < h[dir])) { | |||
| // this line crosses the chopping line | |||
| pr[1-dir] = pq[1-dir] + (nextq[1-dir]-pq[1-dir]) / | |||
| (nextq[dir]-pq[dir]) * (sign*h[dir]-pq[dir]); | |||
| pr[dir] = sign*h[dir]; | |||
| pr += 2; | |||
| nr++; | |||
| if (nr & 8) { | |||
| q = r; | |||
| goto done; | |||
| } | |||
| } | |||
| pq += 2; | |||
| } | |||
| q = r; | |||
| r = (q==ret) ? buffer : ret; | |||
| nq = nr; | |||
| } | |||
| } | |||
| done: | |||
| if (q != ret) memcpy (ret,q,nr*2*sizeof(btScalar)); | |||
| return nr; | |||
| } | |||
| #define M__PI 3.14159265f | |||
| // given n points in the plane (array p, of size 2*n), generate m points that | |||
| // best represent the whole set. the definition of 'best' here is not | |||
| // predetermined - the idea is to select points that give good box-box | |||
| // collision detection behavior. the chosen point indexes are returned in the | |||
| // array iret (of size m). 'i0' is always the first entry in the array. | |||
| // n must be in the range [1..8]. m must be in the range [1..n]. i0 must be | |||
| // in the range [0..n-1]. | |||
| void cullPoints2 (int n, btScalar p[], int m, int i0, int iret[]); | |||
| void cullPoints2 (int n, btScalar p[], int m, int i0, int iret[]) | |||
| { | |||
| // compute the centroid of the polygon in cx,cy | |||
| int i,j; | |||
| btScalar a,cx,cy,q; | |||
| if (n==1) { | |||
| cx = p[0]; | |||
| cy = p[1]; | |||
| } | |||
| else if (n==2) { | |||
| cx = btScalar(0.5)*(p[0] + p[2]); | |||
| cy = btScalar(0.5)*(p[1] + p[3]); | |||
| } | |||
| else { | |||
| a = 0; | |||
| cx = 0; | |||
| cy = 0; | |||
| for (i=0; i<(n-1); i++) { | |||
| q = p[i*2]*p[i*2+3] - p[i*2+2]*p[i*2+1]; | |||
| a += q; | |||
| cx += q*(p[i*2]+p[i*2+2]); | |||
| cy += q*(p[i*2+1]+p[i*2+3]); | |||
| } | |||
| q = p[n*2-2]*p[1] - p[0]*p[n*2-1]; | |||
| if (btFabs(a+q) > SIMD_EPSILON) | |||
| { | |||
| a = 1.f/(btScalar(3.0)*(a+q)); | |||
| } else | |||
| { | |||
| a=BT_LARGE_FLOAT; | |||
| } | |||
| cx = a*(cx + q*(p[n*2-2]+p[0])); | |||
| cy = a*(cy + q*(p[n*2-1]+p[1])); | |||
| } | |||
| // compute the angle of each point w.r.t. the centroid | |||
| btScalar A[8]; | |||
| for (i=0; i<n; i++) A[i] = btAtan2(p[i*2+1]-cy,p[i*2]-cx); | |||
| // search for points that have angles closest to A[i0] + i*(2*pi/m). | |||
| int avail[8]; | |||
| for (i=0; i<n; i++) avail[i] = 1; | |||
| avail[i0] = 0; | |||
| iret[0] = i0; | |||
| iret++; | |||
| for (j=1; j<m; j++) { | |||
| a = btScalar(j)*(2*M__PI/m) + A[i0]; | |||
| if (a > M__PI) a -= 2*M__PI; | |||
| btScalar maxdiff=1e9,diff; | |||
| *iret = i0; // iret is not allowed to keep this value, but it sometimes does, when diff=#QNAN0 | |||
| for (i=0; i<n; i++) { | |||
| if (avail[i]) { | |||
| diff = btFabs (A[i]-a); | |||
| if (diff > M__PI) diff = 2*M__PI - diff; | |||
| if (diff < maxdiff) { | |||
| maxdiff = diff; | |||
| *iret = i; | |||
| } | |||
| } | |||
| } | |||
| #if defined(DEBUG) || defined (_DEBUG) | |||
| btAssert (*iret != i0); // ensure iret got set | |||
| #endif | |||
| avail[*iret] = 0; | |||
| iret++; | |||
| } | |||
| } | |||
| int dBoxBox2 (const btVector3& p1, const dMatrix3 R1, | |||
| const btVector3& side1, const btVector3& p2, | |||
| const dMatrix3 R2, const btVector3& side2, | |||
| btVector3& normal, btScalar *depth, int *return_code, | |||
| int maxc, dContactGeom * /*contact*/, int /*skip*/,btDiscreteCollisionDetectorInterface::Result& output); | |||
| int dBoxBox2 (const btVector3& p1, const dMatrix3 R1, | |||
| const btVector3& side1, const btVector3& p2, | |||
| const dMatrix3 R2, const btVector3& side2, | |||
| btVector3& normal, btScalar *depth, int *return_code, | |||
| int maxc, dContactGeom * /*contact*/, int /*skip*/,btDiscreteCollisionDetectorInterface::Result& output) | |||
| { | |||
| const btScalar fudge_factor = btScalar(1.05); | |||
| btVector3 p,pp,normalC(0.f,0.f,0.f); | |||
| const btScalar *normalR = 0; | |||
| btScalar A[3],B[3],R11,R12,R13,R21,R22,R23,R31,R32,R33, | |||
| Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33,s,s2,l; | |||
| int i,j,invert_normal,code; | |||
| // get vector from centers of box 1 to box 2, relative to box 1 | |||
| p = p2 - p1; | |||
| dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1 | |||
| // get side lengths / 2 | |||
| A[0] = side1[0]*btScalar(0.5); | |||
| A[1] = side1[1]*btScalar(0.5); | |||
| A[2] = side1[2]*btScalar(0.5); | |||
| B[0] = side2[0]*btScalar(0.5); | |||
| B[1] = side2[1]*btScalar(0.5); | |||
| B[2] = side2[2]*btScalar(0.5); | |||
| // Rij is R1'*R2, i.e. the relative rotation between R1 and R2 | |||
| R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2); | |||
| R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2); | |||
| R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2); | |||
| Q11 = btFabs(R11); Q12 = btFabs(R12); Q13 = btFabs(R13); | |||
| Q21 = btFabs(R21); Q22 = btFabs(R22); Q23 = btFabs(R23); | |||
| Q31 = btFabs(R31); Q32 = btFabs(R32); Q33 = btFabs(R33); | |||
| // for all 15 possible separating axes: | |||
| // * see if the axis separates the boxes. if so, return 0. | |||
| // * find the depth of the penetration along the separating axis (s2) | |||
| // * if this is the largest depth so far, record it. | |||
| // the normal vector will be set to the separating axis with the smallest | |||
| // depth. note: normalR is set to point to a column of R1 or R2 if that is | |||
| // the smallest depth normal so far. otherwise normalR is 0 and normalC is | |||
| // set to a vector relative to body 1. invert_normal is 1 if the sign of | |||
| // the normal should be flipped. | |||
| #define TST(expr1,expr2,norm,cc) \ | |||
| s2 = btFabs(expr1) - (expr2); \ | |||
| if (s2 > 0) return 0; \ | |||
| if (s2 > s) { \ | |||
| s = s2; \ | |||
| normalR = norm; \ | |||
| invert_normal = ((expr1) < 0); \ | |||
| code = (cc); \ | |||
| } | |||
| s = -dInfinity; | |||
| invert_normal = 0; | |||
| code = 0; | |||
| // separating axis = u1,u2,u3 | |||
| TST (pp[0],(A[0] + B[0]*Q11 + B[1]*Q12 + B[2]*Q13),R1+0,1); | |||
| TST (pp[1],(A[1] + B[0]*Q21 + B[1]*Q22 + B[2]*Q23),R1+1,2); | |||
| TST (pp[2],(A[2] + B[0]*Q31 + B[1]*Q32 + B[2]*Q33),R1+2,3); | |||
| // separating axis = v1,v2,v3 | |||
| TST (dDOT41(R2+0,p),(A[0]*Q11 + A[1]*Q21 + A[2]*Q31 + B[0]),R2+0,4); | |||
| TST (dDOT41(R2+1,p),(A[0]*Q12 + A[1]*Q22 + A[2]*Q32 + B[1]),R2+1,5); | |||
| TST (dDOT41(R2+2,p),(A[0]*Q13 + A[1]*Q23 + A[2]*Q33 + B[2]),R2+2,6); | |||
| // note: cross product axes need to be scaled when s is computed. | |||
| // normal (n1,n2,n3) is relative to box 1. | |||
| #undef TST | |||
| #define TST(expr1,expr2,n1,n2,n3,cc) \ | |||
| s2 = btFabs(expr1) - (expr2); \ | |||
| if (s2 > SIMD_EPSILON) return 0; \ | |||
| l = btSqrt((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \ | |||
| if (l > SIMD_EPSILON) { \ | |||
| s2 /= l; \ | |||
| if (s2*fudge_factor > s) { \ | |||
| s = s2; \ | |||
| normalR = 0; \ | |||
| normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \ | |||
| invert_normal = ((expr1) < 0); \ | |||
| code = (cc); \ | |||
| } \ | |||
| } | |||
| btScalar fudge2 (1.0e-5f); | |||
| Q11 += fudge2; | |||
| Q12 += fudge2; | |||
| Q13 += fudge2; | |||
| Q21 += fudge2; | |||
| Q22 += fudge2; | |||
| Q23 += fudge2; | |||
| Q31 += fudge2; | |||
| Q32 += fudge2; | |||
| Q33 += fudge2; | |||
| // separating axis = u1 x (v1,v2,v3) | |||
| TST(pp[2]*R21-pp[1]*R31,(A[1]*Q31+A[2]*Q21+B[1]*Q13+B[2]*Q12),0,-R31,R21,7); | |||
| TST(pp[2]*R22-pp[1]*R32,(A[1]*Q32+A[2]*Q22+B[0]*Q13+B[2]*Q11),0,-R32,R22,8); | |||
| TST(pp[2]*R23-pp[1]*R33,(A[1]*Q33+A[2]*Q23+B[0]*Q12+B[1]*Q11),0,-R33,R23,9); | |||
| // separating axis = u2 x (v1,v2,v3) | |||
| TST(pp[0]*R31-pp[2]*R11,(A[0]*Q31+A[2]*Q11+B[1]*Q23+B[2]*Q22),R31,0,-R11,10); | |||
| TST(pp[0]*R32-pp[2]*R12,(A[0]*Q32+A[2]*Q12+B[0]*Q23+B[2]*Q21),R32,0,-R12,11); | |||
| TST(pp[0]*R33-pp[2]*R13,(A[0]*Q33+A[2]*Q13+B[0]*Q22+B[1]*Q21),R33,0,-R13,12); | |||
| // separating axis = u3 x (v1,v2,v3) | |||
| TST(pp[1]*R11-pp[0]*R21,(A[0]*Q21+A[1]*Q11+B[1]*Q33+B[2]*Q32),-R21,R11,0,13); | |||
| TST(pp[1]*R12-pp[0]*R22,(A[0]*Q22+A[1]*Q12+B[0]*Q33+B[2]*Q31),-R22,R12,0,14); | |||
| TST(pp[1]*R13-pp[0]*R23,(A[0]*Q23+A[1]*Q13+B[0]*Q32+B[1]*Q31),-R23,R13,0,15); | |||
| #undef TST | |||
| if (!code) return 0; | |||
| // if we get to this point, the boxes interpenetrate. compute the normal | |||
| // in global coordinates. | |||
| if (normalR) { | |||
| normal[0] = normalR[0]; | |||
| normal[1] = normalR[4]; | |||
| normal[2] = normalR[8]; | |||
| } | |||
| else { | |||
| dMULTIPLY0_331 (normal,R1,normalC); | |||
| } | |||
| if (invert_normal) { | |||
| normal[0] = -normal[0]; | |||
| normal[1] = -normal[1]; | |||
| normal[2] = -normal[2]; | |||
| } | |||
| *depth = -s; | |||
| // compute contact point(s) | |||
| if (code > 6) { | |||
| // an edge from box 1 touches an edge from box 2. | |||
| // find a point pa on the intersecting edge of box 1 | |||
| btVector3 pa; | |||
| btScalar sign; | |||
| for (i=0; i<3; i++) pa[i] = p1[i]; | |||
| for (j=0; j<3; j++) { | |||
| sign = (dDOT14(normal,R1+j) > 0) ? btScalar(1.0) : btScalar(-1.0); | |||
| for (i=0; i<3; i++) pa[i] += sign * A[j] * R1[i*4+j]; | |||
| } | |||
| // find a point pb on the intersecting edge of box 2 | |||
| btVector3 pb; | |||
| for (i=0; i<3; i++) pb[i] = p2[i]; | |||
| for (j=0; j<3; j++) { | |||
| sign = (dDOT14(normal,R2+j) > 0) ? btScalar(-1.0) : btScalar(1.0); | |||
| for (i=0; i<3; i++) pb[i] += sign * B[j] * R2[i*4+j]; | |||
| } | |||
| btScalar alpha,beta; | |||
| btVector3 ua,ub; | |||
| for (i=0; i<3; i++) ua[i] = R1[((code)-7)/3 + i*4]; | |||
| for (i=0; i<3; i++) ub[i] = R2[((code)-7)%3 + i*4]; | |||
| dLineClosestApproach (pa,ua,pb,ub,&alpha,&beta); | |||
| for (i=0; i<3; i++) pa[i] += ua[i]*alpha; | |||
| for (i=0; i<3; i++) pb[i] += ub[i]*beta; | |||
| { | |||
| //contact[0].pos[i] = btScalar(0.5)*(pa[i]+pb[i]); | |||
| //contact[0].depth = *depth; | |||
| btVector3 pointInWorld; | |||
| #ifdef USE_CENTER_POINT | |||
| for (i=0; i<3; i++) | |||
| pointInWorld[i] = (pa[i]+pb[i])*btScalar(0.5); | |||
| output.addContactPoint(-normal,pointInWorld,-*depth); | |||
| #else | |||
| output.addContactPoint(-normal,pb,-*depth); | |||
| #endif // | |||
| *return_code = code; | |||
| } | |||
| return 1; | |||
| } | |||
| // okay, we have a face-something intersection (because the separating | |||
| // axis is perpendicular to a face). define face 'a' to be the reference | |||
| // face (i.e. the normal vector is perpendicular to this) and face 'b' to be | |||
| // the incident face (the closest face of the other box). | |||
| const btScalar *Ra,*Rb,*pa,*pb,*Sa,*Sb; | |||
| if (code <= 3) { | |||
| Ra = R1; | |||
| Rb = R2; | |||
| pa = p1; | |||
| pb = p2; | |||
| Sa = A; | |||
| Sb = B; | |||
| } | |||
| else { | |||
| Ra = R2; | |||
| Rb = R1; | |||
| pa = p2; | |||
| pb = p1; | |||
| Sa = B; | |||
| Sb = A; | |||
| } | |||
| // nr = normal vector of reference face dotted with axes of incident box. | |||
| // anr = absolute values of nr. | |||
| btVector3 normal2,nr,anr; | |||
| if (code <= 3) { | |||
| normal2[0] = normal[0]; | |||
| normal2[1] = normal[1]; | |||
| normal2[2] = normal[2]; | |||
| } | |||
| else { | |||
| normal2[0] = -normal[0]; | |||
| normal2[1] = -normal[1]; | |||
| normal2[2] = -normal[2]; | |||
| } | |||
| dMULTIPLY1_331 (nr,Rb,normal2); | |||
| anr[0] = btFabs (nr[0]); | |||
| anr[1] = btFabs (nr[1]); | |||
| anr[2] = btFabs (nr[2]); | |||
| // find the largest compontent of anr: this corresponds to the normal | |||
| // for the indident face. the other axis numbers of the indicent face | |||
| // are stored in a1,a2. | |||
| int lanr,a1,a2; | |||
| if (anr[1] > anr[0]) { | |||
| if (anr[1] > anr[2]) { | |||
| a1 = 0; | |||
| lanr = 1; | |||
| a2 = 2; | |||
| } | |||
| else { | |||
| a1 = 0; | |||
| a2 = 1; | |||
| lanr = 2; | |||
| } | |||
| } | |||
| else { | |||
| if (anr[0] > anr[2]) { | |||
| lanr = 0; | |||
| a1 = 1; | |||
| a2 = 2; | |||
| } | |||
| else { | |||
| a1 = 0; | |||
| a2 = 1; | |||
| lanr = 2; | |||
| } | |||
| } | |||
| // compute center point of incident face, in reference-face coordinates | |||
| btVector3 center; | |||
| if (nr[lanr] < 0) { | |||
| for (i=0; i<3; i++) center[i] = pb[i] - pa[i] + Sb[lanr] * Rb[i*4+lanr]; | |||
| } | |||
| else { | |||
| for (i=0; i<3; i++) center[i] = pb[i] - pa[i] - Sb[lanr] * Rb[i*4+lanr]; | |||
| } | |||
| // find the normal and non-normal axis numbers of the reference box | |||
| int codeN,code1,code2; | |||
| if (code <= 3) codeN = code-1; else codeN = code-4; | |||
| if (codeN==0) { | |||
| code1 = 1; | |||
| code2 = 2; | |||
| } | |||
| else if (codeN==1) { | |||
| code1 = 0; | |||
| code2 = 2; | |||
| } | |||
| else { | |||
| code1 = 0; | |||
| code2 = 1; | |||
| } | |||
| // find the four corners of the incident face, in reference-face coordinates | |||
| btScalar quad[8]; // 2D coordinate of incident face (x,y pairs) | |||
| btScalar c1,c2,m11,m12,m21,m22; | |||
| c1 = dDOT14 (center,Ra+code1); | |||
| c2 = dDOT14 (center,Ra+code2); | |||
| // optimize this? - we have already computed this data above, but it is not | |||
| // stored in an easy-to-index format. for now it's quicker just to recompute | |||
| // the four dot products. | |||
| m11 = dDOT44 (Ra+code1,Rb+a1); | |||
| m12 = dDOT44 (Ra+code1,Rb+a2); | |||
| m21 = dDOT44 (Ra+code2,Rb+a1); | |||
| m22 = dDOT44 (Ra+code2,Rb+a2); | |||
| { | |||
| btScalar k1 = m11*Sb[a1]; | |||
| btScalar k2 = m21*Sb[a1]; | |||
| btScalar k3 = m12*Sb[a2]; | |||
| btScalar k4 = m22*Sb[a2]; | |||
| quad[0] = c1 - k1 - k3; | |||
| quad[1] = c2 - k2 - k4; | |||
| quad[2] = c1 - k1 + k3; | |||
| quad[3] = c2 - k2 + k4; | |||
| quad[4] = c1 + k1 + k3; | |||
| quad[5] = c2 + k2 + k4; | |||
| quad[6] = c1 + k1 - k3; | |||
| quad[7] = c2 + k2 - k4; | |||
| } | |||
| // find the size of the reference face | |||
| btScalar rect[2]; | |||
| rect[0] = Sa[code1]; | |||
| rect[1] = Sa[code2]; | |||
| // intersect the incident and reference faces | |||
| btScalar ret[16]; | |||
| int n = intersectRectQuad2 (rect,quad,ret); | |||
| if (n < 1) return 0; // this should never happen | |||
| // convert the intersection points into reference-face coordinates, | |||
| // and compute the contact position and depth for each point. only keep | |||
| // those points that have a positive (penetrating) depth. delete points in | |||
| // the 'ret' array as necessary so that 'point' and 'ret' correspond. | |||
| btScalar point[3*8]; // penetrating contact points | |||
| btScalar dep[8]; // depths for those points | |||
| btScalar det1 = 1.f/(m11*m22 - m12*m21); | |||
| m11 *= det1; | |||
| m12 *= det1; | |||
| m21 *= det1; | |||
| m22 *= det1; | |||
| int cnum = 0; // number of penetrating contact points found | |||
| for (j=0; j < n; j++) { | |||
| btScalar k1 = m22*(ret[j*2]-c1) - m12*(ret[j*2+1]-c2); | |||
| btScalar k2 = -m21*(ret[j*2]-c1) + m11*(ret[j*2+1]-c2); | |||
| for (i=0; i<3; i++) point[cnum*3+i] = | |||
| center[i] + k1*Rb[i*4+a1] + k2*Rb[i*4+a2]; | |||
| dep[cnum] = Sa[codeN] - dDOT(normal2,point+cnum*3); | |||
| if (dep[cnum] >= 0) { | |||
| ret[cnum*2] = ret[j*2]; | |||
| ret[cnum*2+1] = ret[j*2+1]; | |||
| cnum++; | |||
| } | |||
| } | |||
| if (cnum < 1) return 0; // this should never happen | |||
| // we can't generate more contacts than we actually have | |||
| if (maxc > cnum) maxc = cnum; | |||
| if (maxc < 1) maxc = 1; | |||
| if (cnum <= maxc) { | |||
| if (code<4) | |||
| { | |||
| // we have less contacts than we need, so we use them all | |||
| for (j=0; j < cnum; j++) | |||
| { | |||
| btVector3 pointInWorld; | |||
| for (i=0; i<3; i++) | |||
| pointInWorld[i] = point[j*3+i] + pa[i]; | |||
| output.addContactPoint(-normal,pointInWorld,-dep[j]); | |||
| } | |||
| } else | |||
| { | |||
| // we have less contacts than we need, so we use them all | |||
| for (j=0; j < cnum; j++) | |||
| { | |||
| btVector3 pointInWorld; | |||
| for (i=0; i<3; i++) | |||
| pointInWorld[i] = point[j*3+i] + pa[i]-normal[i]*dep[j]; | |||
| //pointInWorld[i] = point[j*3+i] + pa[i]; | |||
| output.addContactPoint(-normal,pointInWorld,-dep[j]); | |||
| } | |||
| } | |||
| } | |||
| else { | |||
| // we have more contacts than are wanted, some of them must be culled. | |||
| // find the deepest point, it is always the first contact. | |||
| int i1 = 0; | |||
| btScalar maxdepth = dep[0]; | |||
| for (i=1; i<cnum; i++) { | |||
| if (dep[i] > maxdepth) { | |||
| maxdepth = dep[i]; | |||
| i1 = i; | |||
| } | |||
| } | |||
| int iret[8]; | |||
| cullPoints2 (cnum,ret,maxc,i1,iret); | |||
| for (j=0; j < maxc; j++) { | |||
| // dContactGeom *con = CONTACT(contact,skip*j); | |||
| // for (i=0; i<3; i++) con->pos[i] = point[iret[j]*3+i] + pa[i]; | |||
| // con->depth = dep[iret[j]]; | |||
| btVector3 posInWorld; | |||
| for (i=0; i<3; i++) | |||
| posInWorld[i] = point[iret[j]*3+i] + pa[i]; | |||
| if (code<4) | |||
| { | |||
| output.addContactPoint(-normal,posInWorld,-dep[iret[j]]); | |||
| } else | |||
| { | |||
| output.addContactPoint(-normal,posInWorld-normal*dep[iret[j]],-dep[iret[j]]); | |||
| } | |||
| } | |||
| cnum = maxc; | |||
| } | |||
| *return_code = code; | |||
| return cnum; | |||
| } | |||
| void btBoxBoxDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* /*debugDraw*/,bool /*swapResults*/) | |||
| { | |||
| const btTransform& transformA = input.m_transformA; | |||
| const btTransform& transformB = input.m_transformB; | |||
| int skip = 0; | |||
| dContactGeom *contact = 0; | |||
| dMatrix3 R1; | |||
| dMatrix3 R2; | |||
| for (int j=0;j<3;j++) | |||
| { | |||
| R1[0+4*j] = transformA.getBasis()[j].x(); | |||
| R2[0+4*j] = transformB.getBasis()[j].x(); | |||
| R1[1+4*j] = transformA.getBasis()[j].y(); | |||
| R2[1+4*j] = transformB.getBasis()[j].y(); | |||
| R1[2+4*j] = transformA.getBasis()[j].z(); | |||
| R2[2+4*j] = transformB.getBasis()[j].z(); | |||
| } | |||
| btVector3 normal; | |||
| btScalar depth; | |||
| int return_code; | |||
| int maxc = 4; | |||
| dBoxBox2 (transformA.getOrigin(), | |||
| R1, | |||
| 2.f*m_box1->getHalfExtentsWithMargin(), | |||
| transformB.getOrigin(), | |||
| R2, | |||
| 2.f*m_box2->getHalfExtentsWithMargin(), | |||
| normal, &depth, &return_code, | |||
| maxc, contact, skip, | |||
| output | |||
| ); | |||
| } | |||
| @@ -0,0 +1,44 @@ | |||
| /* | |||
| * Box-Box collision detection re-distributed under the ZLib license with permission from Russell L. Smith | |||
| * Original version is from Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. | |||
| * All rights reserved. Email: russ@q12.org Web: www.q12.org | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_BOX_BOX_DETECTOR_H | |||
| #define BT_BOX_BOX_DETECTOR_H | |||
| class btBoxShape; | |||
| #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" | |||
| /// btBoxBoxDetector wraps the ODE box-box collision detector | |||
| /// re-distributed under the Zlib license with permission from Russell L. Smith | |||
| struct btBoxBoxDetector : public btDiscreteCollisionDetectorInterface | |||
| { | |||
| btBoxShape* m_box1; | |||
| btBoxShape* m_box2; | |||
| public: | |||
| btBoxBoxDetector(btBoxShape* box1,btBoxShape* box2); | |||
| virtual ~btBoxBoxDetector() {}; | |||
| virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults=false); | |||
| }; | |||
| #endif //BT_BOX_BOX_DETECTOR_H | |||
| @@ -0,0 +1,48 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_COLLISION_CONFIGURATION | |||
| #define BT_COLLISION_CONFIGURATION | |||
| struct btCollisionAlgorithmCreateFunc; | |||
| class btStackAlloc; | |||
| class btPoolAllocator; | |||
| ///btCollisionConfiguration allows to configure Bullet collision detection | |||
| ///stack allocator size, default collision algorithms and persistent manifold pool size | |||
| ///@todo: describe the meaning | |||
| class btCollisionConfiguration | |||
| { | |||
| public: | |||
| virtual ~btCollisionConfiguration() | |||
| { | |||
| } | |||
| ///memory pools | |||
| virtual btPoolAllocator* getPersistentManifoldPool() = 0; | |||
| virtual btPoolAllocator* getCollisionAlgorithmPool() = 0; | |||
| virtual btStackAlloc* getStackAllocator() = 0; | |||
| virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) =0; | |||
| }; | |||
| #endif //BT_COLLISION_CONFIGURATION | |||
| @@ -0,0 +1,45 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_COLLISION_CREATE_FUNC | |||
| #define BT_COLLISION_CREATE_FUNC | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| class btCollisionAlgorithm; | |||
| class btCollisionObject; | |||
| struct btCollisionAlgorithmConstructionInfo; | |||
| ///Used by the btCollisionDispatcher to register and create instances for btCollisionAlgorithm | |||
| struct btCollisionAlgorithmCreateFunc | |||
| { | |||
| bool m_swapped; | |||
| btCollisionAlgorithmCreateFunc() | |||
| :m_swapped(false) | |||
| { | |||
| } | |||
| virtual ~btCollisionAlgorithmCreateFunc(){}; | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& , btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| (void)body0; | |||
| (void)body1; | |||
| return 0; | |||
| } | |||
| }; | |||
| #endif //BT_COLLISION_CREATE_FUNC | |||
| @@ -0,0 +1,310 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btCollisionDispatcher.h" | |||
| #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionShapes/btCollisionShape.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" | |||
| #include "LinearMath/btPoolAllocator.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionConfiguration.h" | |||
| int gNumManifold = 0; | |||
| #ifdef BT_DEBUG | |||
| #include <stdio.h> | |||
| #endif | |||
| btCollisionDispatcher::btCollisionDispatcher (btCollisionConfiguration* collisionConfiguration): | |||
| m_dispatcherFlags(btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD), | |||
| m_collisionConfiguration(collisionConfiguration) | |||
| { | |||
| int i; | |||
| setNearCallback(defaultNearCallback); | |||
| m_collisionAlgorithmPoolAllocator = collisionConfiguration->getCollisionAlgorithmPool(); | |||
| m_persistentManifoldPoolAllocator = collisionConfiguration->getPersistentManifoldPool(); | |||
| for (i=0;i<MAX_BROADPHASE_COLLISION_TYPES;i++) | |||
| { | |||
| for (int j=0;j<MAX_BROADPHASE_COLLISION_TYPES;j++) | |||
| { | |||
| m_doubleDispatch[i][j] = m_collisionConfiguration->getCollisionAlgorithmCreateFunc(i,j); | |||
| btAssert(m_doubleDispatch[i][j]); | |||
| } | |||
| } | |||
| } | |||
| void btCollisionDispatcher::registerCollisionCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc) | |||
| { | |||
| m_doubleDispatch[proxyType0][proxyType1] = createFunc; | |||
| } | |||
| btCollisionDispatcher::~btCollisionDispatcher() | |||
| { | |||
| } | |||
| btPersistentManifold* btCollisionDispatcher::getNewManifold(void* b0,void* b1) | |||
| { | |||
| gNumManifold++; | |||
| //btAssert(gNumManifold < 65535); | |||
| btCollisionObject* body0 = (btCollisionObject*)b0; | |||
| btCollisionObject* body1 = (btCollisionObject*)b1; | |||
| //optional relative contact breaking threshold, turned on by default (use setDispatcherFlags to switch off feature for improved performance) | |||
| btScalar contactBreakingThreshold = (m_dispatcherFlags & btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD) ? | |||
| btMin(body0->getCollisionShape()->getContactBreakingThreshold(gContactBreakingThreshold) , body1->getCollisionShape()->getContactBreakingThreshold(gContactBreakingThreshold)) | |||
| : gContactBreakingThreshold ; | |||
| btScalar contactProcessingThreshold = btMin(body0->getContactProcessingThreshold(),body1->getContactProcessingThreshold()); | |||
| void* mem = 0; | |||
| if (m_persistentManifoldPoolAllocator->getFreeCount()) | |||
| { | |||
| mem = m_persistentManifoldPoolAllocator->allocate(sizeof(btPersistentManifold)); | |||
| } else | |||
| { | |||
| //we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert. | |||
| if ((m_dispatcherFlags&CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION)==0) | |||
| { | |||
| mem = btAlignedAlloc(sizeof(btPersistentManifold),16); | |||
| } else | |||
| { | |||
| btAssert(0); | |||
| //make sure to increase the m_defaultMaxPersistentManifoldPoolSize in the btDefaultCollisionConstructionInfo/btDefaultCollisionConfiguration | |||
| return 0; | |||
| } | |||
| } | |||
| btPersistentManifold* manifold = new(mem) btPersistentManifold (body0,body1,0,contactBreakingThreshold,contactProcessingThreshold); | |||
| manifold->m_index1a = m_manifoldsPtr.size(); | |||
| m_manifoldsPtr.push_back(manifold); | |||
| return manifold; | |||
| } | |||
| void btCollisionDispatcher::clearManifold(btPersistentManifold* manifold) | |||
| { | |||
| manifold->clearManifold(); | |||
| } | |||
| void btCollisionDispatcher::releaseManifold(btPersistentManifold* manifold) | |||
| { | |||
| gNumManifold--; | |||
| //printf("releaseManifold: gNumManifold %d\n",gNumManifold); | |||
| clearManifold(manifold); | |||
| int findIndex = manifold->m_index1a; | |||
| btAssert(findIndex < m_manifoldsPtr.size()); | |||
| m_manifoldsPtr.swap(findIndex,m_manifoldsPtr.size()-1); | |||
| m_manifoldsPtr[findIndex]->m_index1a = findIndex; | |||
| m_manifoldsPtr.pop_back(); | |||
| manifold->~btPersistentManifold(); | |||
| if (m_persistentManifoldPoolAllocator->validPtr(manifold)) | |||
| { | |||
| m_persistentManifoldPoolAllocator->freeMemory(manifold); | |||
| } else | |||
| { | |||
| btAlignedFree(manifold); | |||
| } | |||
| } | |||
| btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold) | |||
| { | |||
| btCollisionAlgorithmConstructionInfo ci; | |||
| ci.m_dispatcher1 = this; | |||
| ci.m_manifold = sharedManifold; | |||
| btCollisionAlgorithm* algo = m_doubleDispatch[body0->getCollisionShape()->getShapeType()][body1->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci,body0,body1); | |||
| return algo; | |||
| } | |||
| bool btCollisionDispatcher::needsResponse(btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| //here you can do filtering | |||
| bool hasResponse = | |||
| (body0->hasContactResponse() && body1->hasContactResponse()); | |||
| //no response between two static/kinematic bodies: | |||
| hasResponse = hasResponse && | |||
| ((!body0->isStaticOrKinematicObject()) ||(! body1->isStaticOrKinematicObject())); | |||
| return hasResponse; | |||
| } | |||
| bool btCollisionDispatcher::needsCollision(btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| btAssert(body0); | |||
| btAssert(body1); | |||
| bool needsCollision = true; | |||
| #ifdef BT_DEBUG | |||
| if (!(m_dispatcherFlags & btCollisionDispatcher::CD_STATIC_STATIC_REPORTED)) | |||
| { | |||
| //broadphase filtering already deals with this | |||
| if (body0->isStaticOrKinematicObject() && body1->isStaticOrKinematicObject()) | |||
| { | |||
| m_dispatcherFlags |= btCollisionDispatcher::CD_STATIC_STATIC_REPORTED; | |||
| printf("warning btCollisionDispatcher::needsCollision: static-static collision!\n"); | |||
| } | |||
| } | |||
| #endif //BT_DEBUG | |||
| if ((!body0->isActive()) && (!body1->isActive())) | |||
| needsCollision = false; | |||
| else if (!body0->checkCollideWith(body1)) | |||
| needsCollision = false; | |||
| return needsCollision ; | |||
| } | |||
| ///interface for iterating all overlapping collision pairs, no matter how those pairs are stored (array, set, map etc) | |||
| ///this is useful for the collision dispatcher. | |||
| class btCollisionPairCallback : public btOverlapCallback | |||
| { | |||
| const btDispatcherInfo& m_dispatchInfo; | |||
| btCollisionDispatcher* m_dispatcher; | |||
| public: | |||
| btCollisionPairCallback(const btDispatcherInfo& dispatchInfo,btCollisionDispatcher* dispatcher) | |||
| :m_dispatchInfo(dispatchInfo), | |||
| m_dispatcher(dispatcher) | |||
| { | |||
| } | |||
| /*btCollisionPairCallback& operator=(btCollisionPairCallback& other) | |||
| { | |||
| m_dispatchInfo = other.m_dispatchInfo; | |||
| m_dispatcher = other.m_dispatcher; | |||
| return *this; | |||
| } | |||
| */ | |||
| virtual ~btCollisionPairCallback() {} | |||
| virtual bool processOverlap(btBroadphasePair& pair) | |||
| { | |||
| (*m_dispatcher->getNearCallback())(pair,*m_dispatcher,m_dispatchInfo); | |||
| return false; | |||
| } | |||
| }; | |||
| void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) | |||
| { | |||
| //m_blockedForChanges = true; | |||
| btCollisionPairCallback collisionCallback(dispatchInfo,this); | |||
| pairCache->processAllOverlappingPairs(&collisionCallback,dispatcher); | |||
| //m_blockedForChanges = false; | |||
| } | |||
| //by default, Bullet will use this near callback | |||
| void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo) | |||
| { | |||
| btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject; | |||
| btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject; | |||
| if (dispatcher.needsCollision(colObj0,colObj1)) | |||
| { | |||
| //dispatcher will keep algorithms persistent in the collision pair | |||
| if (!collisionPair.m_algorithm) | |||
| { | |||
| collisionPair.m_algorithm = dispatcher.findAlgorithm(colObj0,colObj1); | |||
| } | |||
| if (collisionPair.m_algorithm) | |||
| { | |||
| btManifoldResult contactPointResult(colObj0,colObj1); | |||
| if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE) | |||
| { | |||
| //discrete collision detection query | |||
| collisionPair.m_algorithm->processCollision(colObj0,colObj1,dispatchInfo,&contactPointResult); | |||
| } else | |||
| { | |||
| //continuous collision detection query, time of impact (toi) | |||
| btScalar toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0,colObj1,dispatchInfo,&contactPointResult); | |||
| if (dispatchInfo.m_timeOfImpact > toi) | |||
| dispatchInfo.m_timeOfImpact = toi; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| void* btCollisionDispatcher::allocateCollisionAlgorithm(int size) | |||
| { | |||
| if (m_collisionAlgorithmPoolAllocator->getFreeCount()) | |||
| { | |||
| return m_collisionAlgorithmPoolAllocator->allocate(size); | |||
| } | |||
| //warn user for overflow? | |||
| return btAlignedAlloc(static_cast<size_t>(size), 16); | |||
| } | |||
| void btCollisionDispatcher::freeCollisionAlgorithm(void* ptr) | |||
| { | |||
| if (m_collisionAlgorithmPoolAllocator->validPtr(ptr)) | |||
| { | |||
| m_collisionAlgorithmPoolAllocator->freeMemory(ptr); | |||
| } else | |||
| { | |||
| btAlignedFree(ptr); | |||
| } | |||
| } | |||
| @@ -0,0 +1,172 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_COLLISION__DISPATCHER_H | |||
| #define BT_COLLISION__DISPATCHER_H | |||
| #include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
| #include "BulletCollision/CollisionDispatch/btManifoldResult.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| class btIDebugDraw; | |||
| class btOverlappingPairCache; | |||
| class btPoolAllocator; | |||
| class btCollisionConfiguration; | |||
| #include "btCollisionCreateFunc.h" | |||
| #define USE_DISPATCH_REGISTRY_ARRAY 1 | |||
| class btCollisionDispatcher; | |||
| ///user can override this nearcallback for collision filtering and more finegrained control over collision detection | |||
| typedef void (*btNearCallback)(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo); | |||
| ///btCollisionDispatcher supports algorithms that handle ConvexConvex and ConvexConcave collision pairs. | |||
| ///Time of Impact, Closest Points and Penetration Depth. | |||
| class btCollisionDispatcher : public btDispatcher | |||
| { | |||
| protected: | |||
| int m_dispatcherFlags; | |||
| btAlignedObjectArray<btPersistentManifold*> m_manifoldsPtr; | |||
| btManifoldResult m_defaultManifoldResult; | |||
| btNearCallback m_nearCallback; | |||
| btPoolAllocator* m_collisionAlgorithmPoolAllocator; | |||
| btPoolAllocator* m_persistentManifoldPoolAllocator; | |||
| btCollisionAlgorithmCreateFunc* m_doubleDispatch[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES]; | |||
| btCollisionConfiguration* m_collisionConfiguration; | |||
| public: | |||
| enum DispatcherFlags | |||
| { | |||
| CD_STATIC_STATIC_REPORTED = 1, | |||
| CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD = 2, | |||
| CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION = 4 | |||
| }; | |||
| int getDispatcherFlags() const | |||
| { | |||
| return m_dispatcherFlags; | |||
| } | |||
| void setDispatcherFlags(int flags) | |||
| { | |||
| m_dispatcherFlags = flags; | |||
| } | |||
| ///registerCollisionCreateFunc allows registration of custom/alternative collision create functions | |||
| void registerCollisionCreateFunc(int proxyType0,int proxyType1, btCollisionAlgorithmCreateFunc* createFunc); | |||
| int getNumManifolds() const | |||
| { | |||
| return int( m_manifoldsPtr.size()); | |||
| } | |||
| btPersistentManifold** getInternalManifoldPointer() | |||
| { | |||
| return m_manifoldsPtr.size()? &m_manifoldsPtr[0] : 0; | |||
| } | |||
| btPersistentManifold* getManifoldByIndexInternal(int index) | |||
| { | |||
| return m_manifoldsPtr[index]; | |||
| } | |||
| const btPersistentManifold* getManifoldByIndexInternal(int index) const | |||
| { | |||
| return m_manifoldsPtr[index]; | |||
| } | |||
| btCollisionDispatcher (btCollisionConfiguration* collisionConfiguration); | |||
| virtual ~btCollisionDispatcher(); | |||
| virtual btPersistentManifold* getNewManifold(void* b0,void* b1); | |||
| virtual void releaseManifold(btPersistentManifold* manifold); | |||
| virtual void clearManifold(btPersistentManifold* manifold); | |||
| btCollisionAlgorithm* findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold = 0); | |||
| virtual bool needsCollision(btCollisionObject* body0,btCollisionObject* body1); | |||
| virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1); | |||
| virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) ; | |||
| void setNearCallback(btNearCallback nearCallback) | |||
| { | |||
| m_nearCallback = nearCallback; | |||
| } | |||
| btNearCallback getNearCallback() const | |||
| { | |||
| return m_nearCallback; | |||
| } | |||
| //by default, Bullet will use this near callback | |||
| static void defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo); | |||
| virtual void* allocateCollisionAlgorithm(int size); | |||
| virtual void freeCollisionAlgorithm(void* ptr); | |||
| btCollisionConfiguration* getCollisionConfiguration() | |||
| { | |||
| return m_collisionConfiguration; | |||
| } | |||
| const btCollisionConfiguration* getCollisionConfiguration() const | |||
| { | |||
| return m_collisionConfiguration; | |||
| } | |||
| void setCollisionConfiguration(btCollisionConfiguration* config) | |||
| { | |||
| m_collisionConfiguration = config; | |||
| } | |||
| virtual btPoolAllocator* getInternalManifoldPool() | |||
| { | |||
| return m_persistentManifoldPoolAllocator; | |||
| } | |||
| virtual const btPoolAllocator* getInternalManifoldPool() const | |||
| { | |||
| return m_persistentManifoldPoolAllocator; | |||
| } | |||
| }; | |||
| #endif //BT_COLLISION__DISPATCHER_H | |||
| @@ -0,0 +1,116 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btCollisionObject.h" | |||
| #include "LinearMath/btSerializer.h" | |||
| btCollisionObject::btCollisionObject() | |||
| : m_anisotropicFriction(1.f,1.f,1.f), | |||
| m_hasAnisotropicFriction(false), | |||
| m_contactProcessingThreshold(BT_LARGE_FLOAT), | |||
| m_broadphaseHandle(0), | |||
| m_collisionShape(0), | |||
| m_extensionPointer(0), | |||
| m_rootCollisionShape(0), | |||
| m_collisionFlags(btCollisionObject::CF_STATIC_OBJECT), | |||
| m_islandTag1(-1), | |||
| m_companionId(-1), | |||
| m_activationState1(1), | |||
| m_deactivationTime(btScalar(0.)), | |||
| m_friction(btScalar(0.5)), | |||
| m_restitution(btScalar(0.)), | |||
| m_internalType(CO_COLLISION_OBJECT), | |||
| m_userObjectPointer(0), | |||
| m_hitFraction(btScalar(1.)), | |||
| m_ccdSweptSphereRadius(btScalar(0.)), | |||
| m_ccdMotionThreshold(btScalar(0.)), | |||
| m_checkCollideWith(false) | |||
| { | |||
| m_worldTransform.setIdentity(); | |||
| } | |||
| btCollisionObject::~btCollisionObject() | |||
| { | |||
| } | |||
| void btCollisionObject::setActivationState(int newState) | |||
| { | |||
| if ( (m_activationState1 != DISABLE_DEACTIVATION) && (m_activationState1 != DISABLE_SIMULATION)) | |||
| m_activationState1 = newState; | |||
| } | |||
| void btCollisionObject::forceActivationState(int newState) | |||
| { | |||
| m_activationState1 = newState; | |||
| } | |||
| void btCollisionObject::activate(bool forceActivation) | |||
| { | |||
| if (forceActivation || !(m_collisionFlags & (CF_STATIC_OBJECT|CF_KINEMATIC_OBJECT))) | |||
| { | |||
| setActivationState(ACTIVE_TAG); | |||
| m_deactivationTime = btScalar(0.); | |||
| } | |||
| } | |||
| const char* btCollisionObject::serialize(void* dataBuffer, btSerializer* serializer) const | |||
| { | |||
| btCollisionObjectData* dataOut = (btCollisionObjectData*)dataBuffer; | |||
| m_worldTransform.serialize(dataOut->m_worldTransform); | |||
| m_interpolationWorldTransform.serialize(dataOut->m_interpolationWorldTransform); | |||
| m_interpolationLinearVelocity.serialize(dataOut->m_interpolationLinearVelocity); | |||
| m_interpolationAngularVelocity.serialize(dataOut->m_interpolationAngularVelocity); | |||
| m_anisotropicFriction.serialize(dataOut->m_anisotropicFriction); | |||
| dataOut->m_hasAnisotropicFriction = m_hasAnisotropicFriction; | |||
| dataOut->m_contactProcessingThreshold = m_contactProcessingThreshold; | |||
| dataOut->m_broadphaseHandle = 0; | |||
| dataOut->m_collisionShape = serializer->getUniquePointer(m_collisionShape); | |||
| dataOut->m_rootCollisionShape = 0;//@todo | |||
| dataOut->m_collisionFlags = m_collisionFlags; | |||
| dataOut->m_islandTag1 = m_islandTag1; | |||
| dataOut->m_companionId = m_companionId; | |||
| dataOut->m_activationState1 = m_activationState1; | |||
| dataOut->m_activationState1 = m_activationState1; | |||
| dataOut->m_deactivationTime = m_deactivationTime; | |||
| dataOut->m_friction = m_friction; | |||
| dataOut->m_restitution = m_restitution; | |||
| dataOut->m_internalType = m_internalType; | |||
| char* name = (char*) serializer->findNameForPointer(this); | |||
| dataOut->m_name = (char*)serializer->getUniquePointer(name); | |||
| if (dataOut->m_name) | |||
| { | |||
| serializer->serializeName(name); | |||
| } | |||
| dataOut->m_hitFraction = m_hitFraction; | |||
| dataOut->m_ccdSweptSphereRadius = m_ccdSweptSphereRadius; | |||
| dataOut->m_ccdMotionThreshold = m_ccdMotionThreshold; | |||
| dataOut->m_ccdMotionThreshold = m_ccdMotionThreshold; | |||
| dataOut->m_checkCollideWith = m_checkCollideWith; | |||
| return btCollisionObjectDataName; | |||
| } | |||
| void btCollisionObject::serializeSingleObject(class btSerializer* serializer) const | |||
| { | |||
| int len = calculateSerializeBufferSize(); | |||
| btChunk* chunk = serializer->allocate(len,1); | |||
| const char* structType = serialize(chunk->m_oldPtr, serializer); | |||
| serializer->finalizeChunk(chunk,structType,BT_COLLISIONOBJECT_CODE,(void*)this); | |||
| } | |||
| @@ -0,0 +1,524 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_COLLISION_OBJECT_H | |||
| #define BT_COLLISION_OBJECT_H | |||
| #include "LinearMath/btTransform.h" | |||
| //island management, m_activationState1 | |||
| #define ACTIVE_TAG 1 | |||
| #define ISLAND_SLEEPING 2 | |||
| #define WANTS_DEACTIVATION 3 | |||
| #define DISABLE_DEACTIVATION 4 | |||
| #define DISABLE_SIMULATION 5 | |||
| struct btBroadphaseProxy; | |||
| class btCollisionShape; | |||
| struct btCollisionShapeData; | |||
| #include "LinearMath/btMotionState.h" | |||
| #include "LinearMath/btAlignedAllocator.h" | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| typedef btAlignedObjectArray<class btCollisionObject*> btCollisionObjectArray; | |||
| #ifdef BT_USE_DOUBLE_PRECISION | |||
| #define btCollisionObjectData btCollisionObjectDoubleData | |||
| #define btCollisionObjectDataName "btCollisionObjectDoubleData" | |||
| #else | |||
| #define btCollisionObjectData btCollisionObjectFloatData | |||
| #define btCollisionObjectDataName "btCollisionObjectFloatData" | |||
| #endif | |||
| /// btCollisionObject can be used to manage collision detection objects. | |||
| /// btCollisionObject maintains all information that is needed for a collision detection: Shape, Transform and AABB proxy. | |||
| /// They can be added to the btCollisionWorld. | |||
| ATTRIBUTE_ALIGNED16(class) btCollisionObject | |||
| { | |||
| protected: | |||
| btTransform m_worldTransform; | |||
| ///m_interpolationWorldTransform is used for CCD and interpolation | |||
| ///it can be either previous or future (predicted) transform | |||
| btTransform m_interpolationWorldTransform; | |||
| //those two are experimental: just added for bullet time effect, so you can still apply impulses (directly modifying velocities) | |||
| //without destroying the continuous interpolated motion (which uses this interpolation velocities) | |||
| btVector3 m_interpolationLinearVelocity; | |||
| btVector3 m_interpolationAngularVelocity; | |||
| btVector3 m_anisotropicFriction; | |||
| int m_hasAnisotropicFriction; | |||
| btScalar m_contactProcessingThreshold; | |||
| btBroadphaseProxy* m_broadphaseHandle; | |||
| btCollisionShape* m_collisionShape; | |||
| ///m_extensionPointer is used by some internal low-level Bullet extensions. | |||
| void* m_extensionPointer; | |||
| ///m_rootCollisionShape is temporarily used to store the original collision shape | |||
| ///The m_collisionShape might be temporarily replaced by a child collision shape during collision detection purposes | |||
| ///If it is NULL, the m_collisionShape is not temporarily replaced. | |||
| btCollisionShape* m_rootCollisionShape; | |||
| int m_collisionFlags; | |||
| int m_islandTag1; | |||
| int m_companionId; | |||
| int m_activationState1; | |||
| btScalar m_deactivationTime; | |||
| btScalar m_friction; | |||
| btScalar m_restitution; | |||
| ///m_internalType is reserved to distinguish Bullet's btCollisionObject, btRigidBody, btSoftBody, btGhostObject etc. | |||
| ///do not assign your own m_internalType unless you write a new dynamics object class. | |||
| int m_internalType; | |||
| ///users can point to their objects, m_userPointer is not used by Bullet, see setUserPointer/getUserPointer | |||
| void* m_userObjectPointer; | |||
| ///time of impact calculation | |||
| btScalar m_hitFraction; | |||
| ///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: | |||
| btScalar m_ccdSweptSphereRadius; | |||
| /// Don't do continuous collision detection if the motion (in one step) is less then m_ccdMotionThreshold | |||
| btScalar m_ccdMotionThreshold; | |||
| /// If some object should have elaborate collision filtering by sub-classes | |||
| int m_checkCollideWith; | |||
| virtual bool checkCollideWithOverride(btCollisionObject* /* co */) | |||
| { | |||
| return true; | |||
| } | |||
| public: | |||
| BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
| enum CollisionFlags | |||
| { | |||
| CF_STATIC_OBJECT= 1, | |||
| CF_KINEMATIC_OBJECT= 2, | |||
| CF_NO_CONTACT_RESPONSE = 4, | |||
| CF_CUSTOM_MATERIAL_CALLBACK = 8,//this allows per-triangle material (friction/restitution) | |||
| CF_CHARACTER_OBJECT = 16, | |||
| CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing | |||
| CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing | |||
| }; | |||
| enum CollisionObjectTypes | |||
| { | |||
| CO_COLLISION_OBJECT =1, | |||
| CO_RIGID_BODY=2, | |||
| ///CO_GHOST_OBJECT keeps track of all objects overlapping its AABB and that pass its collision filter | |||
| ///It is useful for collision sensors, explosion objects, character controller etc. | |||
| CO_GHOST_OBJECT=4, | |||
| CO_SOFT_BODY=8, | |||
| CO_HF_FLUID=16, | |||
| CO_USER_TYPE=32 | |||
| }; | |||
| SIMD_FORCE_INLINE bool mergesSimulationIslands() const | |||
| { | |||
| ///static objects, kinematic and object without contact response don't merge islands | |||
| return ((m_collisionFlags & (CF_STATIC_OBJECT | CF_KINEMATIC_OBJECT | CF_NO_CONTACT_RESPONSE) )==0); | |||
| } | |||
| const btVector3& getAnisotropicFriction() const | |||
| { | |||
| return m_anisotropicFriction; | |||
| } | |||
| void setAnisotropicFriction(const btVector3& anisotropicFriction) | |||
| { | |||
| m_anisotropicFriction = anisotropicFriction; | |||
| m_hasAnisotropicFriction = (anisotropicFriction[0]!=1.f) || (anisotropicFriction[1]!=1.f) || (anisotropicFriction[2]!=1.f); | |||
| } | |||
| bool hasAnisotropicFriction() const | |||
| { | |||
| return m_hasAnisotropicFriction!=0; | |||
| } | |||
| ///the constraint solver can discard solving contacts, if the distance is above this threshold. 0 by default. | |||
| ///Note that using contacts with positive distance can improve stability. It increases, however, the chance of colliding with degerate contacts, such as 'interior' triangle edges | |||
| void setContactProcessingThreshold( btScalar contactProcessingThreshold) | |||
| { | |||
| m_contactProcessingThreshold = contactProcessingThreshold; | |||
| } | |||
| btScalar getContactProcessingThreshold() const | |||
| { | |||
| return m_contactProcessingThreshold; | |||
| } | |||
| SIMD_FORCE_INLINE bool isStaticObject() const { | |||
| return (m_collisionFlags & CF_STATIC_OBJECT) != 0; | |||
| } | |||
| SIMD_FORCE_INLINE bool isKinematicObject() const | |||
| { | |||
| return (m_collisionFlags & CF_KINEMATIC_OBJECT) != 0; | |||
| } | |||
| SIMD_FORCE_INLINE bool isStaticOrKinematicObject() const | |||
| { | |||
| return (m_collisionFlags & (CF_KINEMATIC_OBJECT | CF_STATIC_OBJECT)) != 0 ; | |||
| } | |||
| SIMD_FORCE_INLINE bool hasContactResponse() const { | |||
| return (m_collisionFlags & CF_NO_CONTACT_RESPONSE)==0; | |||
| } | |||
| btCollisionObject(); | |||
| virtual ~btCollisionObject(); | |||
| virtual void setCollisionShape(btCollisionShape* collisionShape) | |||
| { | |||
| m_collisionShape = collisionShape; | |||
| m_rootCollisionShape = collisionShape; | |||
| } | |||
| SIMD_FORCE_INLINE const btCollisionShape* getCollisionShape() const | |||
| { | |||
| return m_collisionShape; | |||
| } | |||
| SIMD_FORCE_INLINE btCollisionShape* getCollisionShape() | |||
| { | |||
| return m_collisionShape; | |||
| } | |||
| SIMD_FORCE_INLINE const btCollisionShape* getRootCollisionShape() const | |||
| { | |||
| return m_rootCollisionShape; | |||
| } | |||
| SIMD_FORCE_INLINE btCollisionShape* getRootCollisionShape() | |||
| { | |||
| return m_rootCollisionShape; | |||
| } | |||
| ///Avoid using this internal API call | |||
| ///internalSetTemporaryCollisionShape is used to temporary replace the actual collision shape by a child collision shape. | |||
| void internalSetTemporaryCollisionShape(btCollisionShape* collisionShape) | |||
| { | |||
| m_collisionShape = collisionShape; | |||
| } | |||
| ///Avoid using this internal API call, the extension pointer is used by some Bullet extensions. | |||
| ///If you need to store your own user pointer, use 'setUserPointer/getUserPointer' instead. | |||
| void* internalGetExtensionPointer() const | |||
| { | |||
| return m_extensionPointer; | |||
| } | |||
| ///Avoid using this internal API call, the extension pointer is used by some Bullet extensions | |||
| ///If you need to store your own user pointer, use 'setUserPointer/getUserPointer' instead. | |||
| void internalSetExtensionPointer(void* pointer) | |||
| { | |||
| m_extensionPointer = pointer; | |||
| } | |||
| SIMD_FORCE_INLINE int getActivationState() const { return m_activationState1;} | |||
| void setActivationState(int newState); | |||
| void setDeactivationTime(btScalar time) | |||
| { | |||
| m_deactivationTime = time; | |||
| } | |||
| btScalar getDeactivationTime() const | |||
| { | |||
| return m_deactivationTime; | |||
| } | |||
| void forceActivationState(int newState); | |||
| void activate(bool forceActivation = false); | |||
| SIMD_FORCE_INLINE bool isActive() const | |||
| { | |||
| return ((getActivationState() != ISLAND_SLEEPING) && (getActivationState() != DISABLE_SIMULATION)); | |||
| } | |||
| void setRestitution(btScalar rest) | |||
| { | |||
| m_restitution = rest; | |||
| } | |||
| btScalar getRestitution() const | |||
| { | |||
| return m_restitution; | |||
| } | |||
| void setFriction(btScalar frict) | |||
| { | |||
| m_friction = frict; | |||
| } | |||
| btScalar getFriction() const | |||
| { | |||
| return m_friction; | |||
| } | |||
| ///reserved for Bullet internal usage | |||
| int getInternalType() const | |||
| { | |||
| return m_internalType; | |||
| } | |||
| btTransform& getWorldTransform() | |||
| { | |||
| return m_worldTransform; | |||
| } | |||
| const btTransform& getWorldTransform() const | |||
| { | |||
| return m_worldTransform; | |||
| } | |||
| void setWorldTransform(const btTransform& worldTrans) | |||
| { | |||
| m_worldTransform = worldTrans; | |||
| } | |||
| SIMD_FORCE_INLINE btBroadphaseProxy* getBroadphaseHandle() | |||
| { | |||
| return m_broadphaseHandle; | |||
| } | |||
| SIMD_FORCE_INLINE const btBroadphaseProxy* getBroadphaseHandle() const | |||
| { | |||
| return m_broadphaseHandle; | |||
| } | |||
| void setBroadphaseHandle(btBroadphaseProxy* handle) | |||
| { | |||
| m_broadphaseHandle = handle; | |||
| } | |||
| const btTransform& getInterpolationWorldTransform() const | |||
| { | |||
| return m_interpolationWorldTransform; | |||
| } | |||
| btTransform& getInterpolationWorldTransform() | |||
| { | |||
| return m_interpolationWorldTransform; | |||
| } | |||
| void setInterpolationWorldTransform(const btTransform& trans) | |||
| { | |||
| m_interpolationWorldTransform = trans; | |||
| } | |||
| void setInterpolationLinearVelocity(const btVector3& linvel) | |||
| { | |||
| m_interpolationLinearVelocity = linvel; | |||
| } | |||
| void setInterpolationAngularVelocity(const btVector3& angvel) | |||
| { | |||
| m_interpolationAngularVelocity = angvel; | |||
| } | |||
| const btVector3& getInterpolationLinearVelocity() const | |||
| { | |||
| return m_interpolationLinearVelocity; | |||
| } | |||
| const btVector3& getInterpolationAngularVelocity() const | |||
| { | |||
| return m_interpolationAngularVelocity; | |||
| } | |||
| SIMD_FORCE_INLINE int getIslandTag() const | |||
| { | |||
| return m_islandTag1; | |||
| } | |||
| void setIslandTag(int tag) | |||
| { | |||
| m_islandTag1 = tag; | |||
| } | |||
| SIMD_FORCE_INLINE int getCompanionId() const | |||
| { | |||
| return m_companionId; | |||
| } | |||
| void setCompanionId(int id) | |||
| { | |||
| m_companionId = id; | |||
| } | |||
| SIMD_FORCE_INLINE btScalar getHitFraction() const | |||
| { | |||
| return m_hitFraction; | |||
| } | |||
| void setHitFraction(btScalar hitFraction) | |||
| { | |||
| m_hitFraction = hitFraction; | |||
| } | |||
| SIMD_FORCE_INLINE int getCollisionFlags() const | |||
| { | |||
| return m_collisionFlags; | |||
| } | |||
| void setCollisionFlags(int flags) | |||
| { | |||
| m_collisionFlags = flags; | |||
| } | |||
| ///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: | |||
| btScalar getCcdSweptSphereRadius() const | |||
| { | |||
| return m_ccdSweptSphereRadius; | |||
| } | |||
| ///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: | |||
| void setCcdSweptSphereRadius(btScalar radius) | |||
| { | |||
| m_ccdSweptSphereRadius = radius; | |||
| } | |||
| btScalar getCcdMotionThreshold() const | |||
| { | |||
| return m_ccdMotionThreshold; | |||
| } | |||
| btScalar getCcdSquareMotionThreshold() const | |||
| { | |||
| return m_ccdMotionThreshold*m_ccdMotionThreshold; | |||
| } | |||
| /// Don't do continuous collision detection if the motion (in one step) is less then m_ccdMotionThreshold | |||
| void setCcdMotionThreshold(btScalar ccdMotionThreshold) | |||
| { | |||
| m_ccdMotionThreshold = ccdMotionThreshold; | |||
| } | |||
| ///users can point to their objects, userPointer is not used by Bullet | |||
| void* getUserPointer() const | |||
| { | |||
| return m_userObjectPointer; | |||
| } | |||
| ///users can point to their objects, userPointer is not used by Bullet | |||
| void setUserPointer(void* userPointer) | |||
| { | |||
| m_userObjectPointer = userPointer; | |||
| } | |||
| inline bool checkCollideWith(btCollisionObject* co) | |||
| { | |||
| if (m_checkCollideWith) | |||
| return checkCollideWithOverride(co); | |||
| return true; | |||
| } | |||
| virtual int calculateSerializeBufferSize() const; | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| virtual const char* serialize(void* dataBuffer, class btSerializer* serializer) const; | |||
| virtual void serializeSingleObject(class btSerializer* serializer) const; | |||
| }; | |||
| ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
| struct btCollisionObjectDoubleData | |||
| { | |||
| void *m_broadphaseHandle; | |||
| void *m_collisionShape; | |||
| btCollisionShapeData *m_rootCollisionShape; | |||
| char *m_name; | |||
| btTransformDoubleData m_worldTransform; | |||
| btTransformDoubleData m_interpolationWorldTransform; | |||
| btVector3DoubleData m_interpolationLinearVelocity; | |||
| btVector3DoubleData m_interpolationAngularVelocity; | |||
| btVector3DoubleData m_anisotropicFriction; | |||
| double m_contactProcessingThreshold; | |||
| double m_deactivationTime; | |||
| double m_friction; | |||
| double m_restitution; | |||
| double m_hitFraction; | |||
| double m_ccdSweptSphereRadius; | |||
| double m_ccdMotionThreshold; | |||
| int m_hasAnisotropicFriction; | |||
| int m_collisionFlags; | |||
| int m_islandTag1; | |||
| int m_companionId; | |||
| int m_activationState1; | |||
| int m_internalType; | |||
| int m_checkCollideWith; | |||
| char m_padding[4]; | |||
| }; | |||
| ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
| struct btCollisionObjectFloatData | |||
| { | |||
| void *m_broadphaseHandle; | |||
| void *m_collisionShape; | |||
| btCollisionShapeData *m_rootCollisionShape; | |||
| char *m_name; | |||
| btTransformFloatData m_worldTransform; | |||
| btTransformFloatData m_interpolationWorldTransform; | |||
| btVector3FloatData m_interpolationLinearVelocity; | |||
| btVector3FloatData m_interpolationAngularVelocity; | |||
| btVector3FloatData m_anisotropicFriction; | |||
| float m_contactProcessingThreshold; | |||
| float m_deactivationTime; | |||
| float m_friction; | |||
| float m_restitution; | |||
| float m_hitFraction; | |||
| float m_ccdSweptSphereRadius; | |||
| float m_ccdMotionThreshold; | |||
| int m_hasAnisotropicFriction; | |||
| int m_collisionFlags; | |||
| int m_islandTag1; | |||
| int m_companionId; | |||
| int m_activationState1; | |||
| int m_internalType; | |||
| int m_checkCollideWith; | |||
| }; | |||
| SIMD_FORCE_INLINE int btCollisionObject::calculateSerializeBufferSize() const | |||
| { | |||
| return sizeof(btCollisionObjectData); | |||
| } | |||
| #endif //BT_COLLISION_OBJECT_H | |||
| @@ -0,0 +1,509 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://bulletphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| /** | |||
| * @mainpage Bullet Documentation | |||
| * | |||
| * @section intro_sec Introduction | |||
| * Bullet Collision Detection & Physics SDK | |||
| * | |||
| * Bullet is a Collision Detection and Rigid Body Dynamics Library. The Library is Open Source and free for commercial use, under the ZLib license ( http://opensource.org/licenses/zlib-license.php ). | |||
| * | |||
| * The main documentation is Bullet_User_Manual.pdf, included in the source code distribution. | |||
| * There is the Physics Forum for feedback and general Collision Detection and Physics discussions. | |||
| * Please visit http://www.bulletphysics.com | |||
| * | |||
| * @section install_sec Installation | |||
| * | |||
| * @subsection step1 Step 1: Download | |||
| * You can download the Bullet Physics Library from the Google Code repository: http://code.google.com/p/bullet/downloads/list | |||
| * | |||
| * @subsection step2 Step 2: Building | |||
| * Bullet main build system for all platforms is cmake, you can download http://www.cmake.org | |||
| * cmake can autogenerate projectfiles for Microsoft Visual Studio, Apple Xcode, KDevelop and Unix Makefiles. | |||
| * The easiest is to run the CMake cmake-gui graphical user interface and choose the options and generate projectfiles. | |||
| * You can also use cmake in the command-line. Here are some examples for various platforms: | |||
| * cmake . -G "Visual Studio 9 2008" | |||
| * cmake . -G Xcode | |||
| * cmake . -G "Unix Makefiles" | |||
| * Although cmake is recommended, you can also use autotools for UNIX: ./autogen.sh ./configure to create a Makefile and then run make. | |||
| * | |||
| * @subsection step3 Step 3: Testing demos | |||
| * Try to run and experiment with BasicDemo executable as a starting point. | |||
| * Bullet can be used in several ways, as Full Rigid Body simulation, as Collision Detector Library or Low Level / Snippets like the GJK Closest Point calculation. | |||
| * The Dependencies can be seen in this documentation under Directories | |||
| * | |||
| * @subsection step4 Step 4: Integrating in your application, full Rigid Body and Soft Body simulation | |||
| * Check out BasicDemo how to create a btDynamicsWorld, btRigidBody and btCollisionShape, Stepping the simulation and synchronizing your graphics object transform. | |||
| * Check out SoftDemo how to use soft body dynamics, using btSoftRigidDynamicsWorld. | |||
| * @subsection step5 Step 5 : Integrate the Collision Detection Library (without Dynamics and other Extras) | |||
| * Bullet Collision Detection can also be used without the Dynamics/Extras. | |||
| * Check out btCollisionWorld and btCollisionObject, and the CollisionInterfaceDemo. | |||
| * @subsection step6 Step 6 : Use Snippets like the GJK Closest Point calculation. | |||
| * Bullet has been designed in a modular way keeping dependencies to a minimum. The ConvexHullDistance demo demonstrates direct use of btGjkPairDetector. | |||
| * | |||
| * @section copyright Copyright | |||
| * For up-to-data information and copyright and contributors list check out the Bullet_User_Manual.pdf | |||
| * | |||
| */ | |||
| #ifndef BT_COLLISION_WORLD_H | |||
| #define BT_COLLISION_WORLD_H | |||
| class btStackAlloc; | |||
| class btCollisionShape; | |||
| class btConvexShape; | |||
| class btBroadphaseInterface; | |||
| class btSerializer; | |||
| #include "LinearMath/btVector3.h" | |||
| #include "LinearMath/btTransform.h" | |||
| #include "btCollisionObject.h" | |||
| #include "btCollisionDispatcher.h" | |||
| #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| ///CollisionWorld is interface and container for the collision detection | |||
| class btCollisionWorld | |||
| { | |||
| protected: | |||
| btAlignedObjectArray<btCollisionObject*> m_collisionObjects; | |||
| btDispatcher* m_dispatcher1; | |||
| btDispatcherInfo m_dispatchInfo; | |||
| btStackAlloc* m_stackAlloc; | |||
| btBroadphaseInterface* m_broadphasePairCache; | |||
| btIDebugDraw* m_debugDrawer; | |||
| ///m_forceUpdateAllAabbs can be set to false as an optimization to only update active object AABBs | |||
| ///it is true by default, because it is error-prone (setting the position of static objects wouldn't update their AABB) | |||
| bool m_forceUpdateAllAabbs; | |||
| void serializeCollisionObjects(btSerializer* serializer); | |||
| public: | |||
| //this constructor doesn't own the dispatcher and paircache/broadphase | |||
| btCollisionWorld(btDispatcher* dispatcher,btBroadphaseInterface* broadphasePairCache, btCollisionConfiguration* collisionConfiguration); | |||
| virtual ~btCollisionWorld(); | |||
| void setBroadphase(btBroadphaseInterface* pairCache) | |||
| { | |||
| m_broadphasePairCache = pairCache; | |||
| } | |||
| const btBroadphaseInterface* getBroadphase() const | |||
| { | |||
| return m_broadphasePairCache; | |||
| } | |||
| btBroadphaseInterface* getBroadphase() | |||
| { | |||
| return m_broadphasePairCache; | |||
| } | |||
| btOverlappingPairCache* getPairCache() | |||
| { | |||
| return m_broadphasePairCache->getOverlappingPairCache(); | |||
| } | |||
| btDispatcher* getDispatcher() | |||
| { | |||
| return m_dispatcher1; | |||
| } | |||
| const btDispatcher* getDispatcher() const | |||
| { | |||
| return m_dispatcher1; | |||
| } | |||
| void updateSingleAabb(btCollisionObject* colObj); | |||
| virtual void updateAabbs(); | |||
| virtual void setDebugDrawer(btIDebugDraw* debugDrawer) | |||
| { | |||
| m_debugDrawer = debugDrawer; | |||
| } | |||
| virtual btIDebugDraw* getDebugDrawer() | |||
| { | |||
| return m_debugDrawer; | |||
| } | |||
| virtual void debugDrawWorld(); | |||
| virtual void debugDrawObject(const btTransform& worldTransform, const btCollisionShape* shape, const btVector3& color); | |||
| ///LocalShapeInfo gives extra information for complex shapes | |||
| ///Currently, only btTriangleMeshShape is available, so it just contains triangleIndex and subpart | |||
| struct LocalShapeInfo | |||
| { | |||
| int m_shapePart; | |||
| int m_triangleIndex; | |||
| //const btCollisionShape* m_shapeTemp; | |||
| //const btTransform* m_shapeLocalTransform; | |||
| }; | |||
| struct LocalRayResult | |||
| { | |||
| LocalRayResult(btCollisionObject* collisionObject, | |||
| LocalShapeInfo* localShapeInfo, | |||
| const btVector3& hitNormalLocal, | |||
| btScalar hitFraction) | |||
| :m_collisionObject(collisionObject), | |||
| m_localShapeInfo(localShapeInfo), | |||
| m_hitNormalLocal(hitNormalLocal), | |||
| m_hitFraction(hitFraction) | |||
| { | |||
| } | |||
| btCollisionObject* m_collisionObject; | |||
| LocalShapeInfo* m_localShapeInfo; | |||
| btVector3 m_hitNormalLocal; | |||
| btScalar m_hitFraction; | |||
| }; | |||
| ///RayResultCallback is used to report new raycast results | |||
| struct RayResultCallback | |||
| { | |||
| btScalar m_closestHitFraction; | |||
| btCollisionObject* m_collisionObject; | |||
| short int m_collisionFilterGroup; | |||
| short int m_collisionFilterMask; | |||
| //@BP Mod - Custom flags, currently used to enable backface culling on tri-meshes, see btRaycastCallback | |||
| unsigned int m_flags; | |||
| virtual ~RayResultCallback() | |||
| { | |||
| } | |||
| bool hasHit() const | |||
| { | |||
| return (m_collisionObject != 0); | |||
| } | |||
| RayResultCallback() | |||
| :m_closestHitFraction(btScalar(1.)), | |||
| m_collisionObject(0), | |||
| m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), | |||
| m_collisionFilterMask(btBroadphaseProxy::AllFilter), | |||
| //@BP Mod | |||
| m_flags(0) | |||
| { | |||
| } | |||
| virtual bool needsCollision(btBroadphaseProxy* proxy0) const | |||
| { | |||
| bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0; | |||
| collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask); | |||
| return collides; | |||
| } | |||
| virtual btScalar addSingleResult(LocalRayResult& rayResult,bool normalInWorldSpace) = 0; | |||
| }; | |||
| struct ClosestRayResultCallback : public RayResultCallback | |||
| { | |||
| ClosestRayResultCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld) | |||
| :m_rayFromWorld(rayFromWorld), | |||
| m_rayToWorld(rayToWorld) | |||
| { | |||
| } | |||
| btVector3 m_rayFromWorld;//used to calculate hitPointWorld from hitFraction | |||
| btVector3 m_rayToWorld; | |||
| btVector3 m_hitNormalWorld; | |||
| btVector3 m_hitPointWorld; | |||
| virtual btScalar addSingleResult(LocalRayResult& rayResult,bool normalInWorldSpace) | |||
| { | |||
| //caller already does the filter on the m_closestHitFraction | |||
| btAssert(rayResult.m_hitFraction <= m_closestHitFraction); | |||
| m_closestHitFraction = rayResult.m_hitFraction; | |||
| m_collisionObject = rayResult.m_collisionObject; | |||
| if (normalInWorldSpace) | |||
| { | |||
| m_hitNormalWorld = rayResult.m_hitNormalLocal; | |||
| } else | |||
| { | |||
| ///need to transform normal into worldspace | |||
| m_hitNormalWorld = m_collisionObject->getWorldTransform().getBasis()*rayResult.m_hitNormalLocal; | |||
| } | |||
| m_hitPointWorld.setInterpolate3(m_rayFromWorld,m_rayToWorld,rayResult.m_hitFraction); | |||
| return rayResult.m_hitFraction; | |||
| } | |||
| }; | |||
| struct AllHitsRayResultCallback : public RayResultCallback | |||
| { | |||
| AllHitsRayResultCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld) | |||
| :m_rayFromWorld(rayFromWorld), | |||
| m_rayToWorld(rayToWorld) | |||
| { | |||
| } | |||
| btAlignedObjectArray<btCollisionObject*> m_collisionObjects; | |||
| btVector3 m_rayFromWorld;//used to calculate hitPointWorld from hitFraction | |||
| btVector3 m_rayToWorld; | |||
| btAlignedObjectArray<btVector3> m_hitNormalWorld; | |||
| btAlignedObjectArray<btVector3> m_hitPointWorld; | |||
| btAlignedObjectArray<btScalar> m_hitFractions; | |||
| virtual btScalar addSingleResult(LocalRayResult& rayResult,bool normalInWorldSpace) | |||
| { | |||
| m_collisionObject = rayResult.m_collisionObject; | |||
| m_collisionObjects.push_back(rayResult.m_collisionObject); | |||
| btVector3 hitNormalWorld; | |||
| if (normalInWorldSpace) | |||
| { | |||
| hitNormalWorld = rayResult.m_hitNormalLocal; | |||
| } else | |||
| { | |||
| ///need to transform normal into worldspace | |||
| hitNormalWorld = m_collisionObject->getWorldTransform().getBasis()*rayResult.m_hitNormalLocal; | |||
| } | |||
| m_hitNormalWorld.push_back(hitNormalWorld); | |||
| btVector3 hitPointWorld; | |||
| hitPointWorld.setInterpolate3(m_rayFromWorld,m_rayToWorld,rayResult.m_hitFraction); | |||
| m_hitPointWorld.push_back(hitPointWorld); | |||
| m_hitFractions.push_back(rayResult.m_hitFraction); | |||
| return m_closestHitFraction; | |||
| } | |||
| }; | |||
| struct LocalConvexResult | |||
| { | |||
| LocalConvexResult(btCollisionObject* hitCollisionObject, | |||
| LocalShapeInfo* localShapeInfo, | |||
| const btVector3& hitNormalLocal, | |||
| const btVector3& hitPointLocal, | |||
| btScalar hitFraction | |||
| ) | |||
| :m_hitCollisionObject(hitCollisionObject), | |||
| m_localShapeInfo(localShapeInfo), | |||
| m_hitNormalLocal(hitNormalLocal), | |||
| m_hitPointLocal(hitPointLocal), | |||
| m_hitFraction(hitFraction) | |||
| { | |||
| } | |||
| btCollisionObject* m_hitCollisionObject; | |||
| LocalShapeInfo* m_localShapeInfo; | |||
| btVector3 m_hitNormalLocal; | |||
| btVector3 m_hitPointLocal; | |||
| btScalar m_hitFraction; | |||
| }; | |||
| ///RayResultCallback is used to report new raycast results | |||
| struct ConvexResultCallback | |||
| { | |||
| btScalar m_closestHitFraction; | |||
| short int m_collisionFilterGroup; | |||
| short int m_collisionFilterMask; | |||
| ConvexResultCallback() | |||
| :m_closestHitFraction(btScalar(1.)), | |||
| m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), | |||
| m_collisionFilterMask(btBroadphaseProxy::AllFilter) | |||
| { | |||
| } | |||
| virtual ~ConvexResultCallback() | |||
| { | |||
| } | |||
| bool hasHit() const | |||
| { | |||
| return (m_closestHitFraction < btScalar(1.)); | |||
| } | |||
| virtual bool needsCollision(btBroadphaseProxy* proxy0) const | |||
| { | |||
| bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0; | |||
| collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask); | |||
| return collides; | |||
| } | |||
| virtual btScalar addSingleResult(LocalConvexResult& convexResult,bool normalInWorldSpace) = 0; | |||
| }; | |||
| struct ClosestConvexResultCallback : public ConvexResultCallback | |||
| { | |||
| ClosestConvexResultCallback(const btVector3& convexFromWorld,const btVector3& convexToWorld) | |||
| :m_convexFromWorld(convexFromWorld), | |||
| m_convexToWorld(convexToWorld), | |||
| m_hitCollisionObject(0) | |||
| { | |||
| } | |||
| btVector3 m_convexFromWorld;//used to calculate hitPointWorld from hitFraction | |||
| btVector3 m_convexToWorld; | |||
| btVector3 m_hitNormalWorld; | |||
| btVector3 m_hitPointWorld; | |||
| btCollisionObject* m_hitCollisionObject; | |||
| virtual btScalar addSingleResult(LocalConvexResult& convexResult,bool normalInWorldSpace) | |||
| { | |||
| //caller already does the filter on the m_closestHitFraction | |||
| btAssert(convexResult.m_hitFraction <= m_closestHitFraction); | |||
| m_closestHitFraction = convexResult.m_hitFraction; | |||
| m_hitCollisionObject = convexResult.m_hitCollisionObject; | |||
| if (normalInWorldSpace) | |||
| { | |||
| m_hitNormalWorld = convexResult.m_hitNormalLocal; | |||
| } else | |||
| { | |||
| ///need to transform normal into worldspace | |||
| m_hitNormalWorld = m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; | |||
| } | |||
| m_hitPointWorld = convexResult.m_hitPointLocal; | |||
| return convexResult.m_hitFraction; | |||
| } | |||
| }; | |||
| ///ContactResultCallback is used to report contact points | |||
| struct ContactResultCallback | |||
| { | |||
| short int m_collisionFilterGroup; | |||
| short int m_collisionFilterMask; | |||
| ContactResultCallback() | |||
| :m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), | |||
| m_collisionFilterMask(btBroadphaseProxy::AllFilter) | |||
| { | |||
| } | |||
| virtual ~ContactResultCallback() | |||
| { | |||
| } | |||
| virtual bool needsCollision(btBroadphaseProxy* proxy0) const | |||
| { | |||
| bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0; | |||
| collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask); | |||
| return collides; | |||
| } | |||
| virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1) = 0; | |||
| }; | |||
| int getNumCollisionObjects() const | |||
| { | |||
| return int(m_collisionObjects.size()); | |||
| } | |||
| /// rayTest performs a raycast on all objects in the btCollisionWorld, and calls the resultCallback | |||
| /// This allows for several queries: first hit, all hits, any hit, dependent on the value returned by the callback. | |||
| virtual void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const; | |||
| /// convexTest performs a swept convex cast on all objects in the btCollisionWorld, and calls the resultCallback | |||
| /// This allows for several queries: first hit, all hits, any hit, dependent on the value return by the callback. | |||
| void convexSweepTest (const btConvexShape* castShape, const btTransform& from, const btTransform& to, ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration = btScalar(0.)) const; | |||
| ///contactTest performs a discrete collision test between colObj against all objects in the btCollisionWorld, and calls the resultCallback. | |||
| ///it reports one or more contact points for every overlapping object (including the one with deepest penetration) | |||
| void contactTest(btCollisionObject* colObj, ContactResultCallback& resultCallback); | |||
| ///contactTest performs a discrete collision test between two collision objects and calls the resultCallback if overlap if detected. | |||
| ///it reports one or more contact points (including the one with deepest penetration) | |||
| void contactPairTest(btCollisionObject* colObjA, btCollisionObject* colObjB, ContactResultCallback& resultCallback); | |||
| /// rayTestSingle performs a raycast call and calls the resultCallback. It is used internally by rayTest. | |||
| /// In a future implementation, we consider moving the ray test as a virtual method in btCollisionShape. | |||
| /// This allows more customization. | |||
| static void rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans, | |||
| btCollisionObject* collisionObject, | |||
| const btCollisionShape* collisionShape, | |||
| const btTransform& colObjWorldTransform, | |||
| RayResultCallback& resultCallback); | |||
| /// objectQuerySingle performs a collision detection query and calls the resultCallback. It is used internally by rayTest. | |||
| static void objectQuerySingle(const btConvexShape* castShape, const btTransform& rayFromTrans,const btTransform& rayToTrans, | |||
| btCollisionObject* collisionObject, | |||
| const btCollisionShape* collisionShape, | |||
| const btTransform& colObjWorldTransform, | |||
| ConvexResultCallback& resultCallback, btScalar allowedPenetration); | |||
| virtual void addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup=btBroadphaseProxy::DefaultFilter,short int collisionFilterMask=btBroadphaseProxy::AllFilter); | |||
| btCollisionObjectArray& getCollisionObjectArray() | |||
| { | |||
| return m_collisionObjects; | |||
| } | |||
| const btCollisionObjectArray& getCollisionObjectArray() const | |||
| { | |||
| return m_collisionObjects; | |||
| } | |||
| virtual void removeCollisionObject(btCollisionObject* collisionObject); | |||
| virtual void performDiscreteCollisionDetection(); | |||
| btDispatcherInfo& getDispatchInfo() | |||
| { | |||
| return m_dispatchInfo; | |||
| } | |||
| const btDispatcherInfo& getDispatchInfo() const | |||
| { | |||
| return m_dispatchInfo; | |||
| } | |||
| bool getForceUpdateAllAabbs() const | |||
| { | |||
| return m_forceUpdateAllAabbs; | |||
| } | |||
| void setForceUpdateAllAabbs( bool forceUpdateAllAabbs) | |||
| { | |||
| m_forceUpdateAllAabbs = forceUpdateAllAabbs; | |||
| } | |||
| ///Preliminary serialization test for Bullet 2.76. Loading those files requires a separate parser (Bullet/Demos/SerializeDemo) | |||
| virtual void serialize(btSerializer* serializer); | |||
| }; | |||
| #endif //BT_COLLISION_WORLD_H | |||
| @@ -0,0 +1,353 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| #include "BulletCollision/CollisionShapes/btCompoundShape.h" | |||
| #include "BulletCollision/BroadphaseCollision/btDbvt.h" | |||
| #include "LinearMath/btIDebugDraw.h" | |||
| #include "LinearMath/btAabbUtil2.h" | |||
| #include "btManifoldResult.h" | |||
| btCompoundCollisionAlgorithm::btCompoundCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped) | |||
| :btActivatingCollisionAlgorithm(ci,body0,body1), | |||
| m_isSwapped(isSwapped), | |||
| m_sharedManifold(ci.m_manifold) | |||
| { | |||
| m_ownsManifold = false; | |||
| btCollisionObject* colObj = m_isSwapped? body1 : body0; | |||
| btAssert (colObj->getCollisionShape()->isCompound()); | |||
| btCompoundShape* compoundShape = static_cast<btCompoundShape*>(colObj->getCollisionShape()); | |||
| m_compoundShapeRevision = compoundShape->getUpdateRevision(); | |||
| preallocateChildAlgorithms(body0,body1); | |||
| } | |||
| void btCompoundCollisionAlgorithm::preallocateChildAlgorithms(btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| btCollisionObject* colObj = m_isSwapped? body1 : body0; | |||
| btCollisionObject* otherObj = m_isSwapped? body0 : body1; | |||
| btAssert (colObj->getCollisionShape()->isCompound()); | |||
| btCompoundShape* compoundShape = static_cast<btCompoundShape*>(colObj->getCollisionShape()); | |||
| int numChildren = compoundShape->getNumChildShapes(); | |||
| int i; | |||
| m_childCollisionAlgorithms.resize(numChildren); | |||
| for (i=0;i<numChildren;i++) | |||
| { | |||
| if (compoundShape->getDynamicAabbTree()) | |||
| { | |||
| m_childCollisionAlgorithms[i] = 0; | |||
| } else | |||
| { | |||
| btCollisionShape* tmpShape = colObj->getCollisionShape(); | |||
| btCollisionShape* childShape = compoundShape->getChildShape(i); | |||
| colObj->internalSetTemporaryCollisionShape( childShape ); | |||
| m_childCollisionAlgorithms[i] = m_dispatcher->findAlgorithm(colObj,otherObj,m_sharedManifold); | |||
| colObj->internalSetTemporaryCollisionShape( tmpShape ); | |||
| } | |||
| } | |||
| } | |||
| void btCompoundCollisionAlgorithm::removeChildAlgorithms() | |||
| { | |||
| int numChildren = m_childCollisionAlgorithms.size(); | |||
| int i; | |||
| for (i=0;i<numChildren;i++) | |||
| { | |||
| if (m_childCollisionAlgorithms[i]) | |||
| { | |||
| m_childCollisionAlgorithms[i]->~btCollisionAlgorithm(); | |||
| m_dispatcher->freeCollisionAlgorithm(m_childCollisionAlgorithms[i]); | |||
| } | |||
| } | |||
| } | |||
| btCompoundCollisionAlgorithm::~btCompoundCollisionAlgorithm() | |||
| { | |||
| removeChildAlgorithms(); | |||
| } | |||
| struct btCompoundLeafCallback : btDbvt::ICollide | |||
| { | |||
| public: | |||
| btCollisionObject* m_compoundColObj; | |||
| btCollisionObject* m_otherObj; | |||
| btDispatcher* m_dispatcher; | |||
| const btDispatcherInfo& m_dispatchInfo; | |||
| btManifoldResult* m_resultOut; | |||
| btCollisionAlgorithm** m_childCollisionAlgorithms; | |||
| btPersistentManifold* m_sharedManifold; | |||
| btCompoundLeafCallback (btCollisionObject* compoundObj,btCollisionObject* otherObj,btDispatcher* dispatcher,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut,btCollisionAlgorithm** childCollisionAlgorithms,btPersistentManifold* sharedManifold) | |||
| :m_compoundColObj(compoundObj),m_otherObj(otherObj),m_dispatcher(dispatcher),m_dispatchInfo(dispatchInfo),m_resultOut(resultOut), | |||
| m_childCollisionAlgorithms(childCollisionAlgorithms), | |||
| m_sharedManifold(sharedManifold) | |||
| { | |||
| } | |||
| void ProcessChildShape(btCollisionShape* childShape,int index) | |||
| { | |||
| btAssert(index>=0); | |||
| btCompoundShape* compoundShape = static_cast<btCompoundShape*>(m_compoundColObj->getCollisionShape()); | |||
| btAssert(index<compoundShape->getNumChildShapes()); | |||
| //backup | |||
| btTransform orgTrans = m_compoundColObj->getWorldTransform(); | |||
| btTransform orgInterpolationTrans = m_compoundColObj->getInterpolationWorldTransform(); | |||
| const btTransform& childTrans = compoundShape->getChildTransform(index); | |||
| btTransform newChildWorldTrans = orgTrans*childTrans ; | |||
| //perform an AABB check first | |||
| btVector3 aabbMin0,aabbMax0,aabbMin1,aabbMax1; | |||
| childShape->getAabb(newChildWorldTrans,aabbMin0,aabbMax0); | |||
| m_otherObj->getCollisionShape()->getAabb(m_otherObj->getWorldTransform(),aabbMin1,aabbMax1); | |||
| if (TestAabbAgainstAabb2(aabbMin0,aabbMax0,aabbMin1,aabbMax1)) | |||
| { | |||
| m_compoundColObj->setWorldTransform( newChildWorldTrans); | |||
| m_compoundColObj->setInterpolationWorldTransform(newChildWorldTrans); | |||
| //the contactpoint is still projected back using the original inverted worldtrans | |||
| btCollisionShape* tmpShape = m_compoundColObj->getCollisionShape(); | |||
| m_compoundColObj->internalSetTemporaryCollisionShape( childShape ); | |||
| if (!m_childCollisionAlgorithms[index]) | |||
| m_childCollisionAlgorithms[index] = m_dispatcher->findAlgorithm(m_compoundColObj,m_otherObj,m_sharedManifold); | |||
| ///detect swapping case | |||
| if (m_resultOut->getBody0Internal() == m_compoundColObj) | |||
| { | |||
| m_resultOut->setShapeIdentifiersA(-1,index); | |||
| } else | |||
| { | |||
| m_resultOut->setShapeIdentifiersB(-1,index); | |||
| } | |||
| m_childCollisionAlgorithms[index]->processCollision(m_compoundColObj,m_otherObj,m_dispatchInfo,m_resultOut); | |||
| if (m_dispatchInfo.m_debugDraw && (m_dispatchInfo.m_debugDraw->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) | |||
| { | |||
| btVector3 worldAabbMin,worldAabbMax; | |||
| m_dispatchInfo.m_debugDraw->drawAabb(aabbMin0,aabbMax0,btVector3(1,1,1)); | |||
| m_dispatchInfo.m_debugDraw->drawAabb(aabbMin1,aabbMax1,btVector3(1,1,1)); | |||
| } | |||
| //revert back transform | |||
| m_compoundColObj->internalSetTemporaryCollisionShape( tmpShape); | |||
| m_compoundColObj->setWorldTransform( orgTrans ); | |||
| m_compoundColObj->setInterpolationWorldTransform(orgInterpolationTrans); | |||
| } | |||
| } | |||
| void Process(const btDbvtNode* leaf) | |||
| { | |||
| int index = leaf->dataAsInt; | |||
| btCompoundShape* compoundShape = static_cast<btCompoundShape*>(m_compoundColObj->getCollisionShape()); | |||
| btCollisionShape* childShape = compoundShape->getChildShape(index); | |||
| if (m_dispatchInfo.m_debugDraw && (m_dispatchInfo.m_debugDraw->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) | |||
| { | |||
| btVector3 worldAabbMin,worldAabbMax; | |||
| btTransform orgTrans = m_compoundColObj->getWorldTransform(); | |||
| btTransformAabb(leaf->volume.Mins(),leaf->volume.Maxs(),0.,orgTrans,worldAabbMin,worldAabbMax); | |||
| m_dispatchInfo.m_debugDraw->drawAabb(worldAabbMin,worldAabbMax,btVector3(1,0,0)); | |||
| } | |||
| ProcessChildShape(childShape,index); | |||
| } | |||
| }; | |||
| void btCompoundCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| btCollisionObject* colObj = m_isSwapped? body1 : body0; | |||
| btCollisionObject* otherObj = m_isSwapped? body0 : body1; | |||
| btAssert (colObj->getCollisionShape()->isCompound()); | |||
| btCompoundShape* compoundShape = static_cast<btCompoundShape*>(colObj->getCollisionShape()); | |||
| ///btCompoundShape might have changed: | |||
| ////make sure the internal child collision algorithm caches are still valid | |||
| if (compoundShape->getUpdateRevision() != m_compoundShapeRevision) | |||
| { | |||
| ///clear and update all | |||
| removeChildAlgorithms(); | |||
| preallocateChildAlgorithms(body0,body1); | |||
| } | |||
| btDbvt* tree = compoundShape->getDynamicAabbTree(); | |||
| //use a dynamic aabb tree to cull potential child-overlaps | |||
| btCompoundLeafCallback callback(colObj,otherObj,m_dispatcher,dispatchInfo,resultOut,&m_childCollisionAlgorithms[0],m_sharedManifold); | |||
| ///we need to refresh all contact manifolds | |||
| ///note that we should actually recursively traverse all children, btCompoundShape can nested more then 1 level deep | |||
| ///so we should add a 'refreshManifolds' in the btCollisionAlgorithm | |||
| { | |||
| int i; | |||
| btManifoldArray manifoldArray; | |||
| for (i=0;i<m_childCollisionAlgorithms.size();i++) | |||
| { | |||
| if (m_childCollisionAlgorithms[i]) | |||
| { | |||
| m_childCollisionAlgorithms[i]->getAllContactManifolds(manifoldArray); | |||
| for (int m=0;m<manifoldArray.size();m++) | |||
| { | |||
| if (manifoldArray[m]->getNumContacts()) | |||
| { | |||
| resultOut->setPersistentManifold(manifoldArray[m]); | |||
| resultOut->refreshContactPoints(); | |||
| resultOut->setPersistentManifold(0);//??necessary? | |||
| } | |||
| } | |||
| manifoldArray.resize(0); | |||
| } | |||
| } | |||
| } | |||
| if (tree) | |||
| { | |||
| btVector3 localAabbMin,localAabbMax; | |||
| btTransform otherInCompoundSpace; | |||
| otherInCompoundSpace = colObj->getWorldTransform().inverse() * otherObj->getWorldTransform(); | |||
| otherObj->getCollisionShape()->getAabb(otherInCompoundSpace,localAabbMin,localAabbMax); | |||
| const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); | |||
| //process all children, that overlap with the given AABB bounds | |||
| tree->collideTV(tree->m_root,bounds,callback); | |||
| } else | |||
| { | |||
| //iterate over all children, perform an AABB check inside ProcessChildShape | |||
| int numChildren = m_childCollisionAlgorithms.size(); | |||
| int i; | |||
| for (i=0;i<numChildren;i++) | |||
| { | |||
| callback.ProcessChildShape(compoundShape->getChildShape(i),i); | |||
| } | |||
| } | |||
| { | |||
| //iterate over all children, perform an AABB check inside ProcessChildShape | |||
| int numChildren = m_childCollisionAlgorithms.size(); | |||
| int i; | |||
| btManifoldArray manifoldArray; | |||
| btCollisionShape* childShape = 0; | |||
| btTransform orgTrans; | |||
| btTransform orgInterpolationTrans; | |||
| btTransform newChildWorldTrans; | |||
| btVector3 aabbMin0,aabbMax0,aabbMin1,aabbMax1; | |||
| for (i=0;i<numChildren;i++) | |||
| { | |||
| if (m_childCollisionAlgorithms[i]) | |||
| { | |||
| childShape = compoundShape->getChildShape(i); | |||
| //if not longer overlapping, remove the algorithm | |||
| orgTrans = colObj->getWorldTransform(); | |||
| orgInterpolationTrans = colObj->getInterpolationWorldTransform(); | |||
| const btTransform& childTrans = compoundShape->getChildTransform(i); | |||
| newChildWorldTrans = orgTrans*childTrans ; | |||
| //perform an AABB check first | |||
| childShape->getAabb(newChildWorldTrans,aabbMin0,aabbMax0); | |||
| otherObj->getCollisionShape()->getAabb(otherObj->getWorldTransform(),aabbMin1,aabbMax1); | |||
| if (!TestAabbAgainstAabb2(aabbMin0,aabbMax0,aabbMin1,aabbMax1)) | |||
| { | |||
| m_childCollisionAlgorithms[i]->~btCollisionAlgorithm(); | |||
| m_dispatcher->freeCollisionAlgorithm(m_childCollisionAlgorithms[i]); | |||
| m_childCollisionAlgorithms[i] = 0; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| btScalar btCompoundCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| btCollisionObject* colObj = m_isSwapped? body1 : body0; | |||
| btCollisionObject* otherObj = m_isSwapped? body0 : body1; | |||
| btAssert (colObj->getCollisionShape()->isCompound()); | |||
| btCompoundShape* compoundShape = static_cast<btCompoundShape*>(colObj->getCollisionShape()); | |||
| //We will use the OptimizedBVH, AABB tree to cull potential child-overlaps | |||
| //If both proxies are Compound, we will deal with that directly, by performing sequential/parallel tree traversals | |||
| //given Proxy0 and Proxy1, if both have a tree, Tree0 and Tree1, this means: | |||
| //determine overlapping nodes of Proxy1 using Proxy0 AABB against Tree1 | |||
| //then use each overlapping node AABB against Tree0 | |||
| //and vise versa. | |||
| btScalar hitFraction = btScalar(1.); | |||
| int numChildren = m_childCollisionAlgorithms.size(); | |||
| int i; | |||
| btTransform orgTrans; | |||
| btScalar frac; | |||
| for (i=0;i<numChildren;i++) | |||
| { | |||
| //temporarily exchange parent btCollisionShape with childShape, and recurse | |||
| btCollisionShape* childShape = compoundShape->getChildShape(i); | |||
| //backup | |||
| orgTrans = colObj->getWorldTransform(); | |||
| const btTransform& childTrans = compoundShape->getChildTransform(i); | |||
| //btTransform newChildWorldTrans = orgTrans*childTrans ; | |||
| colObj->setWorldTransform( orgTrans*childTrans ); | |||
| btCollisionShape* tmpShape = colObj->getCollisionShape(); | |||
| colObj->internalSetTemporaryCollisionShape( childShape ); | |||
| frac = m_childCollisionAlgorithms[i]->calculateTimeOfImpact(colObj,otherObj,dispatchInfo,resultOut); | |||
| if (frac<hitFraction) | |||
| { | |||
| hitFraction = frac; | |||
| } | |||
| //revert back | |||
| colObj->internalSetTemporaryCollisionShape( tmpShape); | |||
| colObj->setWorldTransform( orgTrans); | |||
| } | |||
| return hitFraction; | |||
| } | |||
| @@ -0,0 +1,86 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_COMPOUND_COLLISION_ALGORITHM_H | |||
| #define BT_COMPOUND_COLLISION_ALGORITHM_H | |||
| #include "btActivatingCollisionAlgorithm.h" | |||
| #include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
| class btDispatcher; | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "btCollisionCreateFunc.h" | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| class btDispatcher; | |||
| class btCollisionObject; | |||
| /// btCompoundCollisionAlgorithm supports collision between CompoundCollisionShapes and other collision shapes | |||
| class btCompoundCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
| { | |||
| btAlignedObjectArray<btCollisionAlgorithm*> m_childCollisionAlgorithms; | |||
| bool m_isSwapped; | |||
| class btPersistentManifold* m_sharedManifold; | |||
| bool m_ownsManifold; | |||
| int m_compoundShapeRevision;//to keep track of changes, so that childAlgorithm array can be updated | |||
| void removeChildAlgorithms(); | |||
| void preallocateChildAlgorithms(btCollisionObject* body0,btCollisionObject* body1); | |||
| public: | |||
| btCompoundCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); | |||
| virtual ~btCompoundCollisionAlgorithm(); | |||
| virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
| { | |||
| int i; | |||
| for (i=0;i<m_childCollisionAlgorithms.size();i++) | |||
| { | |||
| if (m_childCollisionAlgorithms[i]) | |||
| m_childCollisionAlgorithms[i]->getAllContactManifolds(manifoldArray); | |||
| } | |||
| } | |||
| struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btCompoundCollisionAlgorithm)); | |||
| return new(mem) btCompoundCollisionAlgorithm(ci,body0,body1,false); | |||
| } | |||
| }; | |||
| struct SwappedCreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btCompoundCollisionAlgorithm)); | |||
| return new(mem) btCompoundCollisionAlgorithm(ci,body0,body1,true); | |||
| } | |||
| }; | |||
| }; | |||
| #endif //BT_COMPOUND_COLLISION_ALGORITHM_H | |||
| @@ -0,0 +1,247 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btConvex2dConvex2dAlgorithm.h" | |||
| //#include <stdio.h> | |||
| #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| #include "BulletCollision/CollisionShapes/btConvexShape.h" | |||
| #include "BulletCollision/CollisionShapes/btCapsuleShape.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
| #include "BulletCollision/CollisionShapes/btBoxShape.h" | |||
| #include "BulletCollision/CollisionDispatch/btManifoldResult.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" | |||
| #include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" | |||
| btConvex2dConvex2dAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) | |||
| { | |||
| m_numPerturbationIterations = 0; | |||
| m_minimumPointsPerturbationThreshold = 3; | |||
| m_simplexSolver = simplexSolver; | |||
| m_pdSolver = pdSolver; | |||
| } | |||
| btConvex2dConvex2dAlgorithm::CreateFunc::~CreateFunc() | |||
| { | |||
| } | |||
| btConvex2dConvex2dAlgorithm::btConvex2dConvex2dAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold) | |||
| : btActivatingCollisionAlgorithm(ci,body0,body1), | |||
| m_simplexSolver(simplexSolver), | |||
| m_pdSolver(pdSolver), | |||
| m_ownManifold (false), | |||
| m_manifoldPtr(mf), | |||
| m_lowLevelOfDetail(false), | |||
| m_numPerturbationIterations(numPerturbationIterations), | |||
| m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold) | |||
| { | |||
| (void)body0; | |||
| (void)body1; | |||
| } | |||
| btConvex2dConvex2dAlgorithm::~btConvex2dConvex2dAlgorithm() | |||
| { | |||
| if (m_ownManifold) | |||
| { | |||
| if (m_manifoldPtr) | |||
| m_dispatcher->releaseManifold(m_manifoldPtr); | |||
| } | |||
| } | |||
| void btConvex2dConvex2dAlgorithm ::setLowLevelOfDetail(bool useLowLevel) | |||
| { | |||
| m_lowLevelOfDetail = useLowLevel; | |||
| } | |||
| extern btScalar gContactBreakingThreshold; | |||
| // | |||
| // Convex-Convex collision algorithm | |||
| // | |||
| void btConvex2dConvex2dAlgorithm ::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| if (!m_manifoldPtr) | |||
| { | |||
| //swapped? | |||
| m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1); | |||
| m_ownManifold = true; | |||
| } | |||
| resultOut->setPersistentManifold(m_manifoldPtr); | |||
| //comment-out next line to test multi-contact generation | |||
| //resultOut->getPersistentManifold()->clearManifold(); | |||
| btConvexShape* min0 = static_cast<btConvexShape*>(body0->getCollisionShape()); | |||
| btConvexShape* min1 = static_cast<btConvexShape*>(body1->getCollisionShape()); | |||
| btVector3 normalOnB; | |||
| btVector3 pointOnBWorld; | |||
| { | |||
| btGjkPairDetector::ClosestPointInput input; | |||
| btGjkPairDetector gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver); | |||
| //TODO: if (dispatchInfo.m_useContinuous) | |||
| gjkPairDetector.setMinkowskiA(min0); | |||
| gjkPairDetector.setMinkowskiB(min1); | |||
| { | |||
| input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold(); | |||
| input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared; | |||
| } | |||
| input.m_stackAlloc = dispatchInfo.m_stackAllocator; | |||
| input.m_transformA = body0->getWorldTransform(); | |||
| input.m_transformB = body1->getWorldTransform(); | |||
| gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); | |||
| btVector3 v0,v1; | |||
| btVector3 sepNormalWorldSpace; | |||
| } | |||
| if (m_ownManifold) | |||
| { | |||
| resultOut->refreshContactPoints(); | |||
| } | |||
| } | |||
| btScalar btConvex2dConvex2dAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| (void)resultOut; | |||
| (void)dispatchInfo; | |||
| ///Rather then checking ALL pairs, only calculate TOI when motion exceeds threshold | |||
| ///Linear motion for one of objects needs to exceed m_ccdSquareMotionThreshold | |||
| ///col0->m_worldTransform, | |||
| btScalar resultFraction = btScalar(1.); | |||
| btScalar squareMot0 = (col0->getInterpolationWorldTransform().getOrigin() - col0->getWorldTransform().getOrigin()).length2(); | |||
| btScalar squareMot1 = (col1->getInterpolationWorldTransform().getOrigin() - col1->getWorldTransform().getOrigin()).length2(); | |||
| if (squareMot0 < col0->getCcdSquareMotionThreshold() && | |||
| squareMot1 < col1->getCcdSquareMotionThreshold()) | |||
| return resultFraction; | |||
| //An adhoc way of testing the Continuous Collision Detection algorithms | |||
| //One object is approximated as a sphere, to simplify things | |||
| //Starting in penetration should report no time of impact | |||
| //For proper CCD, better accuracy and handling of 'allowed' penetration should be added | |||
| //also the mainloop of the physics should have a kind of toi queue (something like Brian Mirtich's application of Timewarp for Rigidbodies) | |||
| /// Convex0 against sphere for Convex1 | |||
| { | |||
| btConvexShape* convex0 = static_cast<btConvexShape*>(col0->getCollisionShape()); | |||
| btSphereShape sphere1(col1->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation | |||
| btConvexCast::CastResult result; | |||
| btVoronoiSimplexSolver voronoiSimplex; | |||
| //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); | |||
| ///Simplification, one object is simplified as a sphere | |||
| btGjkConvexCast ccd1( convex0 ,&sphere1,&voronoiSimplex); | |||
| //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); | |||
| if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), | |||
| col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) | |||
| { | |||
| //store result.m_fraction in both bodies | |||
| if (col0->getHitFraction()> result.m_fraction) | |||
| col0->setHitFraction( result.m_fraction ); | |||
| if (col1->getHitFraction() > result.m_fraction) | |||
| col1->setHitFraction( result.m_fraction); | |||
| if (resultFraction > result.m_fraction) | |||
| resultFraction = result.m_fraction; | |||
| } | |||
| } | |||
| /// Sphere (for convex0) against Convex1 | |||
| { | |||
| btConvexShape* convex1 = static_cast<btConvexShape*>(col1->getCollisionShape()); | |||
| btSphereShape sphere0(col0->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation | |||
| btConvexCast::CastResult result; | |||
| btVoronoiSimplexSolver voronoiSimplex; | |||
| //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); | |||
| ///Simplification, one object is simplified as a sphere | |||
| btGjkConvexCast ccd1(&sphere0,convex1,&voronoiSimplex); | |||
| //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); | |||
| if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), | |||
| col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) | |||
| { | |||
| //store result.m_fraction in both bodies | |||
| if (col0->getHitFraction() > result.m_fraction) | |||
| col0->setHitFraction( result.m_fraction); | |||
| if (col1->getHitFraction() > result.m_fraction) | |||
| col1->setHitFraction( result.m_fraction); | |||
| if (resultFraction > result.m_fraction) | |||
| resultFraction = result.m_fraction; | |||
| } | |||
| } | |||
| return resultFraction; | |||
| } | |||
| @@ -0,0 +1,95 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_CONVEX_2D_CONVEX_2D_ALGORITHM_H | |||
| #define BT_CONVEX_2D_CONVEX_2D_ALGORITHM_H | |||
| #include "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
| #include "LinearMath/btTransformUtil.h" //for btConvexSeparatingDistanceUtil | |||
| class btConvexPenetrationDepthSolver; | |||
| ///The convex2dConvex2dAlgorithm collision algorithm support 2d collision detection for btConvex2dShape | |||
| ///Currently it requires the btMinkowskiPenetrationDepthSolver, it has support for 2d penetration depth computation | |||
| class btConvex2dConvex2dAlgorithm : public btActivatingCollisionAlgorithm | |||
| { | |||
| btSimplexSolverInterface* m_simplexSolver; | |||
| btConvexPenetrationDepthSolver* m_pdSolver; | |||
| bool m_ownManifold; | |||
| btPersistentManifold* m_manifoldPtr; | |||
| bool m_lowLevelOfDetail; | |||
| int m_numPerturbationIterations; | |||
| int m_minimumPointsPerturbationThreshold; | |||
| public: | |||
| btConvex2dConvex2dAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold); | |||
| virtual ~btConvex2dConvex2dAlgorithm(); | |||
| virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
| { | |||
| ///should we use m_ownManifold to avoid adding duplicates? | |||
| if (m_manifoldPtr && m_ownManifold) | |||
| manifoldArray.push_back(m_manifoldPtr); | |||
| } | |||
| void setLowLevelOfDetail(bool useLowLevel); | |||
| const btPersistentManifold* getManifold() | |||
| { | |||
| return m_manifoldPtr; | |||
| } | |||
| struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| btConvexPenetrationDepthSolver* m_pdSolver; | |||
| btSimplexSolverInterface* m_simplexSolver; | |||
| int m_numPerturbationIterations; | |||
| int m_minimumPointsPerturbationThreshold; | |||
| CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver); | |||
| virtual ~CreateFunc(); | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvex2dConvex2dAlgorithm)); | |||
| return new(mem) btConvex2dConvex2dAlgorithm(ci.m_manifold,ci,body0,body1,m_simplexSolver,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); | |||
| } | |||
| }; | |||
| }; | |||
| #endif //BT_CONVEX_2D_CONVEX_2D_ALGORITHM_H | |||
| @@ -0,0 +1,312 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btConvexConcaveCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| #include "BulletCollision/CollisionShapes/btMultiSphereShape.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "BulletCollision/CollisionShapes/btConcaveShape.h" | |||
| #include "BulletCollision/CollisionDispatch/btManifoldResult.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" | |||
| #include "BulletCollision/CollisionShapes/btTriangleShape.h" | |||
| #include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
| #include "LinearMath/btIDebugDraw.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" | |||
| btConvexConcaveCollisionAlgorithm::btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1,bool isSwapped) | |||
| : btActivatingCollisionAlgorithm(ci,body0,body1), | |||
| m_isSwapped(isSwapped), | |||
| m_btConvexTriangleCallback(ci.m_dispatcher1,body0,body1,isSwapped) | |||
| { | |||
| } | |||
| btConvexConcaveCollisionAlgorithm::~btConvexConcaveCollisionAlgorithm() | |||
| { | |||
| } | |||
| void btConvexConcaveCollisionAlgorithm::getAllContactManifolds(btManifoldArray& manifoldArray) | |||
| { | |||
| if (m_btConvexTriangleCallback.m_manifoldPtr) | |||
| { | |||
| manifoldArray.push_back(m_btConvexTriangleCallback.m_manifoldPtr); | |||
| } | |||
| } | |||
| btConvexTriangleCallback::btConvexTriangleCallback(btDispatcher* dispatcher,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped): | |||
| m_dispatcher(dispatcher), | |||
| m_dispatchInfoPtr(0) | |||
| { | |||
| m_convexBody = isSwapped? body1:body0; | |||
| m_triBody = isSwapped? body0:body1; | |||
| // | |||
| // create the manifold from the dispatcher 'manifold pool' | |||
| // | |||
| m_manifoldPtr = m_dispatcher->getNewManifold(m_convexBody,m_triBody); | |||
| clearCache(); | |||
| } | |||
| btConvexTriangleCallback::~btConvexTriangleCallback() | |||
| { | |||
| clearCache(); | |||
| m_dispatcher->releaseManifold( m_manifoldPtr ); | |||
| } | |||
| void btConvexTriangleCallback::clearCache() | |||
| { | |||
| m_dispatcher->clearManifold(m_manifoldPtr); | |||
| } | |||
| void btConvexTriangleCallback::processTriangle(btVector3* triangle,int partId, int triangleIndex) | |||
| { | |||
| //just for debugging purposes | |||
| //printf("triangle %d",m_triangleCount++); | |||
| //aabb filter is already applied! | |||
| btCollisionAlgorithmConstructionInfo ci; | |||
| ci.m_dispatcher1 = m_dispatcher; | |||
| btCollisionObject* ob = static_cast<btCollisionObject*>(m_triBody); | |||
| #if 0 | |||
| ///debug drawing of the overlapping triangles | |||
| if (m_dispatchInfoPtr && m_dispatchInfoPtr->m_debugDraw && (m_dispatchInfoPtr->m_debugDraw->getDebugMode() &btIDebugDraw::DBG_DrawWireframe )) | |||
| { | |||
| btVector3 color(1,1,0); | |||
| btTransform& tr = ob->getWorldTransform(); | |||
| m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[0]),tr(triangle[1]),color); | |||
| m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[1]),tr(triangle[2]),color); | |||
| m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[2]),tr(triangle[0]),color); | |||
| } | |||
| #endif | |||
| if (m_convexBody->getCollisionShape()->isConvex()) | |||
| { | |||
| btTriangleShape tm(triangle[0],triangle[1],triangle[2]); | |||
| tm.setMargin(m_collisionMarginTriangle); | |||
| btCollisionShape* tmpShape = ob->getCollisionShape(); | |||
| ob->internalSetTemporaryCollisionShape( &tm ); | |||
| btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBody,m_triBody,m_manifoldPtr); | |||
| if (m_resultOut->getBody0Internal() == m_triBody) | |||
| { | |||
| m_resultOut->setShapeIdentifiersA(partId,triangleIndex); | |||
| } | |||
| else | |||
| { | |||
| m_resultOut->setShapeIdentifiersB(partId,triangleIndex); | |||
| } | |||
| colAlgo->processCollision(m_convexBody,m_triBody,*m_dispatchInfoPtr,m_resultOut); | |||
| colAlgo->~btCollisionAlgorithm(); | |||
| ci.m_dispatcher1->freeCollisionAlgorithm(colAlgo); | |||
| ob->internalSetTemporaryCollisionShape( tmpShape); | |||
| } | |||
| } | |||
| void btConvexTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTriangle,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| m_dispatchInfoPtr = &dispatchInfo; | |||
| m_collisionMarginTriangle = collisionMarginTriangle; | |||
| m_resultOut = resultOut; | |||
| //recalc aabbs | |||
| btTransform convexInTriangleSpace; | |||
| convexInTriangleSpace = m_triBody->getWorldTransform().inverse() * m_convexBody->getWorldTransform(); | |||
| btCollisionShape* convexShape = static_cast<btCollisionShape*>(m_convexBody->getCollisionShape()); | |||
| //CollisionShape* triangleShape = static_cast<btCollisionShape*>(triBody->m_collisionShape); | |||
| convexShape->getAabb(convexInTriangleSpace,m_aabbMin,m_aabbMax); | |||
| btScalar extraMargin = collisionMarginTriangle; | |||
| btVector3 extra(extraMargin,extraMargin,extraMargin); | |||
| m_aabbMax += extra; | |||
| m_aabbMin -= extra; | |||
| } | |||
| void btConvexConcaveCollisionAlgorithm::clearCache() | |||
| { | |||
| m_btConvexTriangleCallback.clearCache(); | |||
| } | |||
| void btConvexConcaveCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| btCollisionObject* convexBody = m_isSwapped ? body1 : body0; | |||
| btCollisionObject* triBody = m_isSwapped ? body0 : body1; | |||
| if (triBody->getCollisionShape()->isConcave()) | |||
| { | |||
| btCollisionObject* triOb = triBody; | |||
| btConcaveShape* concaveShape = static_cast<btConcaveShape*>( triOb->getCollisionShape()); | |||
| if (convexBody->getCollisionShape()->isConvex()) | |||
| { | |||
| btScalar collisionMarginTriangle = concaveShape->getMargin(); | |||
| resultOut->setPersistentManifold(m_btConvexTriangleCallback.m_manifoldPtr); | |||
| m_btConvexTriangleCallback.setTimeStepAndCounters(collisionMarginTriangle,dispatchInfo,resultOut); | |||
| //Disable persistency. previously, some older algorithm calculated all contacts in one go, so you can clear it here. | |||
| //m_dispatcher->clearManifold(m_btConvexTriangleCallback.m_manifoldPtr); | |||
| m_btConvexTriangleCallback.m_manifoldPtr->setBodies(convexBody,triBody); | |||
| concaveShape->processAllTriangles( &m_btConvexTriangleCallback,m_btConvexTriangleCallback.getAabbMin(),m_btConvexTriangleCallback.getAabbMax()); | |||
| resultOut->refreshContactPoints(); | |||
| } | |||
| } | |||
| } | |||
| btScalar btConvexConcaveCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| (void)resultOut; | |||
| (void)dispatchInfo; | |||
| btCollisionObject* convexbody = m_isSwapped ? body1 : body0; | |||
| btCollisionObject* triBody = m_isSwapped ? body0 : body1; | |||
| //quick approximation using raycast, todo: hook up to the continuous collision detection (one of the btConvexCast) | |||
| //only perform CCD above a certain threshold, this prevents blocking on the long run | |||
| //because object in a blocked ccd state (hitfraction<1) get their linear velocity halved each frame... | |||
| btScalar squareMot0 = (convexbody->getInterpolationWorldTransform().getOrigin() - convexbody->getWorldTransform().getOrigin()).length2(); | |||
| if (squareMot0 < convexbody->getCcdSquareMotionThreshold()) | |||
| { | |||
| return btScalar(1.); | |||
| } | |||
| //const btVector3& from = convexbody->m_worldTransform.getOrigin(); | |||
| //btVector3 to = convexbody->m_interpolationWorldTransform.getOrigin(); | |||
| //todo: only do if the motion exceeds the 'radius' | |||
| btTransform triInv = triBody->getWorldTransform().inverse(); | |||
| btTransform convexFromLocal = triInv * convexbody->getWorldTransform(); | |||
| btTransform convexToLocal = triInv * convexbody->getInterpolationWorldTransform(); | |||
| struct LocalTriangleSphereCastCallback : public btTriangleCallback | |||
| { | |||
| btTransform m_ccdSphereFromTrans; | |||
| btTransform m_ccdSphereToTrans; | |||
| btTransform m_meshTransform; | |||
| btScalar m_ccdSphereRadius; | |||
| btScalar m_hitFraction; | |||
| LocalTriangleSphereCastCallback(const btTransform& from,const btTransform& to,btScalar ccdSphereRadius,btScalar hitFraction) | |||
| :m_ccdSphereFromTrans(from), | |||
| m_ccdSphereToTrans(to), | |||
| m_ccdSphereRadius(ccdSphereRadius), | |||
| m_hitFraction(hitFraction) | |||
| { | |||
| } | |||
| virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) | |||
| { | |||
| (void)partId; | |||
| (void)triangleIndex; | |||
| //do a swept sphere for now | |||
| btTransform ident; | |||
| ident.setIdentity(); | |||
| btConvexCast::CastResult castResult; | |||
| castResult.m_fraction = m_hitFraction; | |||
| btSphereShape pointShape(m_ccdSphereRadius); | |||
| btTriangleShape triShape(triangle[0],triangle[1],triangle[2]); | |||
| btVoronoiSimplexSolver simplexSolver; | |||
| btSubsimplexConvexCast convexCaster(&pointShape,&triShape,&simplexSolver); | |||
| //GjkConvexCast convexCaster(&pointShape,convexShape,&simplexSolver); | |||
| //ContinuousConvexCollision convexCaster(&pointShape,convexShape,&simplexSolver,0); | |||
| //local space? | |||
| if (convexCaster.calcTimeOfImpact(m_ccdSphereFromTrans,m_ccdSphereToTrans, | |||
| ident,ident,castResult)) | |||
| { | |||
| if (m_hitFraction > castResult.m_fraction) | |||
| m_hitFraction = castResult.m_fraction; | |||
| } | |||
| } | |||
| }; | |||
| if (triBody->getCollisionShape()->isConcave()) | |||
| { | |||
| btVector3 rayAabbMin = convexFromLocal.getOrigin(); | |||
| rayAabbMin.setMin(convexToLocal.getOrigin()); | |||
| btVector3 rayAabbMax = convexFromLocal.getOrigin(); | |||
| rayAabbMax.setMax(convexToLocal.getOrigin()); | |||
| btScalar ccdRadius0 = convexbody->getCcdSweptSphereRadius(); | |||
| rayAabbMin -= btVector3(ccdRadius0,ccdRadius0,ccdRadius0); | |||
| rayAabbMax += btVector3(ccdRadius0,ccdRadius0,ccdRadius0); | |||
| btScalar curHitFraction = btScalar(1.); //is this available? | |||
| LocalTriangleSphereCastCallback raycastCallback(convexFromLocal,convexToLocal, | |||
| convexbody->getCcdSweptSphereRadius(),curHitFraction); | |||
| raycastCallback.m_hitFraction = convexbody->getHitFraction(); | |||
| btCollisionObject* concavebody = triBody; | |||
| btConcaveShape* triangleMesh = (btConcaveShape*) concavebody->getCollisionShape(); | |||
| if (triangleMesh) | |||
| { | |||
| triangleMesh->processAllTriangles(&raycastCallback,rayAabbMin,rayAabbMax); | |||
| } | |||
| if (raycastCallback.m_hitFraction < convexbody->getHitFraction()) | |||
| { | |||
| convexbody->setHitFraction( raycastCallback.m_hitFraction); | |||
| return raycastCallback.m_hitFraction; | |||
| } | |||
| } | |||
| return btScalar(1.); | |||
| } | |||
| @@ -0,0 +1,116 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_CONVEX_CONCAVE_COLLISION_ALGORITHM_H | |||
| #define BT_CONVEX_CONCAVE_COLLISION_ALGORITHM_H | |||
| #include "btActivatingCollisionAlgorithm.h" | |||
| #include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" | |||
| #include "BulletCollision/CollisionShapes/btTriangleCallback.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
| class btDispatcher; | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "btCollisionCreateFunc.h" | |||
| ///For each triangle in the concave mesh that overlaps with the AABB of a convex (m_convexProxy), processTriangle is called. | |||
| class btConvexTriangleCallback : public btTriangleCallback | |||
| { | |||
| btCollisionObject* m_convexBody; | |||
| btCollisionObject* m_triBody; | |||
| btVector3 m_aabbMin; | |||
| btVector3 m_aabbMax ; | |||
| btManifoldResult* m_resultOut; | |||
| btDispatcher* m_dispatcher; | |||
| const btDispatcherInfo* m_dispatchInfoPtr; | |||
| btScalar m_collisionMarginTriangle; | |||
| public: | |||
| int m_triangleCount; | |||
| btPersistentManifold* m_manifoldPtr; | |||
| btConvexTriangleCallback(btDispatcher* dispatcher,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); | |||
| void setTimeStepAndCounters(btScalar collisionMarginTriangle,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual ~btConvexTriangleCallback(); | |||
| virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex); | |||
| void clearCache(); | |||
| SIMD_FORCE_INLINE const btVector3& getAabbMin() const | |||
| { | |||
| return m_aabbMin; | |||
| } | |||
| SIMD_FORCE_INLINE const btVector3& getAabbMax() const | |||
| { | |||
| return m_aabbMax; | |||
| } | |||
| }; | |||
| /// btConvexConcaveCollisionAlgorithm supports collision between convex shapes and (concave) trianges meshes. | |||
| class btConvexConcaveCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
| { | |||
| bool m_isSwapped; | |||
| btConvexTriangleCallback m_btConvexTriangleCallback; | |||
| public: | |||
| btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); | |||
| virtual ~btConvexConcaveCollisionAlgorithm(); | |||
| virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual void getAllContactManifolds(btManifoldArray& manifoldArray); | |||
| void clearCache(); | |||
| struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConcaveCollisionAlgorithm)); | |||
| return new(mem) btConvexConcaveCollisionAlgorithm(ci,body0,body1,false); | |||
| } | |||
| }; | |||
| struct SwappedCreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConcaveCollisionAlgorithm)); | |||
| return new(mem) btConvexConcaveCollisionAlgorithm(ci,body0,body1,true); | |||
| } | |||
| }; | |||
| }; | |||
| #endif //BT_CONVEX_CONCAVE_COLLISION_ALGORITHM_H | |||
| @@ -0,0 +1,739 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| ///Specialized capsule-capsule collision algorithm has been added for Bullet 2.75 release to increase ragdoll performance | |||
| ///If you experience problems with capsule-capsule collision, try to define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER and report it in the Bullet forums | |||
| ///with reproduction case | |||
| //define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER 1 | |||
| //#define ZERO_MARGIN | |||
| #include "btConvexConvexAlgorithm.h" | |||
| //#include <stdio.h> | |||
| #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| #include "BulletCollision/CollisionShapes/btConvexShape.h" | |||
| #include "BulletCollision/CollisionShapes/btCapsuleShape.h" | |||
| #include "BulletCollision/CollisionShapes/btTriangleShape.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
| #include "BulletCollision/CollisionShapes/btBoxShape.h" | |||
| #include "BulletCollision/CollisionDispatch/btManifoldResult.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" | |||
| #include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h" | |||
| /////////// | |||
| static SIMD_FORCE_INLINE void segmentsClosestPoints( | |||
| btVector3& ptsVector, | |||
| btVector3& offsetA, | |||
| btVector3& offsetB, | |||
| btScalar& tA, btScalar& tB, | |||
| const btVector3& translation, | |||
| const btVector3& dirA, btScalar hlenA, | |||
| const btVector3& dirB, btScalar hlenB ) | |||
| { | |||
| // compute the parameters of the closest points on each line segment | |||
| btScalar dirA_dot_dirB = btDot(dirA,dirB); | |||
| btScalar dirA_dot_trans = btDot(dirA,translation); | |||
| btScalar dirB_dot_trans = btDot(dirB,translation); | |||
| btScalar denom = 1.0f - dirA_dot_dirB * dirA_dot_dirB; | |||
| if ( denom == 0.0f ) { | |||
| tA = 0.0f; | |||
| } else { | |||
| tA = ( dirA_dot_trans - dirB_dot_trans * dirA_dot_dirB ) / denom; | |||
| if ( tA < -hlenA ) | |||
| tA = -hlenA; | |||
| else if ( tA > hlenA ) | |||
| tA = hlenA; | |||
| } | |||
| tB = tA * dirA_dot_dirB - dirB_dot_trans; | |||
| if ( tB < -hlenB ) { | |||
| tB = -hlenB; | |||
| tA = tB * dirA_dot_dirB + dirA_dot_trans; | |||
| if ( tA < -hlenA ) | |||
| tA = -hlenA; | |||
| else if ( tA > hlenA ) | |||
| tA = hlenA; | |||
| } else if ( tB > hlenB ) { | |||
| tB = hlenB; | |||
| tA = tB * dirA_dot_dirB + dirA_dot_trans; | |||
| if ( tA < -hlenA ) | |||
| tA = -hlenA; | |||
| else if ( tA > hlenA ) | |||
| tA = hlenA; | |||
| } | |||
| // compute the closest points relative to segment centers. | |||
| offsetA = dirA * tA; | |||
| offsetB = dirB * tB; | |||
| ptsVector = translation - offsetA + offsetB; | |||
| } | |||
| static SIMD_FORCE_INLINE btScalar capsuleCapsuleDistance( | |||
| btVector3& normalOnB, | |||
| btVector3& pointOnB, | |||
| btScalar capsuleLengthA, | |||
| btScalar capsuleRadiusA, | |||
| btScalar capsuleLengthB, | |||
| btScalar capsuleRadiusB, | |||
| int capsuleAxisA, | |||
| int capsuleAxisB, | |||
| const btTransform& transformA, | |||
| const btTransform& transformB, | |||
| btScalar distanceThreshold ) | |||
| { | |||
| btVector3 directionA = transformA.getBasis().getColumn(capsuleAxisA); | |||
| btVector3 translationA = transformA.getOrigin(); | |||
| btVector3 directionB = transformB.getBasis().getColumn(capsuleAxisB); | |||
| btVector3 translationB = transformB.getOrigin(); | |||
| // translation between centers | |||
| btVector3 translation = translationB - translationA; | |||
| // compute the closest points of the capsule line segments | |||
| btVector3 ptsVector; // the vector between the closest points | |||
| btVector3 offsetA, offsetB; // offsets from segment centers to their closest points | |||
| btScalar tA, tB; // parameters on line segment | |||
| segmentsClosestPoints( ptsVector, offsetA, offsetB, tA, tB, translation, | |||
| directionA, capsuleLengthA, directionB, capsuleLengthB ); | |||
| btScalar distance = ptsVector.length() - capsuleRadiusA - capsuleRadiusB; | |||
| if ( distance > distanceThreshold ) | |||
| return distance; | |||
| btScalar lenSqr = ptsVector.length2(); | |||
| if (lenSqr<= (SIMD_EPSILON*SIMD_EPSILON)) | |||
| { | |||
| //degenerate case where 2 capsules are likely at the same location: take a vector tangential to 'directionA' | |||
| btVector3 q; | |||
| btPlaneSpace1(directionA,normalOnB,q); | |||
| } else | |||
| { | |||
| // compute the contact normal | |||
| normalOnB = ptsVector*-btRecipSqrt(lenSqr); | |||
| } | |||
| pointOnB = transformB.getOrigin()+offsetB + normalOnB * capsuleRadiusB; | |||
| return distance; | |||
| } | |||
| ////////// | |||
| btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) | |||
| { | |||
| m_numPerturbationIterations = 0; | |||
| m_minimumPointsPerturbationThreshold = 3; | |||
| m_simplexSolver = simplexSolver; | |||
| m_pdSolver = pdSolver; | |||
| } | |||
| btConvexConvexAlgorithm::CreateFunc::~CreateFunc() | |||
| { | |||
| } | |||
| btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold) | |||
| : btActivatingCollisionAlgorithm(ci,body0,body1), | |||
| m_simplexSolver(simplexSolver), | |||
| m_pdSolver(pdSolver), | |||
| m_ownManifold (false), | |||
| m_manifoldPtr(mf), | |||
| m_lowLevelOfDetail(false), | |||
| #ifdef USE_SEPDISTANCE_UTIL2 | |||
| m_sepDistance((static_cast<btConvexShape*>(body0->getCollisionShape()))->getAngularMotionDisc(), | |||
| (static_cast<btConvexShape*>(body1->getCollisionShape()))->getAngularMotionDisc()), | |||
| #endif | |||
| m_numPerturbationIterations(numPerturbationIterations), | |||
| m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold) | |||
| { | |||
| (void)body0; | |||
| (void)body1; | |||
| } | |||
| btConvexConvexAlgorithm::~btConvexConvexAlgorithm() | |||
| { | |||
| if (m_ownManifold) | |||
| { | |||
| if (m_manifoldPtr) | |||
| m_dispatcher->releaseManifold(m_manifoldPtr); | |||
| } | |||
| } | |||
| void btConvexConvexAlgorithm ::setLowLevelOfDetail(bool useLowLevel) | |||
| { | |||
| m_lowLevelOfDetail = useLowLevel; | |||
| } | |||
| struct btPerturbedContactResult : public btManifoldResult | |||
| { | |||
| btManifoldResult* m_originalManifoldResult; | |||
| btTransform m_transformA; | |||
| btTransform m_transformB; | |||
| btTransform m_unPerturbedTransform; | |||
| bool m_perturbA; | |||
| btIDebugDraw* m_debugDrawer; | |||
| btPerturbedContactResult(btManifoldResult* originalResult,const btTransform& transformA,const btTransform& transformB,const btTransform& unPerturbedTransform,bool perturbA,btIDebugDraw* debugDrawer) | |||
| :m_originalManifoldResult(originalResult), | |||
| m_transformA(transformA), | |||
| m_transformB(transformB), | |||
| m_unPerturbedTransform(unPerturbedTransform), | |||
| m_perturbA(perturbA), | |||
| m_debugDrawer(debugDrawer) | |||
| { | |||
| } | |||
| virtual ~ btPerturbedContactResult() | |||
| { | |||
| } | |||
| virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar orgDepth) | |||
| { | |||
| btVector3 endPt,startPt; | |||
| btScalar newDepth; | |||
| btVector3 newNormal; | |||
| if (m_perturbA) | |||
| { | |||
| btVector3 endPtOrg = pointInWorld + normalOnBInWorld*orgDepth; | |||
| endPt = (m_unPerturbedTransform*m_transformA.inverse())(endPtOrg); | |||
| newDepth = (endPt - pointInWorld).dot(normalOnBInWorld); | |||
| startPt = endPt+normalOnBInWorld*newDepth; | |||
| } else | |||
| { | |||
| endPt = pointInWorld + normalOnBInWorld*orgDepth; | |||
| startPt = (m_unPerturbedTransform*m_transformB.inverse())(pointInWorld); | |||
| newDepth = (endPt - startPt).dot(normalOnBInWorld); | |||
| } | |||
| //#define DEBUG_CONTACTS 1 | |||
| #ifdef DEBUG_CONTACTS | |||
| m_debugDrawer->drawLine(startPt,endPt,btVector3(1,0,0)); | |||
| m_debugDrawer->drawSphere(startPt,0.05,btVector3(0,1,0)); | |||
| m_debugDrawer->drawSphere(endPt,0.05,btVector3(0,0,1)); | |||
| #endif //DEBUG_CONTACTS | |||
| m_originalManifoldResult->addContactPoint(normalOnBInWorld,startPt,newDepth); | |||
| } | |||
| }; | |||
| extern btScalar gContactBreakingThreshold; | |||
| // | |||
| // Convex-Convex collision algorithm | |||
| // | |||
| void btConvexConvexAlgorithm ::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| if (!m_manifoldPtr) | |||
| { | |||
| //swapped? | |||
| m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1); | |||
| m_ownManifold = true; | |||
| } | |||
| resultOut->setPersistentManifold(m_manifoldPtr); | |||
| //comment-out next line to test multi-contact generation | |||
| //resultOut->getPersistentManifold()->clearManifold(); | |||
| btConvexShape* min0 = static_cast<btConvexShape*>(body0->getCollisionShape()); | |||
| btConvexShape* min1 = static_cast<btConvexShape*>(body1->getCollisionShape()); | |||
| btVector3 normalOnB; | |||
| btVector3 pointOnBWorld; | |||
| #ifndef BT_DISABLE_CAPSULE_CAPSULE_COLLIDER | |||
| if ((min0->getShapeType() == CAPSULE_SHAPE_PROXYTYPE) && (min1->getShapeType() == CAPSULE_SHAPE_PROXYTYPE)) | |||
| { | |||
| btCapsuleShape* capsuleA = (btCapsuleShape*) min0; | |||
| btCapsuleShape* capsuleB = (btCapsuleShape*) min1; | |||
| btVector3 localScalingA = capsuleA->getLocalScaling(); | |||
| btVector3 localScalingB = capsuleB->getLocalScaling(); | |||
| btScalar threshold = m_manifoldPtr->getContactBreakingThreshold(); | |||
| btScalar dist = capsuleCapsuleDistance(normalOnB, pointOnBWorld,capsuleA->getHalfHeight(),capsuleA->getRadius(), | |||
| capsuleB->getHalfHeight(),capsuleB->getRadius(),capsuleA->getUpAxis(),capsuleB->getUpAxis(), | |||
| body0->getWorldTransform(),body1->getWorldTransform(),threshold); | |||
| if (dist<threshold) | |||
| { | |||
| btAssert(normalOnB.length2()>=(SIMD_EPSILON*SIMD_EPSILON)); | |||
| resultOut->addContactPoint(normalOnB,pointOnBWorld,dist); | |||
| } | |||
| resultOut->refreshContactPoints(); | |||
| return; | |||
| } | |||
| #endif //BT_DISABLE_CAPSULE_CAPSULE_COLLIDER | |||
| #ifdef USE_SEPDISTANCE_UTIL2 | |||
| if (dispatchInfo.m_useConvexConservativeDistanceUtil) | |||
| { | |||
| m_sepDistance.updateSeparatingDistance(body0->getWorldTransform(),body1->getWorldTransform()); | |||
| } | |||
| if (!dispatchInfo.m_useConvexConservativeDistanceUtil || m_sepDistance.getConservativeSeparatingDistance()<=0.f) | |||
| #endif //USE_SEPDISTANCE_UTIL2 | |||
| { | |||
| btGjkPairDetector::ClosestPointInput input; | |||
| btGjkPairDetector gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver); | |||
| //TODO: if (dispatchInfo.m_useContinuous) | |||
| gjkPairDetector.setMinkowskiA(min0); | |||
| gjkPairDetector.setMinkowskiB(min1); | |||
| #ifdef USE_SEPDISTANCE_UTIL2 | |||
| if (dispatchInfo.m_useConvexConservativeDistanceUtil) | |||
| { | |||
| input.m_maximumDistanceSquared = BT_LARGE_FLOAT; | |||
| } else | |||
| #endif //USE_SEPDISTANCE_UTIL2 | |||
| { | |||
| //if (dispatchInfo.m_convexMaxDistanceUseCPT) | |||
| //{ | |||
| // input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactProcessingThreshold(); | |||
| //} else | |||
| //{ | |||
| input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold(); | |||
| // } | |||
| input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared; | |||
| } | |||
| input.m_stackAlloc = dispatchInfo.m_stackAllocator; | |||
| input.m_transformA = body0->getWorldTransform(); | |||
| input.m_transformB = body1->getWorldTransform(); | |||
| #ifdef USE_SEPDISTANCE_UTIL2 | |||
| btScalar sepDist = 0.f; | |||
| if (dispatchInfo.m_useConvexConservativeDistanceUtil) | |||
| { | |||
| sepDist = gjkPairDetector.getCachedSeparatingDistance(); | |||
| if (sepDist>SIMD_EPSILON) | |||
| { | |||
| sepDist += dispatchInfo.m_convexConservativeDistanceThreshold; | |||
| //now perturbe directions to get multiple contact points | |||
| } | |||
| } | |||
| #endif //USE_SEPDISTANCE_UTIL2 | |||
| if (min0->isPolyhedral() && min1->isPolyhedral()) | |||
| { | |||
| struct btDummyResult : public btDiscreteCollisionDetectorInterface::Result | |||
| { | |||
| virtual void setShapeIdentifiersA(int partId0,int index0){} | |||
| virtual void setShapeIdentifiersB(int partId1,int index1){} | |||
| virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) | |||
| { | |||
| } | |||
| }; | |||
| btDummyResult dummy; | |||
| btPolyhedralConvexShape* polyhedronA = (btPolyhedralConvexShape*) min0; | |||
| btPolyhedralConvexShape* polyhedronB = (btPolyhedralConvexShape*) min1; | |||
| if (polyhedronA->getConvexPolyhedron() && polyhedronB->getConvexPolyhedron()) | |||
| { | |||
| btScalar threshold = m_manifoldPtr->getContactBreakingThreshold(); | |||
| btScalar minDist = -1e30f; | |||
| btVector3 sepNormalWorldSpace; | |||
| bool foundSepAxis = true; | |||
| if (dispatchInfo.m_enableSatConvex) | |||
| { | |||
| foundSepAxis = btPolyhedralContactClipping::findSeparatingAxis( | |||
| *polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(), | |||
| body0->getWorldTransform(), | |||
| body1->getWorldTransform(), | |||
| sepNormalWorldSpace); | |||
| } else | |||
| { | |||
| #ifdef ZERO_MARGIN | |||
| gjkPairDetector.setIgnoreMargin(true); | |||
| gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); | |||
| #else | |||
| //gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); | |||
| gjkPairDetector.getClosestPoints(input,dummy,dispatchInfo.m_debugDraw); | |||
| #endif //ZERO_MARGIN | |||
| btScalar l2 = gjkPairDetector.getCachedSeparatingAxis().length2(); | |||
| if (l2>SIMD_EPSILON) | |||
| { | |||
| sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis()*(1.f/l2); | |||
| //minDist = -1e30f;//gjkPairDetector.getCachedSeparatingDistance(); | |||
| minDist = gjkPairDetector.getCachedSeparatingDistance()-min0->getMargin()-min1->getMargin(); | |||
| #ifdef ZERO_MARGIN | |||
| foundSepAxis = true;//gjkPairDetector.getCachedSeparatingDistance()<0.f; | |||
| #else | |||
| foundSepAxis = gjkPairDetector.getCachedSeparatingDistance()<(min0->getMargin()+min1->getMargin()); | |||
| #endif | |||
| } | |||
| } | |||
| if (foundSepAxis) | |||
| { | |||
| // printf("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.getX(),sepNormalWorldSpace.getY(),sepNormalWorldSpace.getZ()); | |||
| btPolyhedralContactClipping::clipHullAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(), | |||
| body0->getWorldTransform(), | |||
| body1->getWorldTransform(), minDist-threshold, threshold, *resultOut); | |||
| } | |||
| if (m_ownManifold) | |||
| { | |||
| resultOut->refreshContactPoints(); | |||
| } | |||
| return; | |||
| } else | |||
| { | |||
| //we can also deal with convex versus triangle (without connectivity data) | |||
| if (polyhedronA->getConvexPolyhedron() && polyhedronB->getShapeType()==TRIANGLE_SHAPE_PROXYTYPE) | |||
| { | |||
| btVertexArray vertices; | |||
| btTriangleShape* tri = (btTriangleShape*)polyhedronB; | |||
| vertices.push_back( body1->getWorldTransform()*tri->m_vertices1[0]); | |||
| vertices.push_back( body1->getWorldTransform()*tri->m_vertices1[1]); | |||
| vertices.push_back( body1->getWorldTransform()*tri->m_vertices1[2]); | |||
| //tri->initializePolyhedralFeatures(); | |||
| btScalar threshold = m_manifoldPtr->getContactBreakingThreshold(); | |||
| btVector3 sepNormalWorldSpace; | |||
| btScalar minDist =-1e30f; | |||
| btScalar maxDist = threshold; | |||
| bool foundSepAxis = false; | |||
| if (0) | |||
| { | |||
| polyhedronB->initializePolyhedralFeatures(); | |||
| foundSepAxis = btPolyhedralContactClipping::findSeparatingAxis( | |||
| *polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(), | |||
| body0->getWorldTransform(), | |||
| body1->getWorldTransform(), | |||
| sepNormalWorldSpace); | |||
| // printf("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.getX(),sepNormalWorldSpace.getY(),sepNormalWorldSpace.getZ()); | |||
| } else | |||
| { | |||
| #ifdef ZERO_MARGIN | |||
| gjkPairDetector.setIgnoreMargin(true); | |||
| gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); | |||
| #else | |||
| gjkPairDetector.getClosestPoints(input,dummy,dispatchInfo.m_debugDraw); | |||
| #endif//ZERO_MARGIN | |||
| btScalar l2 = gjkPairDetector.getCachedSeparatingAxis().length2(); | |||
| if (l2>SIMD_EPSILON) | |||
| { | |||
| sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis()*(1.f/l2); | |||
| //minDist = gjkPairDetector.getCachedSeparatingDistance(); | |||
| //maxDist = threshold; | |||
| minDist = gjkPairDetector.getCachedSeparatingDistance()-min0->getMargin()-min1->getMargin(); | |||
| foundSepAxis = true; | |||
| } | |||
| } | |||
| if (foundSepAxis) | |||
| { | |||
| btPolyhedralContactClipping::clipFaceAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(), | |||
| body0->getWorldTransform(), vertices, minDist-threshold, maxDist, *resultOut); | |||
| } | |||
| if (m_ownManifold) | |||
| { | |||
| resultOut->refreshContactPoints(); | |||
| } | |||
| return; | |||
| } | |||
| } | |||
| } | |||
| gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); | |||
| //now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects | |||
| //perform perturbation when more then 'm_minimumPointsPerturbationThreshold' points | |||
| if (m_numPerturbationIterations && resultOut->getPersistentManifold()->getNumContacts() < m_minimumPointsPerturbationThreshold) | |||
| { | |||
| int i; | |||
| btVector3 v0,v1; | |||
| btVector3 sepNormalWorldSpace; | |||
| btScalar l2 = gjkPairDetector.getCachedSeparatingAxis().length2(); | |||
| if (l2>SIMD_EPSILON) | |||
| { | |||
| sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis()*(1.f/l2); | |||
| btPlaneSpace1(sepNormalWorldSpace,v0,v1); | |||
| bool perturbeA = true; | |||
| const btScalar angleLimit = 0.125f * SIMD_PI; | |||
| btScalar perturbeAngle; | |||
| btScalar radiusA = min0->getAngularMotionDisc(); | |||
| btScalar radiusB = min1->getAngularMotionDisc(); | |||
| if (radiusA < radiusB) | |||
| { | |||
| perturbeAngle = gContactBreakingThreshold /radiusA; | |||
| perturbeA = true; | |||
| } else | |||
| { | |||
| perturbeAngle = gContactBreakingThreshold / radiusB; | |||
| perturbeA = false; | |||
| } | |||
| if ( perturbeAngle > angleLimit ) | |||
| perturbeAngle = angleLimit; | |||
| btTransform unPerturbedTransform; | |||
| if (perturbeA) | |||
| { | |||
| unPerturbedTransform = input.m_transformA; | |||
| } else | |||
| { | |||
| unPerturbedTransform = input.m_transformB; | |||
| } | |||
| for ( i=0;i<m_numPerturbationIterations;i++) | |||
| { | |||
| if (v0.length2()>SIMD_EPSILON) | |||
| { | |||
| btQuaternion perturbeRot(v0,perturbeAngle); | |||
| btScalar iterationAngle = i*(SIMD_2_PI/btScalar(m_numPerturbationIterations)); | |||
| btQuaternion rotq(sepNormalWorldSpace,iterationAngle); | |||
| if (perturbeA) | |||
| { | |||
| input.m_transformA.setBasis( btMatrix3x3(rotq.inverse()*perturbeRot*rotq)*body0->getWorldTransform().getBasis()); | |||
| input.m_transformB = body1->getWorldTransform(); | |||
| #ifdef DEBUG_CONTACTS | |||
| dispatchInfo.m_debugDraw->drawTransform(input.m_transformA,10.0); | |||
| #endif //DEBUG_CONTACTS | |||
| } else | |||
| { | |||
| input.m_transformA = body0->getWorldTransform(); | |||
| input.m_transformB.setBasis( btMatrix3x3(rotq.inverse()*perturbeRot*rotq)*body1->getWorldTransform().getBasis()); | |||
| #ifdef DEBUG_CONTACTS | |||
| dispatchInfo.m_debugDraw->drawTransform(input.m_transformB,10.0); | |||
| #endif | |||
| } | |||
| btPerturbedContactResult perturbedResultOut(resultOut,input.m_transformA,input.m_transformB,unPerturbedTransform,perturbeA,dispatchInfo.m_debugDraw); | |||
| gjkPairDetector.getClosestPoints(input,perturbedResultOut,dispatchInfo.m_debugDraw); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| #ifdef USE_SEPDISTANCE_UTIL2 | |||
| if (dispatchInfo.m_useConvexConservativeDistanceUtil && (sepDist>SIMD_EPSILON)) | |||
| { | |||
| m_sepDistance.initSeparatingDistance(gjkPairDetector.getCachedSeparatingAxis(),sepDist,body0->getWorldTransform(),body1->getWorldTransform()); | |||
| } | |||
| #endif //USE_SEPDISTANCE_UTIL2 | |||
| } | |||
| if (m_ownManifold) | |||
| { | |||
| resultOut->refreshContactPoints(); | |||
| } | |||
| } | |||
| bool disableCcd = false; | |||
| btScalar btConvexConvexAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| (void)resultOut; | |||
| (void)dispatchInfo; | |||
| ///Rather then checking ALL pairs, only calculate TOI when motion exceeds threshold | |||
| ///Linear motion for one of objects needs to exceed m_ccdSquareMotionThreshold | |||
| ///col0->m_worldTransform, | |||
| btScalar resultFraction = btScalar(1.); | |||
| btScalar squareMot0 = (col0->getInterpolationWorldTransform().getOrigin() - col0->getWorldTransform().getOrigin()).length2(); | |||
| btScalar squareMot1 = (col1->getInterpolationWorldTransform().getOrigin() - col1->getWorldTransform().getOrigin()).length2(); | |||
| if (squareMot0 < col0->getCcdSquareMotionThreshold() && | |||
| squareMot1 < col1->getCcdSquareMotionThreshold()) | |||
| return resultFraction; | |||
| if (disableCcd) | |||
| return btScalar(1.); | |||
| //An adhoc way of testing the Continuous Collision Detection algorithms | |||
| //One object is approximated as a sphere, to simplify things | |||
| //Starting in penetration should report no time of impact | |||
| //For proper CCD, better accuracy and handling of 'allowed' penetration should be added | |||
| //also the mainloop of the physics should have a kind of toi queue (something like Brian Mirtich's application of Timewarp for Rigidbodies) | |||
| /// Convex0 against sphere for Convex1 | |||
| { | |||
| btConvexShape* convex0 = static_cast<btConvexShape*>(col0->getCollisionShape()); | |||
| btSphereShape sphere1(col1->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation | |||
| btConvexCast::CastResult result; | |||
| btVoronoiSimplexSolver voronoiSimplex; | |||
| //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); | |||
| ///Simplification, one object is simplified as a sphere | |||
| btGjkConvexCast ccd1( convex0 ,&sphere1,&voronoiSimplex); | |||
| //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); | |||
| if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), | |||
| col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) | |||
| { | |||
| //store result.m_fraction in both bodies | |||
| if (col0->getHitFraction()> result.m_fraction) | |||
| col0->setHitFraction( result.m_fraction ); | |||
| if (col1->getHitFraction() > result.m_fraction) | |||
| col1->setHitFraction( result.m_fraction); | |||
| if (resultFraction > result.m_fraction) | |||
| resultFraction = result.m_fraction; | |||
| } | |||
| } | |||
| /// Sphere (for convex0) against Convex1 | |||
| { | |||
| btConvexShape* convex1 = static_cast<btConvexShape*>(col1->getCollisionShape()); | |||
| btSphereShape sphere0(col0->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation | |||
| btConvexCast::CastResult result; | |||
| btVoronoiSimplexSolver voronoiSimplex; | |||
| //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); | |||
| ///Simplification, one object is simplified as a sphere | |||
| btGjkConvexCast ccd1(&sphere0,convex1,&voronoiSimplex); | |||
| //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); | |||
| if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), | |||
| col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) | |||
| { | |||
| //store result.m_fraction in both bodies | |||
| if (col0->getHitFraction() > result.m_fraction) | |||
| col0->setHitFraction( result.m_fraction); | |||
| if (col1->getHitFraction() > result.m_fraction) | |||
| col1->setHitFraction( result.m_fraction); | |||
| if (resultFraction > result.m_fraction) | |||
| resultFraction = result.m_fraction; | |||
| } | |||
| } | |||
| return resultFraction; | |||
| } | |||
| @@ -0,0 +1,109 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_CONVEX_CONVEX_ALGORITHM_H | |||
| #define BT_CONVEX_CONVEX_ALGORITHM_H | |||
| #include "btActivatingCollisionAlgorithm.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" | |||
| #include "btCollisionCreateFunc.h" | |||
| #include "btCollisionDispatcher.h" | |||
| #include "LinearMath/btTransformUtil.h" //for btConvexSeparatingDistanceUtil | |||
| class btConvexPenetrationDepthSolver; | |||
| ///Enabling USE_SEPDISTANCE_UTIL2 requires 100% reliable distance computation. However, when using large size ratios GJK can be imprecise | |||
| ///so the distance is not conservative. In that case, enabling this USE_SEPDISTANCE_UTIL2 would result in failing/missing collisions. | |||
| ///Either improve GJK for large size ratios (testing a 100 units versus a 0.1 unit object) or only enable the util | |||
| ///for certain pairs that have a small size ratio | |||
| //#define USE_SEPDISTANCE_UTIL2 1 | |||
| ///The convexConvexAlgorithm collision algorithm implements time of impact, convex closest points and penetration depth calculations between two convex objects. | |||
| ///Multiple contact points are calculated by perturbing the orientation of the smallest object orthogonal to the separating normal. | |||
| ///This idea was described by Gino van den Bergen in this forum topic http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=4&t=288&p=888#p888 | |||
| class btConvexConvexAlgorithm : public btActivatingCollisionAlgorithm | |||
| { | |||
| #ifdef USE_SEPDISTANCE_UTIL2 | |||
| btConvexSeparatingDistanceUtil m_sepDistance; | |||
| #endif | |||
| btSimplexSolverInterface* m_simplexSolver; | |||
| btConvexPenetrationDepthSolver* m_pdSolver; | |||
| bool m_ownManifold; | |||
| btPersistentManifold* m_manifoldPtr; | |||
| bool m_lowLevelOfDetail; | |||
| int m_numPerturbationIterations; | |||
| int m_minimumPointsPerturbationThreshold; | |||
| ///cache separating vector to speedup collision detection | |||
| public: | |||
| btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold); | |||
| virtual ~btConvexConvexAlgorithm(); | |||
| virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
| { | |||
| ///should we use m_ownManifold to avoid adding duplicates? | |||
| if (m_manifoldPtr && m_ownManifold) | |||
| manifoldArray.push_back(m_manifoldPtr); | |||
| } | |||
| void setLowLevelOfDetail(bool useLowLevel); | |||
| const btPersistentManifold* getManifold() | |||
| { | |||
| return m_manifoldPtr; | |||
| } | |||
| struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| btConvexPenetrationDepthSolver* m_pdSolver; | |||
| btSimplexSolverInterface* m_simplexSolver; | |||
| int m_numPerturbationIterations; | |||
| int m_minimumPointsPerturbationThreshold; | |||
| CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver); | |||
| virtual ~CreateFunc(); | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConvexAlgorithm)); | |||
| return new(mem) btConvexConvexAlgorithm(ci.m_manifold,ci,body0,body1,m_simplexSolver,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); | |||
| } | |||
| }; | |||
| }; | |||
| #endif //BT_CONVEX_CONVEX_ALGORITHM_H | |||
| @@ -0,0 +1,173 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btConvexPlaneCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| #include "BulletCollision/CollisionShapes/btConvexShape.h" | |||
| #include "BulletCollision/CollisionShapes/btStaticPlaneShape.h" | |||
| //#include <stdio.h> | |||
| btConvexPlaneCollisionAlgorithm::btConvexPlaneCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped, int numPerturbationIterations,int minimumPointsPerturbationThreshold) | |||
| : btCollisionAlgorithm(ci), | |||
| m_ownManifold(false), | |||
| m_manifoldPtr(mf), | |||
| m_isSwapped(isSwapped), | |||
| m_numPerturbationIterations(numPerturbationIterations), | |||
| m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold) | |||
| { | |||
| btCollisionObject* convexObj = m_isSwapped? col1 : col0; | |||
| btCollisionObject* planeObj = m_isSwapped? col0 : col1; | |||
| if (!m_manifoldPtr && m_dispatcher->needsCollision(convexObj,planeObj)) | |||
| { | |||
| m_manifoldPtr = m_dispatcher->getNewManifold(convexObj,planeObj); | |||
| m_ownManifold = true; | |||
| } | |||
| } | |||
| btConvexPlaneCollisionAlgorithm::~btConvexPlaneCollisionAlgorithm() | |||
| { | |||
| if (m_ownManifold) | |||
| { | |||
| if (m_manifoldPtr) | |||
| m_dispatcher->releaseManifold(m_manifoldPtr); | |||
| } | |||
| } | |||
| void btConvexPlaneCollisionAlgorithm::collideSingleContact (const btQuaternion& perturbeRot, btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| btCollisionObject* convexObj = m_isSwapped? body1 : body0; | |||
| btCollisionObject* planeObj = m_isSwapped? body0: body1; | |||
| btConvexShape* convexShape = (btConvexShape*) convexObj->getCollisionShape(); | |||
| btStaticPlaneShape* planeShape = (btStaticPlaneShape*) planeObj->getCollisionShape(); | |||
| bool hasCollision = false; | |||
| const btVector3& planeNormal = planeShape->getPlaneNormal(); | |||
| const btScalar& planeConstant = planeShape->getPlaneConstant(); | |||
| btTransform convexWorldTransform = convexObj->getWorldTransform(); | |||
| btTransform convexInPlaneTrans; | |||
| convexInPlaneTrans= planeObj->getWorldTransform().inverse() * convexWorldTransform; | |||
| //now perturbe the convex-world transform | |||
| convexWorldTransform.getBasis()*=btMatrix3x3(perturbeRot); | |||
| btTransform planeInConvex; | |||
| planeInConvex= convexWorldTransform.inverse() * planeObj->getWorldTransform(); | |||
| btVector3 vtx = convexShape->localGetSupportingVertex(planeInConvex.getBasis()*-planeNormal); | |||
| btVector3 vtxInPlane = convexInPlaneTrans(vtx); | |||
| btScalar distance = (planeNormal.dot(vtxInPlane) - planeConstant); | |||
| btVector3 vtxInPlaneProjected = vtxInPlane - distance*planeNormal; | |||
| btVector3 vtxInPlaneWorld = planeObj->getWorldTransform() * vtxInPlaneProjected; | |||
| hasCollision = distance < m_manifoldPtr->getContactBreakingThreshold(); | |||
| resultOut->setPersistentManifold(m_manifoldPtr); | |||
| if (hasCollision) | |||
| { | |||
| /// report a contact. internally this will be kept persistent, and contact reduction is done | |||
| btVector3 normalOnSurfaceB = planeObj->getWorldTransform().getBasis() * planeNormal; | |||
| btVector3 pOnB = vtxInPlaneWorld; | |||
| resultOut->addContactPoint(normalOnSurfaceB,pOnB,distance); | |||
| } | |||
| } | |||
| void btConvexPlaneCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| (void)dispatchInfo; | |||
| if (!m_manifoldPtr) | |||
| return; | |||
| btCollisionObject* convexObj = m_isSwapped? body1 : body0; | |||
| btCollisionObject* planeObj = m_isSwapped? body0: body1; | |||
| btConvexShape* convexShape = (btConvexShape*) convexObj->getCollisionShape(); | |||
| btStaticPlaneShape* planeShape = (btStaticPlaneShape*) planeObj->getCollisionShape(); | |||
| bool hasCollision = false; | |||
| const btVector3& planeNormal = planeShape->getPlaneNormal(); | |||
| const btScalar& planeConstant = planeShape->getPlaneConstant(); | |||
| btTransform planeInConvex; | |||
| planeInConvex= convexObj->getWorldTransform().inverse() * planeObj->getWorldTransform(); | |||
| btTransform convexInPlaneTrans; | |||
| convexInPlaneTrans= planeObj->getWorldTransform().inverse() * convexObj->getWorldTransform(); | |||
| btVector3 vtx = convexShape->localGetSupportingVertex(planeInConvex.getBasis()*-planeNormal); | |||
| btVector3 vtxInPlane = convexInPlaneTrans(vtx); | |||
| btScalar distance = (planeNormal.dot(vtxInPlane) - planeConstant); | |||
| btVector3 vtxInPlaneProjected = vtxInPlane - distance*planeNormal; | |||
| btVector3 vtxInPlaneWorld = planeObj->getWorldTransform() * vtxInPlaneProjected; | |||
| hasCollision = distance < m_manifoldPtr->getContactBreakingThreshold(); | |||
| resultOut->setPersistentManifold(m_manifoldPtr); | |||
| if (hasCollision) | |||
| { | |||
| /// report a contact. internally this will be kept persistent, and contact reduction is done | |||
| btVector3 normalOnSurfaceB = planeObj->getWorldTransform().getBasis() * planeNormal; | |||
| btVector3 pOnB = vtxInPlaneWorld; | |||
| resultOut->addContactPoint(normalOnSurfaceB,pOnB,distance); | |||
| } | |||
| //the perturbation algorithm doesn't work well with implicit surfaces such as spheres, cylinder and cones: | |||
| //they keep on rolling forever because of the additional off-center contact points | |||
| //so only enable the feature for polyhedral shapes (btBoxShape, btConvexHullShape etc) | |||
| if (convexShape->isPolyhedral() && resultOut->getPersistentManifold()->getNumContacts()<m_minimumPointsPerturbationThreshold) | |||
| { | |||
| btVector3 v0,v1; | |||
| btPlaneSpace1(planeNormal,v0,v1); | |||
| //now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects | |||
| const btScalar angleLimit = 0.125f * SIMD_PI; | |||
| btScalar perturbeAngle; | |||
| btScalar radius = convexShape->getAngularMotionDisc(); | |||
| perturbeAngle = gContactBreakingThreshold / radius; | |||
| if ( perturbeAngle > angleLimit ) | |||
| perturbeAngle = angleLimit; | |||
| btQuaternion perturbeRot(v0,perturbeAngle); | |||
| for (int i=0;i<m_numPerturbationIterations;i++) | |||
| { | |||
| btScalar iterationAngle = i*(SIMD_2_PI/btScalar(m_numPerturbationIterations)); | |||
| btQuaternion rotq(planeNormal,iterationAngle); | |||
| collideSingleContact(rotq.inverse()*perturbeRot*rotq,body0,body1,dispatchInfo,resultOut); | |||
| } | |||
| } | |||
| if (m_ownManifold) | |||
| { | |||
| if (m_manifoldPtr->getNumContacts()) | |||
| { | |||
| resultOut->refreshContactPoints(); | |||
| } | |||
| } | |||
| } | |||
| btScalar btConvexPlaneCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| (void)resultOut; | |||
| (void)dispatchInfo; | |||
| (void)col0; | |||
| (void)col1; | |||
| //not yet | |||
| return btScalar(1.); | |||
| } | |||
| @@ -0,0 +1,84 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_CONVEX_PLANE_COLLISION_ALGORITHM_H | |||
| #define BT_CONVEX_PLANE_COLLISION_ALGORITHM_H | |||
| #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
| class btPersistentManifold; | |||
| #include "btCollisionDispatcher.h" | |||
| #include "LinearMath/btVector3.h" | |||
| /// btSphereBoxCollisionAlgorithm provides sphere-box collision detection. | |||
| /// Other features are frame-coherency (persistent data) and collision response. | |||
| class btConvexPlaneCollisionAlgorithm : public btCollisionAlgorithm | |||
| { | |||
| bool m_ownManifold; | |||
| btPersistentManifold* m_manifoldPtr; | |||
| bool m_isSwapped; | |||
| int m_numPerturbationIterations; | |||
| int m_minimumPointsPerturbationThreshold; | |||
| public: | |||
| btConvexPlaneCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped, int numPerturbationIterations,int minimumPointsPerturbationThreshold); | |||
| virtual ~btConvexPlaneCollisionAlgorithm(); | |||
| virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| void collideSingleContact (const btQuaternion& perturbeRot, btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
| { | |||
| if (m_manifoldPtr && m_ownManifold) | |||
| { | |||
| manifoldArray.push_back(m_manifoldPtr); | |||
| } | |||
| } | |||
| struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| int m_numPerturbationIterations; | |||
| int m_minimumPointsPerturbationThreshold; | |||
| CreateFunc() | |||
| : m_numPerturbationIterations(1), | |||
| m_minimumPointsPerturbationThreshold(0) | |||
| { | |||
| } | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexPlaneCollisionAlgorithm)); | |||
| if (!m_swapped) | |||
| { | |||
| return new(mem) btConvexPlaneCollisionAlgorithm(0,ci,body0,body1,false,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); | |||
| } else | |||
| { | |||
| return new(mem) btConvexPlaneCollisionAlgorithm(0,ci,body0,body1,true,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); | |||
| } | |||
| } | |||
| }; | |||
| }; | |||
| #endif //BT_CONVEX_PLANE_COLLISION_ALGORITHM_H | |||
| @@ -0,0 +1,309 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btDefaultCollisionConfiguration.h" | |||
| #include "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h" | |||
| #ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
| #include "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h" | |||
| #endif //USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
| #include "BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" | |||
| #include "LinearMath/btStackAlloc.h" | |||
| #include "LinearMath/btPoolAllocator.h" | |||
| btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefaultCollisionConstructionInfo& constructionInfo) | |||
| //btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(btStackAlloc* stackAlloc,btPoolAllocator* persistentManifoldPool,btPoolAllocator* collisionAlgorithmPool) | |||
| { | |||
| void* mem = btAlignedAlloc(sizeof(btVoronoiSimplexSolver),16); | |||
| m_simplexSolver = new (mem)btVoronoiSimplexSolver(); | |||
| if (constructionInfo.m_useEpaPenetrationAlgorithm) | |||
| { | |||
| mem = btAlignedAlloc(sizeof(btGjkEpaPenetrationDepthSolver),16); | |||
| m_pdSolver = new (mem)btGjkEpaPenetrationDepthSolver; | |||
| }else | |||
| { | |||
| mem = btAlignedAlloc(sizeof(btMinkowskiPenetrationDepthSolver),16); | |||
| m_pdSolver = new (mem)btMinkowskiPenetrationDepthSolver; | |||
| } | |||
| //default CreationFunctions, filling the m_doubleDispatch table | |||
| mem = btAlignedAlloc(sizeof(btConvexConvexAlgorithm::CreateFunc),16); | |||
| m_convexConvexCreateFunc = new(mem) btConvexConvexAlgorithm::CreateFunc(m_simplexSolver,m_pdSolver); | |||
| mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16); | |||
| m_convexConcaveCreateFunc = new (mem)btConvexConcaveCollisionAlgorithm::CreateFunc; | |||
| mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16); | |||
| m_swappedConvexConcaveCreateFunc = new (mem)btConvexConcaveCollisionAlgorithm::SwappedCreateFunc; | |||
| mem = btAlignedAlloc(sizeof(btCompoundCollisionAlgorithm::CreateFunc),16); | |||
| m_compoundCreateFunc = new (mem)btCompoundCollisionAlgorithm::CreateFunc; | |||
| mem = btAlignedAlloc(sizeof(btCompoundCollisionAlgorithm::SwappedCreateFunc),16); | |||
| m_swappedCompoundCreateFunc = new (mem)btCompoundCollisionAlgorithm::SwappedCreateFunc; | |||
| mem = btAlignedAlloc(sizeof(btEmptyAlgorithm::CreateFunc),16); | |||
| m_emptyCreateFunc = new(mem) btEmptyAlgorithm::CreateFunc; | |||
| mem = btAlignedAlloc(sizeof(btSphereSphereCollisionAlgorithm::CreateFunc),16); | |||
| m_sphereSphereCF = new(mem) btSphereSphereCollisionAlgorithm::CreateFunc; | |||
| #ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
| mem = btAlignedAlloc(sizeof(btSphereBoxCollisionAlgorithm::CreateFunc),16); | |||
| m_sphereBoxCF = new(mem) btSphereBoxCollisionAlgorithm::CreateFunc; | |||
| mem = btAlignedAlloc(sizeof(btSphereBoxCollisionAlgorithm::CreateFunc),16); | |||
| m_boxSphereCF = new (mem)btSphereBoxCollisionAlgorithm::CreateFunc; | |||
| m_boxSphereCF->m_swapped = true; | |||
| #endif //USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
| mem = btAlignedAlloc(sizeof(btSphereTriangleCollisionAlgorithm::CreateFunc),16); | |||
| m_sphereTriangleCF = new (mem)btSphereTriangleCollisionAlgorithm::CreateFunc; | |||
| mem = btAlignedAlloc(sizeof(btSphereTriangleCollisionAlgorithm::CreateFunc),16); | |||
| m_triangleSphereCF = new (mem)btSphereTriangleCollisionAlgorithm::CreateFunc; | |||
| m_triangleSphereCF->m_swapped = true; | |||
| mem = btAlignedAlloc(sizeof(btBoxBoxCollisionAlgorithm::CreateFunc),16); | |||
| m_boxBoxCF = new(mem)btBoxBoxCollisionAlgorithm::CreateFunc; | |||
| //convex versus plane | |||
| mem = btAlignedAlloc (sizeof(btConvexPlaneCollisionAlgorithm::CreateFunc),16); | |||
| m_convexPlaneCF = new (mem) btConvexPlaneCollisionAlgorithm::CreateFunc; | |||
| mem = btAlignedAlloc (sizeof(btConvexPlaneCollisionAlgorithm::CreateFunc),16); | |||
| m_planeConvexCF = new (mem) btConvexPlaneCollisionAlgorithm::CreateFunc; | |||
| m_planeConvexCF->m_swapped = true; | |||
| ///calculate maximum element size, big enough to fit any collision algorithm in the memory pool | |||
| int maxSize = sizeof(btConvexConvexAlgorithm); | |||
| int maxSize2 = sizeof(btConvexConcaveCollisionAlgorithm); | |||
| int maxSize3 = sizeof(btCompoundCollisionAlgorithm); | |||
| int sl = sizeof(btConvexSeparatingDistanceUtil); | |||
| sl = sizeof(btGjkPairDetector); | |||
| int collisionAlgorithmMaxElementSize = btMax(maxSize,constructionInfo.m_customCollisionAlgorithmMaxElementSize); | |||
| collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize2); | |||
| collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize3); | |||
| if (constructionInfo.m_stackAlloc) | |||
| { | |||
| m_ownsStackAllocator = false; | |||
| this->m_stackAlloc = constructionInfo.m_stackAlloc; | |||
| } else | |||
| { | |||
| m_ownsStackAllocator = true; | |||
| void* mem = btAlignedAlloc(sizeof(btStackAlloc),16); | |||
| m_stackAlloc = new(mem)btStackAlloc(constructionInfo.m_defaultStackAllocatorSize); | |||
| } | |||
| if (constructionInfo.m_persistentManifoldPool) | |||
| { | |||
| m_ownsPersistentManifoldPool = false; | |||
| m_persistentManifoldPool = constructionInfo.m_persistentManifoldPool; | |||
| } else | |||
| { | |||
| m_ownsPersistentManifoldPool = true; | |||
| void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16); | |||
| m_persistentManifoldPool = new (mem) btPoolAllocator(sizeof(btPersistentManifold),constructionInfo.m_defaultMaxPersistentManifoldPoolSize); | |||
| } | |||
| if (constructionInfo.m_collisionAlgorithmPool) | |||
| { | |||
| m_ownsCollisionAlgorithmPool = false; | |||
| m_collisionAlgorithmPool = constructionInfo.m_collisionAlgorithmPool; | |||
| } else | |||
| { | |||
| m_ownsCollisionAlgorithmPool = true; | |||
| void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16); | |||
| m_collisionAlgorithmPool = new(mem) btPoolAllocator(collisionAlgorithmMaxElementSize,constructionInfo.m_defaultMaxCollisionAlgorithmPoolSize); | |||
| } | |||
| } | |||
| btDefaultCollisionConfiguration::~btDefaultCollisionConfiguration() | |||
| { | |||
| if (m_ownsStackAllocator) | |||
| { | |||
| m_stackAlloc->destroy(); | |||
| m_stackAlloc->~btStackAlloc(); | |||
| btAlignedFree(m_stackAlloc); | |||
| } | |||
| if (m_ownsCollisionAlgorithmPool) | |||
| { | |||
| m_collisionAlgorithmPool->~btPoolAllocator(); | |||
| btAlignedFree(m_collisionAlgorithmPool); | |||
| } | |||
| if (m_ownsPersistentManifoldPool) | |||
| { | |||
| m_persistentManifoldPool->~btPoolAllocator(); | |||
| btAlignedFree(m_persistentManifoldPool); | |||
| } | |||
| m_convexConvexCreateFunc->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_convexConvexCreateFunc); | |||
| m_convexConcaveCreateFunc->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_convexConcaveCreateFunc); | |||
| m_swappedConvexConcaveCreateFunc->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_swappedConvexConcaveCreateFunc); | |||
| m_compoundCreateFunc->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_compoundCreateFunc); | |||
| m_swappedCompoundCreateFunc->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_swappedCompoundCreateFunc); | |||
| m_emptyCreateFunc->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_emptyCreateFunc); | |||
| m_sphereSphereCF->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_sphereSphereCF); | |||
| #ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
| m_sphereBoxCF->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_sphereBoxCF); | |||
| m_boxSphereCF->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_boxSphereCF); | |||
| #endif //USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
| m_sphereTriangleCF->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_sphereTriangleCF); | |||
| m_triangleSphereCF->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_triangleSphereCF); | |||
| m_boxBoxCF->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_boxBoxCF); | |||
| m_convexPlaneCF->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_convexPlaneCF); | |||
| m_planeConvexCF->~btCollisionAlgorithmCreateFunc(); | |||
| btAlignedFree( m_planeConvexCF); | |||
| m_simplexSolver->~btVoronoiSimplexSolver(); | |||
| btAlignedFree(m_simplexSolver); | |||
| m_pdSolver->~btConvexPenetrationDepthSolver(); | |||
| btAlignedFree(m_pdSolver); | |||
| } | |||
| btCollisionAlgorithmCreateFunc* btDefaultCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) | |||
| { | |||
| if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1==SPHERE_SHAPE_PROXYTYPE)) | |||
| { | |||
| return m_sphereSphereCF; | |||
| } | |||
| #ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
| if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1==BOX_SHAPE_PROXYTYPE)) | |||
| { | |||
| return m_sphereBoxCF; | |||
| } | |||
| if ((proxyType0 == BOX_SHAPE_PROXYTYPE ) && (proxyType1==SPHERE_SHAPE_PROXYTYPE)) | |||
| { | |||
| return m_boxSphereCF; | |||
| } | |||
| #endif //USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
| if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE ) && (proxyType1==TRIANGLE_SHAPE_PROXYTYPE)) | |||
| { | |||
| return m_sphereTriangleCF; | |||
| } | |||
| if ((proxyType0 == TRIANGLE_SHAPE_PROXYTYPE ) && (proxyType1==SPHERE_SHAPE_PROXYTYPE)) | |||
| { | |||
| return m_triangleSphereCF; | |||
| } | |||
| if ((proxyType0 == BOX_SHAPE_PROXYTYPE) && (proxyType1 == BOX_SHAPE_PROXYTYPE)) | |||
| { | |||
| return m_boxBoxCF; | |||
| } | |||
| if (btBroadphaseProxy::isConvex(proxyType0) && (proxyType1 == STATIC_PLANE_PROXYTYPE)) | |||
| { | |||
| return m_convexPlaneCF; | |||
| } | |||
| if (btBroadphaseProxy::isConvex(proxyType1) && (proxyType0 == STATIC_PLANE_PROXYTYPE)) | |||
| { | |||
| return m_planeConvexCF; | |||
| } | |||
| if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConvex(proxyType1)) | |||
| { | |||
| return m_convexConvexCreateFunc; | |||
| } | |||
| if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConcave(proxyType1)) | |||
| { | |||
| return m_convexConcaveCreateFunc; | |||
| } | |||
| if (btBroadphaseProxy::isConvex(proxyType1) && btBroadphaseProxy::isConcave(proxyType0)) | |||
| { | |||
| return m_swappedConvexConcaveCreateFunc; | |||
| } | |||
| if (btBroadphaseProxy::isCompound(proxyType0)) | |||
| { | |||
| return m_compoundCreateFunc; | |||
| } else | |||
| { | |||
| if (btBroadphaseProxy::isCompound(proxyType1)) | |||
| { | |||
| return m_swappedCompoundCreateFunc; | |||
| } | |||
| } | |||
| //failed to find an algorithm | |||
| return m_emptyCreateFunc; | |||
| } | |||
| void btDefaultCollisionConfiguration::setConvexConvexMultipointIterations(int numPerturbationIterations, int minimumPointsPerturbationThreshold) | |||
| { | |||
| btConvexConvexAlgorithm::CreateFunc* convexConvex = (btConvexConvexAlgorithm::CreateFunc*) m_convexConvexCreateFunc; | |||
| convexConvex->m_numPerturbationIterations = numPerturbationIterations; | |||
| convexConvex->m_minimumPointsPerturbationThreshold = minimumPointsPerturbationThreshold; | |||
| } | |||
| void btDefaultCollisionConfiguration::setPlaneConvexMultipointIterations(int numPerturbationIterations, int minimumPointsPerturbationThreshold) | |||
| { | |||
| btConvexPlaneCollisionAlgorithm::CreateFunc* cpCF = (btConvexPlaneCollisionAlgorithm::CreateFunc*)m_convexPlaneCF; | |||
| cpCF->m_numPerturbationIterations = numPerturbationIterations; | |||
| cpCF->m_minimumPointsPerturbationThreshold = minimumPointsPerturbationThreshold; | |||
| btConvexPlaneCollisionAlgorithm::CreateFunc* pcCF = (btConvexPlaneCollisionAlgorithm::CreateFunc*)m_planeConvexCF; | |||
| pcCF->m_numPerturbationIterations = numPerturbationIterations; | |||
| pcCF->m_minimumPointsPerturbationThreshold = minimumPointsPerturbationThreshold; | |||
| } | |||
| @@ -0,0 +1,137 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_DEFAULT_COLLISION_CONFIGURATION | |||
| #define BT_DEFAULT_COLLISION_CONFIGURATION | |||
| #include "btCollisionConfiguration.h" | |||
| class btVoronoiSimplexSolver; | |||
| class btConvexPenetrationDepthSolver; | |||
| struct btDefaultCollisionConstructionInfo | |||
| { | |||
| btStackAlloc* m_stackAlloc; | |||
| btPoolAllocator* m_persistentManifoldPool; | |||
| btPoolAllocator* m_collisionAlgorithmPool; | |||
| int m_defaultMaxPersistentManifoldPoolSize; | |||
| int m_defaultMaxCollisionAlgorithmPoolSize; | |||
| int m_customCollisionAlgorithmMaxElementSize; | |||
| int m_defaultStackAllocatorSize; | |||
| int m_useEpaPenetrationAlgorithm; | |||
| btDefaultCollisionConstructionInfo() | |||
| :m_stackAlloc(0), | |||
| m_persistentManifoldPool(0), | |||
| m_collisionAlgorithmPool(0), | |||
| m_defaultMaxPersistentManifoldPoolSize(4096), | |||
| m_defaultMaxCollisionAlgorithmPoolSize(4096), | |||
| m_customCollisionAlgorithmMaxElementSize(0), | |||
| m_defaultStackAllocatorSize(0), | |||
| m_useEpaPenetrationAlgorithm(true) | |||
| { | |||
| } | |||
| }; | |||
| ///btCollisionConfiguration allows to configure Bullet collision detection | |||
| ///stack allocator, pool memory allocators | |||
| ///@todo: describe the meaning | |||
| class btDefaultCollisionConfiguration : public btCollisionConfiguration | |||
| { | |||
| protected: | |||
| int m_persistentManifoldPoolSize; | |||
| btStackAlloc* m_stackAlloc; | |||
| bool m_ownsStackAllocator; | |||
| btPoolAllocator* m_persistentManifoldPool; | |||
| bool m_ownsPersistentManifoldPool; | |||
| btPoolAllocator* m_collisionAlgorithmPool; | |||
| bool m_ownsCollisionAlgorithmPool; | |||
| //default simplex/penetration depth solvers | |||
| btVoronoiSimplexSolver* m_simplexSolver; | |||
| btConvexPenetrationDepthSolver* m_pdSolver; | |||
| //default CreationFunctions, filling the m_doubleDispatch table | |||
| btCollisionAlgorithmCreateFunc* m_convexConvexCreateFunc; | |||
| btCollisionAlgorithmCreateFunc* m_convexConcaveCreateFunc; | |||
| btCollisionAlgorithmCreateFunc* m_swappedConvexConcaveCreateFunc; | |||
| btCollisionAlgorithmCreateFunc* m_compoundCreateFunc; | |||
| btCollisionAlgorithmCreateFunc* m_swappedCompoundCreateFunc; | |||
| btCollisionAlgorithmCreateFunc* m_emptyCreateFunc; | |||
| btCollisionAlgorithmCreateFunc* m_sphereSphereCF; | |||
| #ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
| btCollisionAlgorithmCreateFunc* m_sphereBoxCF; | |||
| btCollisionAlgorithmCreateFunc* m_boxSphereCF; | |||
| #endif //USE_BUGGY_SPHERE_BOX_ALGORITHM | |||
| btCollisionAlgorithmCreateFunc* m_boxBoxCF; | |||
| btCollisionAlgorithmCreateFunc* m_sphereTriangleCF; | |||
| btCollisionAlgorithmCreateFunc* m_triangleSphereCF; | |||
| btCollisionAlgorithmCreateFunc* m_planeConvexCF; | |||
| btCollisionAlgorithmCreateFunc* m_convexPlaneCF; | |||
| public: | |||
| btDefaultCollisionConfiguration(const btDefaultCollisionConstructionInfo& constructionInfo = btDefaultCollisionConstructionInfo()); | |||
| virtual ~btDefaultCollisionConfiguration(); | |||
| ///memory pools | |||
| virtual btPoolAllocator* getPersistentManifoldPool() | |||
| { | |||
| return m_persistentManifoldPool; | |||
| } | |||
| virtual btPoolAllocator* getCollisionAlgorithmPool() | |||
| { | |||
| return m_collisionAlgorithmPool; | |||
| } | |||
| virtual btStackAlloc* getStackAllocator() | |||
| { | |||
| return m_stackAlloc; | |||
| } | |||
| virtual btVoronoiSimplexSolver* getSimplexSolver() | |||
| { | |||
| return m_simplexSolver; | |||
| } | |||
| virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1); | |||
| ///Use this method to allow to generate multiple contact points between at once, between two objects using the generic convex-convex algorithm. | |||
| ///By default, this feature is disabled for best performance. | |||
| ///@param numPerturbationIterations controls the number of collision queries. Set it to zero to disable the feature. | |||
| ///@param minimumPointsPerturbationThreshold is the minimum number of points in the contact cache, above which the feature is disabled | |||
| ///3 is a good value for both params, if you want to enable the feature. This is because the default contact cache contains a maximum of 4 points, and one collision query at the unperturbed orientation is performed first. | |||
| ///See Bullet/Demos/CollisionDemo for an example how this feature gathers multiple points. | |||
| ///@todo we could add a per-object setting of those parameters, for level-of-detail collision detection. | |||
| void setConvexConvexMultipointIterations(int numPerturbationIterations=3, int minimumPointsPerturbationThreshold = 3); | |||
| void setPlaneConvexMultipointIterations(int numPerturbationIterations=3, int minimumPointsPerturbationThreshold = 3); | |||
| }; | |||
| #endif //BT_DEFAULT_COLLISION_CONFIGURATION | |||
| @@ -0,0 +1,34 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btEmptyCollisionAlgorithm.h" | |||
| btEmptyAlgorithm::btEmptyAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) | |||
| : btCollisionAlgorithm(ci) | |||
| { | |||
| } | |||
| void btEmptyAlgorithm::processCollision (btCollisionObject* ,btCollisionObject* ,const btDispatcherInfo& ,btManifoldResult* ) | |||
| { | |||
| } | |||
| btScalar btEmptyAlgorithm::calculateTimeOfImpact(btCollisionObject* ,btCollisionObject* ,const btDispatcherInfo& ,btManifoldResult* ) | |||
| { | |||
| return btScalar(1.); | |||
| } | |||
| @@ -0,0 +1,54 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_EMPTY_ALGORITH | |||
| #define BT_EMPTY_ALGORITH | |||
| #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" | |||
| #include "btCollisionCreateFunc.h" | |||
| #include "btCollisionDispatcher.h" | |||
| #define ATTRIBUTE_ALIGNED(a) | |||
| ///EmptyAlgorithm is a stub for unsupported collision pairs. | |||
| ///The dispatcher can dispatch a persistent btEmptyAlgorithm to avoid a search every frame. | |||
| class btEmptyAlgorithm : public btCollisionAlgorithm | |||
| { | |||
| public: | |||
| btEmptyAlgorithm(const btCollisionAlgorithmConstructionInfo& ci); | |||
| virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
| { | |||
| } | |||
| struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| (void)body0; | |||
| (void)body1; | |||
| void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btEmptyAlgorithm)); | |||
| return new(mem) btEmptyAlgorithm(ci); | |||
| } | |||
| }; | |||
| } ATTRIBUTE_ALIGNED(16); | |||
| #endif //BT_EMPTY_ALGORITH | |||
| @@ -0,0 +1,171 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btGhostObject.h" | |||
| #include "btCollisionWorld.h" | |||
| #include "BulletCollision/CollisionShapes/btConvexShape.h" | |||
| #include "LinearMath/btAabbUtil2.h" | |||
| btGhostObject::btGhostObject() | |||
| { | |||
| m_internalType = CO_GHOST_OBJECT; | |||
| } | |||
| btGhostObject::~btGhostObject() | |||
| { | |||
| ///btGhostObject should have been removed from the world, so no overlapping objects | |||
| btAssert(!m_overlappingObjects.size()); | |||
| } | |||
| void btGhostObject::addOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btBroadphaseProxy* thisProxy) | |||
| { | |||
| btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject; | |||
| btAssert(otherObject); | |||
| ///if this linearSearch becomes too slow (too many overlapping objects) we should add a more appropriate data structure | |||
| int index = m_overlappingObjects.findLinearSearch(otherObject); | |||
| if (index==m_overlappingObjects.size()) | |||
| { | |||
| //not found | |||
| m_overlappingObjects.push_back(otherObject); | |||
| } | |||
| } | |||
| void btGhostObject::removeOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher,btBroadphaseProxy* thisProxy) | |||
| { | |||
| btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject; | |||
| btAssert(otherObject); | |||
| int index = m_overlappingObjects.findLinearSearch(otherObject); | |||
| if (index<m_overlappingObjects.size()) | |||
| { | |||
| m_overlappingObjects[index] = m_overlappingObjects[m_overlappingObjects.size()-1]; | |||
| m_overlappingObjects.pop_back(); | |||
| } | |||
| } | |||
| btPairCachingGhostObject::btPairCachingGhostObject() | |||
| { | |||
| m_hashPairCache = new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache(); | |||
| } | |||
| btPairCachingGhostObject::~btPairCachingGhostObject() | |||
| { | |||
| m_hashPairCache->~btHashedOverlappingPairCache(); | |||
| btAlignedFree( m_hashPairCache ); | |||
| } | |||
| void btPairCachingGhostObject::addOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btBroadphaseProxy* thisProxy) | |||
| { | |||
| btBroadphaseProxy*actualThisProxy = thisProxy ? thisProxy : getBroadphaseHandle(); | |||
| btAssert(actualThisProxy); | |||
| btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject; | |||
| btAssert(otherObject); | |||
| int index = m_overlappingObjects.findLinearSearch(otherObject); | |||
| if (index==m_overlappingObjects.size()) | |||
| { | |||
| m_overlappingObjects.push_back(otherObject); | |||
| m_hashPairCache->addOverlappingPair(actualThisProxy,otherProxy); | |||
| } | |||
| } | |||
| void btPairCachingGhostObject::removeOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher,btBroadphaseProxy* thisProxy1) | |||
| { | |||
| btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject; | |||
| btBroadphaseProxy* actualThisProxy = thisProxy1 ? thisProxy1 : getBroadphaseHandle(); | |||
| btAssert(actualThisProxy); | |||
| btAssert(otherObject); | |||
| int index = m_overlappingObjects.findLinearSearch(otherObject); | |||
| if (index<m_overlappingObjects.size()) | |||
| { | |||
| m_overlappingObjects[index] = m_overlappingObjects[m_overlappingObjects.size()-1]; | |||
| m_overlappingObjects.pop_back(); | |||
| m_hashPairCache->removeOverlappingPair(actualThisProxy,otherProxy,dispatcher); | |||
| } | |||
| } | |||
| void btGhostObject::convexSweepTest(const btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, btCollisionWorld::ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration) const | |||
| { | |||
| btTransform convexFromTrans,convexToTrans; | |||
| convexFromTrans = convexFromWorld; | |||
| convexToTrans = convexToWorld; | |||
| btVector3 castShapeAabbMin, castShapeAabbMax; | |||
| /* Compute AABB that encompasses angular movement */ | |||
| { | |||
| btVector3 linVel, angVel; | |||
| btTransformUtil::calculateVelocity (convexFromTrans, convexToTrans, 1.0, linVel, angVel); | |||
| btTransform R; | |||
| R.setIdentity (); | |||
| R.setRotation (convexFromTrans.getRotation()); | |||
| castShape->calculateTemporalAabb (R, linVel, angVel, 1.0, castShapeAabbMin, castShapeAabbMax); | |||
| } | |||
| /// go over all objects, and if the ray intersects their aabb + cast shape aabb, | |||
| // do a ray-shape query using convexCaster (CCD) | |||
| int i; | |||
| for (i=0;i<m_overlappingObjects.size();i++) | |||
| { | |||
| btCollisionObject* collisionObject= m_overlappingObjects[i]; | |||
| //only perform raycast if filterMask matches | |||
| if(resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) { | |||
| //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); | |||
| btVector3 collisionObjectAabbMin,collisionObjectAabbMax; | |||
| collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax); | |||
| AabbExpand (collisionObjectAabbMin, collisionObjectAabbMax, castShapeAabbMin, castShapeAabbMax); | |||
| btScalar hitLambda = btScalar(1.); //could use resultCallback.m_closestHitFraction, but needs testing | |||
| btVector3 hitNormal; | |||
| if (btRayAabb(convexFromWorld.getOrigin(),convexToWorld.getOrigin(),collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,hitNormal)) | |||
| { | |||
| btCollisionWorld::objectQuerySingle(castShape, convexFromTrans,convexToTrans, | |||
| collisionObject, | |||
| collisionObject->getCollisionShape(), | |||
| collisionObject->getWorldTransform(), | |||
| resultCallback, | |||
| allowedCcdPenetration); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| void btGhostObject::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const | |||
| { | |||
| btTransform rayFromTrans; | |||
| rayFromTrans.setIdentity(); | |||
| rayFromTrans.setOrigin(rayFromWorld); | |||
| btTransform rayToTrans; | |||
| rayToTrans.setIdentity(); | |||
| rayToTrans.setOrigin(rayToWorld); | |||
| int i; | |||
| for (i=0;i<m_overlappingObjects.size();i++) | |||
| { | |||
| btCollisionObject* collisionObject= m_overlappingObjects[i]; | |||
| //only perform raycast if filterMask matches | |||
| if(resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) | |||
| { | |||
| btCollisionWorld::rayTestSingle(rayFromTrans,rayToTrans, | |||
| collisionObject, | |||
| collisionObject->getCollisionShape(), | |||
| collisionObject->getWorldTransform(), | |||
| resultCallback); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,175 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_GHOST_OBJECT_H | |||
| #define BT_GHOST_OBJECT_H | |||
| #include "btCollisionObject.h" | |||
| #include "BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h" | |||
| #include "LinearMath/btAlignedAllocator.h" | |||
| #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" | |||
| #include "btCollisionWorld.h" | |||
| class btConvexShape; | |||
| class btDispatcher; | |||
| ///The btGhostObject can keep track of all objects that are overlapping | |||
| ///By default, this overlap is based on the AABB | |||
| ///This is useful for creating a character controller, collision sensors/triggers, explosions etc. | |||
| ///We plan on adding rayTest and other queries for the btGhostObject | |||
| ATTRIBUTE_ALIGNED16(class) btGhostObject : public btCollisionObject | |||
| { | |||
| protected: | |||
| btAlignedObjectArray<btCollisionObject*> m_overlappingObjects; | |||
| public: | |||
| btGhostObject(); | |||
| virtual ~btGhostObject(); | |||
| void convexSweepTest(const class btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, btCollisionWorld::ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration = 0.f) const; | |||
| void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const; | |||
| ///this method is mainly for expert/internal use only. | |||
| virtual void addOverlappingObjectInternal(btBroadphaseProxy* otherProxy, btBroadphaseProxy* thisProxy=0); | |||
| ///this method is mainly for expert/internal use only. | |||
| virtual void removeOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher,btBroadphaseProxy* thisProxy=0); | |||
| int getNumOverlappingObjects() const | |||
| { | |||
| return m_overlappingObjects.size(); | |||
| } | |||
| btCollisionObject* getOverlappingObject(int index) | |||
| { | |||
| return m_overlappingObjects[index]; | |||
| } | |||
| const btCollisionObject* getOverlappingObject(int index) const | |||
| { | |||
| return m_overlappingObjects[index]; | |||
| } | |||
| btAlignedObjectArray<btCollisionObject*>& getOverlappingPairs() | |||
| { | |||
| return m_overlappingObjects; | |||
| } | |||
| const btAlignedObjectArray<btCollisionObject*> getOverlappingPairs() const | |||
| { | |||
| return m_overlappingObjects; | |||
| } | |||
| // | |||
| // internal cast | |||
| // | |||
| static const btGhostObject* upcast(const btCollisionObject* colObj) | |||
| { | |||
| if (colObj->getInternalType()==CO_GHOST_OBJECT) | |||
| return (const btGhostObject*)colObj; | |||
| return 0; | |||
| } | |||
| static btGhostObject* upcast(btCollisionObject* colObj) | |||
| { | |||
| if (colObj->getInternalType()==CO_GHOST_OBJECT) | |||
| return (btGhostObject*)colObj; | |||
| return 0; | |||
| } | |||
| }; | |||
| class btPairCachingGhostObject : public btGhostObject | |||
| { | |||
| btHashedOverlappingPairCache* m_hashPairCache; | |||
| public: | |||
| btPairCachingGhostObject(); | |||
| virtual ~btPairCachingGhostObject(); | |||
| ///this method is mainly for expert/internal use only. | |||
| virtual void addOverlappingObjectInternal(btBroadphaseProxy* otherProxy, btBroadphaseProxy* thisProxy=0); | |||
| virtual void removeOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher,btBroadphaseProxy* thisProxy=0); | |||
| btHashedOverlappingPairCache* getOverlappingPairCache() | |||
| { | |||
| return m_hashPairCache; | |||
| } | |||
| }; | |||
| ///The btGhostPairCallback interfaces and forwards adding and removal of overlapping pairs from the btBroadphaseInterface to btGhostObject. | |||
| class btGhostPairCallback : public btOverlappingPairCallback | |||
| { | |||
| public: | |||
| btGhostPairCallback() | |||
| { | |||
| } | |||
| virtual ~btGhostPairCallback() | |||
| { | |||
| } | |||
| virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) | |||
| { | |||
| btCollisionObject* colObj0 = (btCollisionObject*) proxy0->m_clientObject; | |||
| btCollisionObject* colObj1 = (btCollisionObject*) proxy1->m_clientObject; | |||
| btGhostObject* ghost0 = btGhostObject::upcast(colObj0); | |||
| btGhostObject* ghost1 = btGhostObject::upcast(colObj1); | |||
| if (ghost0) | |||
| ghost0->addOverlappingObjectInternal(proxy1, proxy0); | |||
| if (ghost1) | |||
| ghost1->addOverlappingObjectInternal(proxy0, proxy1); | |||
| return 0; | |||
| } | |||
| virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher) | |||
| { | |||
| btCollisionObject* colObj0 = (btCollisionObject*) proxy0->m_clientObject; | |||
| btCollisionObject* colObj1 = (btCollisionObject*) proxy1->m_clientObject; | |||
| btGhostObject* ghost0 = btGhostObject::upcast(colObj0); | |||
| btGhostObject* ghost1 = btGhostObject::upcast(colObj1); | |||
| if (ghost0) | |||
| ghost0->removeOverlappingObjectInternal(proxy1,dispatcher,proxy0); | |||
| if (ghost1) | |||
| ghost1->removeOverlappingObjectInternal(proxy0,dispatcher,proxy1); | |||
| return 0; | |||
| } | |||
| virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* /*proxy0*/,btDispatcher* /*dispatcher*/) | |||
| { | |||
| btAssert(0); | |||
| //need to keep track of all ghost objects and call them here | |||
| //m_hashPairCache->removeOverlappingPairsContainingProxy(proxy0,dispatcher); | |||
| } | |||
| }; | |||
| #endif | |||
| @@ -0,0 +1,842 @@ | |||
| #include "btInternalEdgeUtility.h" | |||
| #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" | |||
| #include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" | |||
| #include "BulletCollision/CollisionShapes/btTriangleShape.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h" | |||
| #include "LinearMath/btIDebugDraw.h" | |||
| //#define DEBUG_INTERNAL_EDGE | |||
| #ifdef DEBUG_INTERNAL_EDGE | |||
| #include <stdio.h> | |||
| #endif //DEBUG_INTERNAL_EDGE | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| static btIDebugDraw* gDebugDrawer = 0; | |||
| void btSetDebugDrawer(btIDebugDraw* debugDrawer) | |||
| { | |||
| gDebugDrawer = debugDrawer; | |||
| } | |||
| static void btDebugDrawLine(const btVector3& from,const btVector3& to, const btVector3& color) | |||
| { | |||
| if (gDebugDrawer) | |||
| gDebugDrawer->drawLine(from,to,color); | |||
| } | |||
| #endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| static int btGetHash(int partId, int triangleIndex) | |||
| { | |||
| int hash = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | triangleIndex; | |||
| return hash; | |||
| } | |||
| static btScalar btGetAngle(const btVector3& edgeA, const btVector3& normalA,const btVector3& normalB) | |||
| { | |||
| const btVector3 refAxis0 = edgeA; | |||
| const btVector3 refAxis1 = normalA; | |||
| const btVector3 swingAxis = normalB; | |||
| btScalar angle = btAtan2(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1)); | |||
| return angle; | |||
| } | |||
| struct btConnectivityProcessor : public btTriangleCallback | |||
| { | |||
| int m_partIdA; | |||
| int m_triangleIndexA; | |||
| btVector3* m_triangleVerticesA; | |||
| btTriangleInfoMap* m_triangleInfoMap; | |||
| virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) | |||
| { | |||
| //skip self-collisions | |||
| if ((m_partIdA == partId) && (m_triangleIndexA == triangleIndex)) | |||
| return; | |||
| //skip duplicates (disabled for now) | |||
| //if ((m_partIdA <= partId) && (m_triangleIndexA <= triangleIndex)) | |||
| // return; | |||
| //search for shared vertices and edges | |||
| int numshared = 0; | |||
| int sharedVertsA[3]={-1,-1,-1}; | |||
| int sharedVertsB[3]={-1,-1,-1}; | |||
| ///skip degenerate triangles | |||
| btScalar crossBSqr = ((triangle[1]-triangle[0]).cross(triangle[2]-triangle[0])).length2(); | |||
| if (crossBSqr < m_triangleInfoMap->m_equalVertexThreshold) | |||
| return; | |||
| btScalar crossASqr = ((m_triangleVerticesA[1]-m_triangleVerticesA[0]).cross(m_triangleVerticesA[2]-m_triangleVerticesA[0])).length2(); | |||
| ///skip degenerate triangles | |||
| if (crossASqr< m_triangleInfoMap->m_equalVertexThreshold) | |||
| return; | |||
| #if 0 | |||
| printf("triangle A[0] = (%f,%f,%f)\ntriangle A[1] = (%f,%f,%f)\ntriangle A[2] = (%f,%f,%f)\n", | |||
| m_triangleVerticesA[0].getX(),m_triangleVerticesA[0].getY(),m_triangleVerticesA[0].getZ(), | |||
| m_triangleVerticesA[1].getX(),m_triangleVerticesA[1].getY(),m_triangleVerticesA[1].getZ(), | |||
| m_triangleVerticesA[2].getX(),m_triangleVerticesA[2].getY(),m_triangleVerticesA[2].getZ()); | |||
| printf("partId=%d, triangleIndex=%d\n",partId,triangleIndex); | |||
| printf("triangle B[0] = (%f,%f,%f)\ntriangle B[1] = (%f,%f,%f)\ntriangle B[2] = (%f,%f,%f)\n", | |||
| triangle[0].getX(),triangle[0].getY(),triangle[0].getZ(), | |||
| triangle[1].getX(),triangle[1].getY(),triangle[1].getZ(), | |||
| triangle[2].getX(),triangle[2].getY(),triangle[2].getZ()); | |||
| #endif | |||
| for (int i=0;i<3;i++) | |||
| { | |||
| for (int j=0;j<3;j++) | |||
| { | |||
| if ( (m_triangleVerticesA[i]-triangle[j]).length2() < m_triangleInfoMap->m_equalVertexThreshold) | |||
| { | |||
| sharedVertsA[numshared] = i; | |||
| sharedVertsB[numshared] = j; | |||
| numshared++; | |||
| ///degenerate case | |||
| if(numshared >= 3) | |||
| return; | |||
| } | |||
| } | |||
| ///degenerate case | |||
| if(numshared >= 3) | |||
| return; | |||
| } | |||
| switch (numshared) | |||
| { | |||
| case 0: | |||
| { | |||
| break; | |||
| } | |||
| case 1: | |||
| { | |||
| //shared vertex | |||
| break; | |||
| } | |||
| case 2: | |||
| { | |||
| //shared edge | |||
| //we need to make sure the edge is in the order V2V0 and not V0V2 so that the signs are correct | |||
| if (sharedVertsA[0] == 0 && sharedVertsA[1] == 2) | |||
| { | |||
| sharedVertsA[0] = 2; | |||
| sharedVertsA[1] = 0; | |||
| int tmp = sharedVertsB[1]; | |||
| sharedVertsB[1] = sharedVertsB[0]; | |||
| sharedVertsB[0] = tmp; | |||
| } | |||
| int hash = btGetHash(m_partIdA,m_triangleIndexA); | |||
| btTriangleInfo* info = m_triangleInfoMap->find(hash); | |||
| if (!info) | |||
| { | |||
| btTriangleInfo tmp; | |||
| m_triangleInfoMap->insert(hash,tmp); | |||
| info = m_triangleInfoMap->find(hash); | |||
| } | |||
| int sumvertsA = sharedVertsA[0]+sharedVertsA[1]; | |||
| int otherIndexA = 3-sumvertsA; | |||
| btVector3 edge(m_triangleVerticesA[sharedVertsA[1]]-m_triangleVerticesA[sharedVertsA[0]]); | |||
| btTriangleShape tA(m_triangleVerticesA[0],m_triangleVerticesA[1],m_triangleVerticesA[2]); | |||
| int otherIndexB = 3-(sharedVertsB[0]+sharedVertsB[1]); | |||
| btTriangleShape tB(triangle[sharedVertsB[1]],triangle[sharedVertsB[0]],triangle[otherIndexB]); | |||
| //btTriangleShape tB(triangle[0],triangle[1],triangle[2]); | |||
| btVector3 normalA; | |||
| btVector3 normalB; | |||
| tA.calcNormal(normalA); | |||
| tB.calcNormal(normalB); | |||
| edge.normalize(); | |||
| btVector3 edgeCrossA = edge.cross(normalA).normalize(); | |||
| { | |||
| btVector3 tmp = m_triangleVerticesA[otherIndexA]-m_triangleVerticesA[sharedVertsA[0]]; | |||
| if (edgeCrossA.dot(tmp) < 0) | |||
| { | |||
| edgeCrossA*=-1; | |||
| } | |||
| } | |||
| btVector3 edgeCrossB = edge.cross(normalB).normalize(); | |||
| { | |||
| btVector3 tmp = triangle[otherIndexB]-triangle[sharedVertsB[0]]; | |||
| if (edgeCrossB.dot(tmp) < 0) | |||
| { | |||
| edgeCrossB*=-1; | |||
| } | |||
| } | |||
| btScalar angle2 = 0; | |||
| btScalar ang4 = 0.f; | |||
| btVector3 calculatedEdge = edgeCrossA.cross(edgeCrossB); | |||
| btScalar len2 = calculatedEdge.length2(); | |||
| btScalar correctedAngle(0); | |||
| btVector3 calculatedNormalB = normalA; | |||
| bool isConvex = false; | |||
| if (len2<m_triangleInfoMap->m_planarEpsilon) | |||
| { | |||
| angle2 = 0.f; | |||
| ang4 = 0.f; | |||
| } else | |||
| { | |||
| calculatedEdge.normalize(); | |||
| btVector3 calculatedNormalA = calculatedEdge.cross(edgeCrossA); | |||
| calculatedNormalA.normalize(); | |||
| angle2 = btGetAngle(calculatedNormalA,edgeCrossA,edgeCrossB); | |||
| ang4 = SIMD_PI-angle2; | |||
| btScalar dotA = normalA.dot(edgeCrossB); | |||
| ///@todo: check if we need some epsilon, due to floating point imprecision | |||
| isConvex = (dotA<0.); | |||
| correctedAngle = isConvex ? ang4 : -ang4; | |||
| btQuaternion orn2(calculatedEdge,-correctedAngle); | |||
| calculatedNormalB = btMatrix3x3(orn2)*normalA; | |||
| } | |||
| //alternatively use | |||
| //btVector3 calculatedNormalB2 = quatRotate(orn,normalA); | |||
| switch (sumvertsA) | |||
| { | |||
| case 1: | |||
| { | |||
| btVector3 edge = m_triangleVerticesA[0]-m_triangleVerticesA[1]; | |||
| btQuaternion orn(edge,-correctedAngle); | |||
| btVector3 computedNormalB = quatRotate(orn,normalA); | |||
| btScalar bla = computedNormalB.dot(normalB); | |||
| if (bla<0) | |||
| { | |||
| computedNormalB*=-1; | |||
| info->m_flags |= TRI_INFO_V0V1_SWAP_NORMALB; | |||
| } | |||
| #ifdef DEBUG_INTERNAL_EDGE | |||
| if ((computedNormalB-normalB).length()>0.0001) | |||
| { | |||
| printf("warning: normals not identical\n"); | |||
| } | |||
| #endif//DEBUG_INTERNAL_EDGE | |||
| info->m_edgeV0V1Angle = -correctedAngle; | |||
| if (isConvex) | |||
| info->m_flags |= TRI_INFO_V0V1_CONVEX; | |||
| break; | |||
| } | |||
| case 2: | |||
| { | |||
| btVector3 edge = m_triangleVerticesA[2]-m_triangleVerticesA[0]; | |||
| btQuaternion orn(edge,-correctedAngle); | |||
| btVector3 computedNormalB = quatRotate(orn,normalA); | |||
| if (computedNormalB.dot(normalB)<0) | |||
| { | |||
| computedNormalB*=-1; | |||
| info->m_flags |= TRI_INFO_V2V0_SWAP_NORMALB; | |||
| } | |||
| #ifdef DEBUG_INTERNAL_EDGE | |||
| if ((computedNormalB-normalB).length()>0.0001) | |||
| { | |||
| printf("warning: normals not identical\n"); | |||
| } | |||
| #endif //DEBUG_INTERNAL_EDGE | |||
| info->m_edgeV2V0Angle = -correctedAngle; | |||
| if (isConvex) | |||
| info->m_flags |= TRI_INFO_V2V0_CONVEX; | |||
| break; | |||
| } | |||
| case 3: | |||
| { | |||
| btVector3 edge = m_triangleVerticesA[1]-m_triangleVerticesA[2]; | |||
| btQuaternion orn(edge,-correctedAngle); | |||
| btVector3 computedNormalB = quatRotate(orn,normalA); | |||
| if (computedNormalB.dot(normalB)<0) | |||
| { | |||
| info->m_flags |= TRI_INFO_V1V2_SWAP_NORMALB; | |||
| computedNormalB*=-1; | |||
| } | |||
| #ifdef DEBUG_INTERNAL_EDGE | |||
| if ((computedNormalB-normalB).length()>0.0001) | |||
| { | |||
| printf("warning: normals not identical\n"); | |||
| } | |||
| #endif //DEBUG_INTERNAL_EDGE | |||
| info->m_edgeV1V2Angle = -correctedAngle; | |||
| if (isConvex) | |||
| info->m_flags |= TRI_INFO_V1V2_CONVEX; | |||
| break; | |||
| } | |||
| } | |||
| break; | |||
| } | |||
| default: | |||
| { | |||
| // printf("warning: duplicate triangle\n"); | |||
| } | |||
| } | |||
| } | |||
| }; | |||
| ///////////////////////////////////////////////////////// | |||
| ///////////////////////////////////////////////////////// | |||
| void btGenerateInternalEdgeInfo (btBvhTriangleMeshShape*trimeshShape, btTriangleInfoMap* triangleInfoMap) | |||
| { | |||
| //the user pointer shouldn't already be used for other purposes, we intend to store connectivity info there! | |||
| if (trimeshShape->getTriangleInfoMap()) | |||
| return; | |||
| trimeshShape->setTriangleInfoMap(triangleInfoMap); | |||
| btStridingMeshInterface* meshInterface = trimeshShape->getMeshInterface(); | |||
| const btVector3& meshScaling = meshInterface->getScaling(); | |||
| for (int partId = 0; partId< meshInterface->getNumSubParts();partId++) | |||
| { | |||
| const unsigned char *vertexbase = 0; | |||
| int numverts = 0; | |||
| PHY_ScalarType type = PHY_INTEGER; | |||
| int stride = 0; | |||
| const unsigned char *indexbase = 0; | |||
| int indexstride = 0; | |||
| int numfaces = 0; | |||
| PHY_ScalarType indicestype = PHY_INTEGER; | |||
| //PHY_ScalarType indexType=0; | |||
| btVector3 triangleVerts[3]; | |||
| meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase,numverts, type,stride,&indexbase,indexstride,numfaces,indicestype,partId); | |||
| btVector3 aabbMin,aabbMax; | |||
| for (int triangleIndex = 0 ; triangleIndex < numfaces;triangleIndex++) | |||
| { | |||
| unsigned int* gfxbase = (unsigned int*)(indexbase+triangleIndex*indexstride); | |||
| for (int j=2;j>=0;j--) | |||
| { | |||
| int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; | |||
| if (type == PHY_FLOAT) | |||
| { | |||
| float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); | |||
| triangleVerts[j] = btVector3( | |||
| graphicsbase[0]*meshScaling.getX(), | |||
| graphicsbase[1]*meshScaling.getY(), | |||
| graphicsbase[2]*meshScaling.getZ()); | |||
| } | |||
| else | |||
| { | |||
| double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); | |||
| triangleVerts[j] = btVector3( btScalar(graphicsbase[0]*meshScaling.getX()), btScalar(graphicsbase[1]*meshScaling.getY()), btScalar(graphicsbase[2]*meshScaling.getZ())); | |||
| } | |||
| } | |||
| aabbMin.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); | |||
| aabbMax.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); | |||
| aabbMin.setMin(triangleVerts[0]); | |||
| aabbMax.setMax(triangleVerts[0]); | |||
| aabbMin.setMin(triangleVerts[1]); | |||
| aabbMax.setMax(triangleVerts[1]); | |||
| aabbMin.setMin(triangleVerts[2]); | |||
| aabbMax.setMax(triangleVerts[2]); | |||
| btConnectivityProcessor connectivityProcessor; | |||
| connectivityProcessor.m_partIdA = partId; | |||
| connectivityProcessor.m_triangleIndexA = triangleIndex; | |||
| connectivityProcessor.m_triangleVerticesA = &triangleVerts[0]; | |||
| connectivityProcessor.m_triangleInfoMap = triangleInfoMap; | |||
| trimeshShape->processAllTriangles(&connectivityProcessor,aabbMin,aabbMax); | |||
| } | |||
| } | |||
| } | |||
| // Given a point and a line segment (defined by two points), compute the closest point | |||
| // in the line. Cap the point at the endpoints of the line segment. | |||
| void btNearestPointInLineSegment(const btVector3 &point, const btVector3& line0, const btVector3& line1, btVector3& nearestPoint) | |||
| { | |||
| btVector3 lineDelta = line1 - line0; | |||
| // Handle degenerate lines | |||
| if ( lineDelta.fuzzyZero()) | |||
| { | |||
| nearestPoint = line0; | |||
| } | |||
| else | |||
| { | |||
| btScalar delta = (point-line0).dot(lineDelta) / (lineDelta).dot(lineDelta); | |||
| // Clamp the point to conform to the segment's endpoints | |||
| if ( delta < 0 ) | |||
| delta = 0; | |||
| else if ( delta > 1 ) | |||
| delta = 1; | |||
| nearestPoint = line0 + lineDelta*delta; | |||
| } | |||
| } | |||
| bool btClampNormal(const btVector3& edge,const btVector3& tri_normal_org,const btVector3& localContactNormalOnB, btScalar correctedEdgeAngle, btVector3 & clampedLocalNormal) | |||
| { | |||
| btVector3 tri_normal = tri_normal_org; | |||
| //we only have a local triangle normal, not a local contact normal -> only normal in world space... | |||
| //either compute the current angle all in local space, or all in world space | |||
| btVector3 edgeCross = edge.cross(tri_normal).normalize(); | |||
| btScalar curAngle = btGetAngle(edgeCross,tri_normal,localContactNormalOnB); | |||
| if (correctedEdgeAngle<0) | |||
| { | |||
| if (curAngle < correctedEdgeAngle) | |||
| { | |||
| btScalar diffAngle = correctedEdgeAngle-curAngle; | |||
| btQuaternion rotation(edge,diffAngle ); | |||
| clampedLocalNormal = btMatrix3x3(rotation)*localContactNormalOnB; | |||
| return true; | |||
| } | |||
| } | |||
| if (correctedEdgeAngle>=0) | |||
| { | |||
| if (curAngle > correctedEdgeAngle) | |||
| { | |||
| btScalar diffAngle = correctedEdgeAngle-curAngle; | |||
| btQuaternion rotation(edge,diffAngle ); | |||
| clampedLocalNormal = btMatrix3x3(rotation)*localContactNormalOnB; | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| /// Changes a btManifoldPoint collision normal to the normal from the mesh. | |||
| void btAdjustInternalEdgeContacts(btManifoldPoint& cp, const btCollisionObject* colObj0,const btCollisionObject* colObj1, int partId0, int index0, int normalAdjustFlags) | |||
| { | |||
| //btAssert(colObj0->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE); | |||
| if (colObj0->getCollisionShape()->getShapeType() != TRIANGLE_SHAPE_PROXYTYPE) | |||
| return; | |||
| btBvhTriangleMeshShape* trimesh = 0; | |||
| if( colObj0->getRootCollisionShape()->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE ) | |||
| trimesh = ((btScaledBvhTriangleMeshShape*)colObj0->getRootCollisionShape())->getChildShape(); | |||
| else | |||
| trimesh = (btBvhTriangleMeshShape*)colObj0->getRootCollisionShape(); | |||
| btTriangleInfoMap* triangleInfoMapPtr = (btTriangleInfoMap*) trimesh->getTriangleInfoMap(); | |||
| if (!triangleInfoMapPtr) | |||
| return; | |||
| int hash = btGetHash(partId0,index0); | |||
| btTriangleInfo* info = triangleInfoMapPtr->find(hash); | |||
| if (!info) | |||
| return; | |||
| btScalar frontFacing = (normalAdjustFlags & BT_TRIANGLE_CONVEX_BACKFACE_MODE)==0? 1.f : -1.f; | |||
| const btTriangleShape* tri_shape = static_cast<const btTriangleShape*>(colObj0->getCollisionShape()); | |||
| btVector3 v0,v1,v2; | |||
| tri_shape->getVertex(0,v0); | |||
| tri_shape->getVertex(1,v1); | |||
| tri_shape->getVertex(2,v2); | |||
| btVector3 center = (v0+v1+v2)*btScalar(1./3.); | |||
| btVector3 red(1,0,0), green(0,1,0),blue(0,0,1),white(1,1,1),black(0,0,0); | |||
| btVector3 tri_normal; | |||
| tri_shape->calcNormal(tri_normal); | |||
| //btScalar dot = tri_normal.dot(cp.m_normalWorldOnB); | |||
| btVector3 nearest; | |||
| btNearestPointInLineSegment(cp.m_localPointB,v0,v1,nearest); | |||
| btVector3 contact = cp.m_localPointB; | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| const btTransform& tr = colObj0->getWorldTransform(); | |||
| btDebugDrawLine(tr*nearest,tr*cp.m_localPointB,red); | |||
| #endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| bool isNearEdge = false; | |||
| int numConcaveEdgeHits = 0; | |||
| int numConvexEdgeHits = 0; | |||
| btVector3 localContactNormalOnB = colObj0->getWorldTransform().getBasis().transpose() * cp.m_normalWorldOnB; | |||
| localContactNormalOnB.normalize();//is this necessary? | |||
| // Get closest edge | |||
| int bestedge=-1; | |||
| btScalar disttobestedge=BT_LARGE_FLOAT; | |||
| // | |||
| // Edge 0 -> 1 | |||
| if (btFabs(info->m_edgeV0V1Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) | |||
| { | |||
| btVector3 nearest; | |||
| btNearestPointInLineSegment( cp.m_localPointB, v0, v1, nearest ); | |||
| btScalar len=(contact-nearest).length(); | |||
| // | |||
| if( len < disttobestedge ) | |||
| { | |||
| bestedge=0; | |||
| disttobestedge=len; | |||
| } | |||
| } | |||
| // Edge 1 -> 2 | |||
| if (btFabs(info->m_edgeV1V2Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) | |||
| { | |||
| btVector3 nearest; | |||
| btNearestPointInLineSegment( cp.m_localPointB, v1, v2, nearest ); | |||
| btScalar len=(contact-nearest).length(); | |||
| // | |||
| if( len < disttobestedge ) | |||
| { | |||
| bestedge=1; | |||
| disttobestedge=len; | |||
| } | |||
| } | |||
| // Edge 2 -> 0 | |||
| if (btFabs(info->m_edgeV2V0Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) | |||
| { | |||
| btVector3 nearest; | |||
| btNearestPointInLineSegment( cp.m_localPointB, v2, v0, nearest ); | |||
| btScalar len=(contact-nearest).length(); | |||
| // | |||
| if( len < disttobestedge ) | |||
| { | |||
| bestedge=2; | |||
| disttobestedge=len; | |||
| } | |||
| } | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btVector3 upfix=tri_normal * btVector3(0.1f,0.1f,0.1f); | |||
| btDebugDrawLine(tr * v0 + upfix, tr * v1 + upfix, red ); | |||
| #endif | |||
| if (btFabs(info->m_edgeV0V1Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) | |||
| { | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btDebugDrawLine(tr*contact,tr*(contact+cp.m_normalWorldOnB*10),black); | |||
| #endif | |||
| btScalar len = (contact-nearest).length(); | |||
| if(len<triangleInfoMapPtr->m_edgeDistanceThreshold) | |||
| if( bestedge==0 ) | |||
| { | |||
| btVector3 edge(v0-v1); | |||
| isNearEdge = true; | |||
| if (info->m_edgeV0V1Angle==btScalar(0)) | |||
| { | |||
| numConcaveEdgeHits++; | |||
| } else | |||
| { | |||
| bool isEdgeConvex = (info->m_flags & TRI_INFO_V0V1_CONVEX); | |||
| btScalar swapFactor = isEdgeConvex ? btScalar(1) : btScalar(-1); | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btDebugDrawLine(tr*nearest,tr*(nearest+swapFactor*tri_normal*10),white); | |||
| #endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btVector3 nA = swapFactor * tri_normal; | |||
| btQuaternion orn(edge,info->m_edgeV0V1Angle); | |||
| btVector3 computedNormalB = quatRotate(orn,tri_normal); | |||
| if (info->m_flags & TRI_INFO_V0V1_SWAP_NORMALB) | |||
| computedNormalB*=-1; | |||
| btVector3 nB = swapFactor*computedNormalB; | |||
| btScalar NdotA = localContactNormalOnB.dot(nA); | |||
| btScalar NdotB = localContactNormalOnB.dot(nB); | |||
| bool backFacingNormal = (NdotA< triangleInfoMapPtr->m_convexEpsilon) && (NdotB<triangleInfoMapPtr->m_convexEpsilon); | |||
| #ifdef DEBUG_INTERNAL_EDGE | |||
| { | |||
| btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+tr.getBasis()*(nB*20),red); | |||
| } | |||
| #endif //DEBUG_INTERNAL_EDGE | |||
| if (backFacingNormal) | |||
| { | |||
| numConcaveEdgeHits++; | |||
| } | |||
| else | |||
| { | |||
| numConvexEdgeHits++; | |||
| btVector3 clampedLocalNormal; | |||
| bool isClamped = btClampNormal(edge,swapFactor*tri_normal,localContactNormalOnB, info->m_edgeV0V1Angle,clampedLocalNormal); | |||
| if (isClamped) | |||
| { | |||
| if (((normalAdjustFlags & BT_TRIANGLE_CONVEX_DOUBLE_SIDED)!=0) || (clampedLocalNormal.dot(frontFacing*tri_normal)>0)) | |||
| { | |||
| btVector3 newNormal = colObj0->getWorldTransform().getBasis() * clampedLocalNormal; | |||
| // cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB); | |||
| cp.m_normalWorldOnB = newNormal; | |||
| // Reproject collision point along normal. (what about cp.m_distance1?) | |||
| cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; | |||
| cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| btNearestPointInLineSegment(contact,v1,v2,nearest); | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btDebugDrawLine(tr*nearest,tr*cp.m_localPointB,green); | |||
| #endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btDebugDrawLine(tr * v1 + upfix, tr * v2 + upfix , green ); | |||
| #endif | |||
| if (btFabs(info->m_edgeV1V2Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) | |||
| { | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btDebugDrawLine(tr*contact,tr*(contact+cp.m_normalWorldOnB*10),black); | |||
| #endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btScalar len = (contact-nearest).length(); | |||
| if(len<triangleInfoMapPtr->m_edgeDistanceThreshold) | |||
| if( bestedge==1 ) | |||
| { | |||
| isNearEdge = true; | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btDebugDrawLine(tr*nearest,tr*(nearest+tri_normal*10),white); | |||
| #endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btVector3 edge(v1-v2); | |||
| isNearEdge = true; | |||
| if (info->m_edgeV1V2Angle == btScalar(0)) | |||
| { | |||
| numConcaveEdgeHits++; | |||
| } else | |||
| { | |||
| bool isEdgeConvex = (info->m_flags & TRI_INFO_V1V2_CONVEX)!=0; | |||
| btScalar swapFactor = isEdgeConvex ? btScalar(1) : btScalar(-1); | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btDebugDrawLine(tr*nearest,tr*(nearest+swapFactor*tri_normal*10),white); | |||
| #endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btVector3 nA = swapFactor * tri_normal; | |||
| btQuaternion orn(edge,info->m_edgeV1V2Angle); | |||
| btVector3 computedNormalB = quatRotate(orn,tri_normal); | |||
| if (info->m_flags & TRI_INFO_V1V2_SWAP_NORMALB) | |||
| computedNormalB*=-1; | |||
| btVector3 nB = swapFactor*computedNormalB; | |||
| #ifdef DEBUG_INTERNAL_EDGE | |||
| { | |||
| btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+tr.getBasis()*(nB*20),red); | |||
| } | |||
| #endif //DEBUG_INTERNAL_EDGE | |||
| btScalar NdotA = localContactNormalOnB.dot(nA); | |||
| btScalar NdotB = localContactNormalOnB.dot(nB); | |||
| bool backFacingNormal = (NdotA< triangleInfoMapPtr->m_convexEpsilon) && (NdotB<triangleInfoMapPtr->m_convexEpsilon); | |||
| if (backFacingNormal) | |||
| { | |||
| numConcaveEdgeHits++; | |||
| } | |||
| else | |||
| { | |||
| numConvexEdgeHits++; | |||
| btVector3 localContactNormalOnB = colObj0->getWorldTransform().getBasis().transpose() * cp.m_normalWorldOnB; | |||
| btVector3 clampedLocalNormal; | |||
| bool isClamped = btClampNormal(edge,swapFactor*tri_normal,localContactNormalOnB, info->m_edgeV1V2Angle,clampedLocalNormal); | |||
| if (isClamped) | |||
| { | |||
| if (((normalAdjustFlags & BT_TRIANGLE_CONVEX_DOUBLE_SIDED)!=0) || (clampedLocalNormal.dot(frontFacing*tri_normal)>0)) | |||
| { | |||
| btVector3 newNormal = colObj0->getWorldTransform().getBasis() * clampedLocalNormal; | |||
| // cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB); | |||
| cp.m_normalWorldOnB = newNormal; | |||
| // Reproject collision point along normal. | |||
| cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; | |||
| cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| btNearestPointInLineSegment(contact,v2,v0,nearest); | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btDebugDrawLine(tr*nearest,tr*cp.m_localPointB,blue); | |||
| #endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btDebugDrawLine(tr * v2 + upfix, tr * v0 + upfix , blue ); | |||
| #endif | |||
| if (btFabs(info->m_edgeV2V0Angle)< triangleInfoMapPtr->m_maxEdgeAngleThreshold) | |||
| { | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btDebugDrawLine(tr*contact,tr*(contact+cp.m_normalWorldOnB*10),black); | |||
| #endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btScalar len = (contact-nearest).length(); | |||
| if(len<triangleInfoMapPtr->m_edgeDistanceThreshold) | |||
| if( bestedge==2 ) | |||
| { | |||
| isNearEdge = true; | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btDebugDrawLine(tr*nearest,tr*(nearest+tri_normal*10),white); | |||
| #endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btVector3 edge(v2-v0); | |||
| if (info->m_edgeV2V0Angle==btScalar(0)) | |||
| { | |||
| numConcaveEdgeHits++; | |||
| } else | |||
| { | |||
| bool isEdgeConvex = (info->m_flags & TRI_INFO_V2V0_CONVEX)!=0; | |||
| btScalar swapFactor = isEdgeConvex ? btScalar(1) : btScalar(-1); | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btDebugDrawLine(tr*nearest,tr*(nearest+swapFactor*tri_normal*10),white); | |||
| #endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| btVector3 nA = swapFactor * tri_normal; | |||
| btQuaternion orn(edge,info->m_edgeV2V0Angle); | |||
| btVector3 computedNormalB = quatRotate(orn,tri_normal); | |||
| if (info->m_flags & TRI_INFO_V2V0_SWAP_NORMALB) | |||
| computedNormalB*=-1; | |||
| btVector3 nB = swapFactor*computedNormalB; | |||
| #ifdef DEBUG_INTERNAL_EDGE | |||
| { | |||
| btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+tr.getBasis()*(nB*20),red); | |||
| } | |||
| #endif //DEBUG_INTERNAL_EDGE | |||
| btScalar NdotA = localContactNormalOnB.dot(nA); | |||
| btScalar NdotB = localContactNormalOnB.dot(nB); | |||
| bool backFacingNormal = (NdotA< triangleInfoMapPtr->m_convexEpsilon) && (NdotB<triangleInfoMapPtr->m_convexEpsilon); | |||
| if (backFacingNormal) | |||
| { | |||
| numConcaveEdgeHits++; | |||
| } | |||
| else | |||
| { | |||
| numConvexEdgeHits++; | |||
| // printf("hitting convex edge\n"); | |||
| btVector3 localContactNormalOnB = colObj0->getWorldTransform().getBasis().transpose() * cp.m_normalWorldOnB; | |||
| btVector3 clampedLocalNormal; | |||
| bool isClamped = btClampNormal(edge,swapFactor*tri_normal,localContactNormalOnB,info->m_edgeV2V0Angle,clampedLocalNormal); | |||
| if (isClamped) | |||
| { | |||
| if (((normalAdjustFlags & BT_TRIANGLE_CONVEX_DOUBLE_SIDED)!=0) || (clampedLocalNormal.dot(frontFacing*tri_normal)>0)) | |||
| { | |||
| btVector3 newNormal = colObj0->getWorldTransform().getBasis() * clampedLocalNormal; | |||
| // cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB); | |||
| cp.m_normalWorldOnB = newNormal; | |||
| // Reproject collision point along normal. | |||
| cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; | |||
| cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| #ifdef DEBUG_INTERNAL_EDGE | |||
| { | |||
| btVector3 color(0,1,1); | |||
| btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+cp.m_normalWorldOnB*10,color); | |||
| } | |||
| #endif //DEBUG_INTERNAL_EDGE | |||
| if (isNearEdge) | |||
| { | |||
| if (numConcaveEdgeHits>0) | |||
| { | |||
| if ((normalAdjustFlags & BT_TRIANGLE_CONCAVE_DOUBLE_SIDED)!=0) | |||
| { | |||
| //fix tri_normal so it pointing the same direction as the current local contact normal | |||
| if (tri_normal.dot(localContactNormalOnB) < 0) | |||
| { | |||
| tri_normal *= -1; | |||
| } | |||
| cp.m_normalWorldOnB = colObj0->getWorldTransform().getBasis()*tri_normal; | |||
| } else | |||
| { | |||
| btVector3 newNormal = tri_normal *frontFacing; | |||
| //if the tri_normal is pointing opposite direction as the current local contact normal, skip it | |||
| btScalar d = newNormal.dot(localContactNormalOnB) ; | |||
| if (d< 0) | |||
| { | |||
| return; | |||
| } | |||
| //modify the normal to be the triangle normal (or backfacing normal) | |||
| cp.m_normalWorldOnB = colObj0->getWorldTransform().getBasis() *newNormal; | |||
| } | |||
| // Reproject collision point along normal. | |||
| cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; | |||
| cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,46 @@ | |||
| #ifndef BT_INTERNAL_EDGE_UTILITY_H | |||
| #define BT_INTERNAL_EDGE_UTILITY_H | |||
| #include "LinearMath/btHashMap.h" | |||
| #include "LinearMath/btVector3.h" | |||
| #include "BulletCollision/CollisionShapes/btTriangleInfoMap.h" | |||
| ///The btInternalEdgeUtility helps to avoid or reduce artifacts due to wrong collision normals caused by internal edges. | |||
| ///See also http://code.google.com/p/bullet/issues/detail?id=27 | |||
| class btBvhTriangleMeshShape; | |||
| class btCollisionObject; | |||
| class btManifoldPoint; | |||
| class btIDebugDraw; | |||
| enum btInternalEdgeAdjustFlags | |||
| { | |||
| BT_TRIANGLE_CONVEX_BACKFACE_MODE = 1, | |||
| BT_TRIANGLE_CONCAVE_DOUBLE_SIDED = 2, //double sided options are experimental, single sided is recommended | |||
| BT_TRIANGLE_CONVEX_DOUBLE_SIDED = 4 | |||
| }; | |||
| ///Call btGenerateInternalEdgeInfo to create triangle info, store in the shape 'userInfo' | |||
| void btGenerateInternalEdgeInfo (btBvhTriangleMeshShape*trimeshShape, btTriangleInfoMap* triangleInfoMap); | |||
| ///Call the btFixMeshNormal to adjust the collision normal, using the triangle info map (generated using btGenerateInternalEdgeInfo) | |||
| ///If this info map is missing, or the triangle is not store in this map, nothing will be done | |||
| void btAdjustInternalEdgeContacts(btManifoldPoint& cp, const btCollisionObject* trimeshColObj0,const btCollisionObject* otherColObj1, int partId0, int index0, int normalAdjustFlags = 0); | |||
| ///Enable the BT_INTERNAL_EDGE_DEBUG_DRAW define and call btSetDebugDrawer, to get visual info to see if the internal edge utility works properly. | |||
| ///If the utility doesn't work properly, you might have to adjust the threshold values in btTriangleInfoMap | |||
| //#define BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| void btSetDebugDrawer(btIDebugDraw* debugDrawer); | |||
| #endif //BT_INTERNAL_EDGE_DEBUG_DRAW | |||
| #endif //BT_INTERNAL_EDGE_UTILITY_H | |||
| @@ -0,0 +1,135 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btManifoldResult.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| ///This is to allow MaterialCombiner/Custom Friction/Restitution values | |||
| ContactAddedCallback gContactAddedCallback=0; | |||
| ///User can override this material combiner by implementing gContactAddedCallback and setting body0->m_collisionFlags |= btCollisionObject::customMaterialCallback; | |||
| inline btScalar calculateCombinedFriction(const btCollisionObject* body0,const btCollisionObject* body1) | |||
| { | |||
| btScalar friction = body0->getFriction() * body1->getFriction(); | |||
| const btScalar MAX_FRICTION = btScalar(10.); | |||
| if (friction < -MAX_FRICTION) | |||
| friction = -MAX_FRICTION; | |||
| if (friction > MAX_FRICTION) | |||
| friction = MAX_FRICTION; | |||
| return friction; | |||
| } | |||
| inline btScalar calculateCombinedRestitution(const btCollisionObject* body0,const btCollisionObject* body1) | |||
| { | |||
| return body0->getRestitution() * body1->getRestitution(); | |||
| } | |||
| btManifoldResult::btManifoldResult(btCollisionObject* body0,btCollisionObject* body1) | |||
| :m_manifoldPtr(0), | |||
| m_body0(body0), | |||
| m_body1(body1) | |||
| #ifdef DEBUG_PART_INDEX | |||
| ,m_partId0(-1), | |||
| m_partId1(-1), | |||
| m_index0(-1), | |||
| m_index1(-1) | |||
| #endif //DEBUG_PART_INDEX | |||
| { | |||
| m_rootTransA = body0->getWorldTransform(); | |||
| m_rootTransB = body1->getWorldTransform(); | |||
| } | |||
| void btManifoldResult::addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) | |||
| { | |||
| btAssert(m_manifoldPtr); | |||
| //order in manifold needs to match | |||
| if (depth > m_manifoldPtr->getContactBreakingThreshold()) | |||
| // if (depth > m_manifoldPtr->getContactProcessingThreshold()) | |||
| return; | |||
| bool isSwapped = m_manifoldPtr->getBody0() != m_body0; | |||
| btVector3 pointA = pointInWorld + normalOnBInWorld * depth; | |||
| btVector3 localA; | |||
| btVector3 localB; | |||
| if (isSwapped) | |||
| { | |||
| localA = m_rootTransB.invXform(pointA ); | |||
| localB = m_rootTransA.invXform(pointInWorld); | |||
| } else | |||
| { | |||
| localA = m_rootTransA.invXform(pointA ); | |||
| localB = m_rootTransB.invXform(pointInWorld); | |||
| } | |||
| btManifoldPoint newPt(localA,localB,normalOnBInWorld,depth); | |||
| newPt.m_positionWorldOnA = pointA; | |||
| newPt.m_positionWorldOnB = pointInWorld; | |||
| int insertIndex = m_manifoldPtr->getCacheEntry(newPt); | |||
| newPt.m_combinedFriction = calculateCombinedFriction(m_body0,m_body1); | |||
| newPt.m_combinedRestitution = calculateCombinedRestitution(m_body0,m_body1); | |||
| //BP mod, store contact triangles. | |||
| if (isSwapped) | |||
| { | |||
| newPt.m_partId0 = m_partId1; | |||
| newPt.m_partId1 = m_partId0; | |||
| newPt.m_index0 = m_index1; | |||
| newPt.m_index1 = m_index0; | |||
| } else | |||
| { | |||
| newPt.m_partId0 = m_partId0; | |||
| newPt.m_partId1 = m_partId1; | |||
| newPt.m_index0 = m_index0; | |||
| newPt.m_index1 = m_index1; | |||
| } | |||
| //printf("depth=%f\n",depth); | |||
| ///@todo, check this for any side effects | |||
| if (insertIndex >= 0) | |||
| { | |||
| //const btManifoldPoint& oldPoint = m_manifoldPtr->getContactPoint(insertIndex); | |||
| m_manifoldPtr->replaceContactPoint(newPt,insertIndex); | |||
| } else | |||
| { | |||
| insertIndex = m_manifoldPtr->addManifoldPoint(newPt); | |||
| } | |||
| //User can override friction and/or restitution | |||
| if (gContactAddedCallback && | |||
| //and if either of the two bodies requires custom material | |||
| ((m_body0->getCollisionFlags() & btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK) || | |||
| (m_body1->getCollisionFlags() & btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK))) | |||
| { | |||
| //experimental feature info, for per-triangle material etc. | |||
| btCollisionObject* obj0 = isSwapped? m_body1 : m_body0; | |||
| btCollisionObject* obj1 = isSwapped? m_body0 : m_body1; | |||
| (*gContactAddedCallback)(m_manifoldPtr->getContactPoint(insertIndex),obj0,newPt.m_partId0,newPt.m_index0,obj1,newPt.m_partId1,newPt.m_index1); | |||
| } | |||
| } | |||
| @@ -0,0 +1,128 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_MANIFOLD_RESULT_H | |||
| #define BT_MANIFOLD_RESULT_H | |||
| class btCollisionObject; | |||
| #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
| class btManifoldPoint; | |||
| #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" | |||
| #include "LinearMath/btTransform.h" | |||
| typedef bool (*ContactAddedCallback)(btManifoldPoint& cp, const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1); | |||
| extern ContactAddedCallback gContactAddedCallback; | |||
| //#define DEBUG_PART_INDEX 1 | |||
| ///btManifoldResult is a helper class to manage contact results. | |||
| class btManifoldResult : public btDiscreteCollisionDetectorInterface::Result | |||
| { | |||
| protected: | |||
| btPersistentManifold* m_manifoldPtr; | |||
| //we need this for compounds | |||
| btTransform m_rootTransA; | |||
| btTransform m_rootTransB; | |||
| btCollisionObject* m_body0; | |||
| btCollisionObject* m_body1; | |||
| int m_partId0; | |||
| int m_partId1; | |||
| int m_index0; | |||
| int m_index1; | |||
| public: | |||
| btManifoldResult() | |||
| #ifdef DEBUG_PART_INDEX | |||
| : | |||
| m_partId0(-1), | |||
| m_partId1(-1), | |||
| m_index0(-1), | |||
| m_index1(-1) | |||
| #endif //DEBUG_PART_INDEX | |||
| { | |||
| } | |||
| btManifoldResult(btCollisionObject* body0,btCollisionObject* body1); | |||
| virtual ~btManifoldResult() {}; | |||
| void setPersistentManifold(btPersistentManifold* manifoldPtr) | |||
| { | |||
| m_manifoldPtr = manifoldPtr; | |||
| } | |||
| const btPersistentManifold* getPersistentManifold() const | |||
| { | |||
| return m_manifoldPtr; | |||
| } | |||
| btPersistentManifold* getPersistentManifold() | |||
| { | |||
| return m_manifoldPtr; | |||
| } | |||
| virtual void setShapeIdentifiersA(int partId0,int index0) | |||
| { | |||
| m_partId0=partId0; | |||
| m_index0=index0; | |||
| } | |||
| virtual void setShapeIdentifiersB( int partId1,int index1) | |||
| { | |||
| m_partId1=partId1; | |||
| m_index1=index1; | |||
| } | |||
| virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth); | |||
| SIMD_FORCE_INLINE void refreshContactPoints() | |||
| { | |||
| btAssert(m_manifoldPtr); | |||
| if (!m_manifoldPtr->getNumContacts()) | |||
| return; | |||
| bool isSwapped = m_manifoldPtr->getBody0() != m_body0; | |||
| if (isSwapped) | |||
| { | |||
| m_manifoldPtr->refreshContactPoints(m_rootTransB,m_rootTransA); | |||
| } else | |||
| { | |||
| m_manifoldPtr->refreshContactPoints(m_rootTransA,m_rootTransB); | |||
| } | |||
| } | |||
| const btCollisionObject* getBody0Internal() const | |||
| { | |||
| return m_body0; | |||
| } | |||
| const btCollisionObject* getBody1Internal() const | |||
| { | |||
| return m_body1; | |||
| } | |||
| }; | |||
| #endif //BT_MANIFOLD_RESULT_H | |||
| @@ -0,0 +1,450 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "LinearMath/btScalar.h" | |||
| #include "btSimulationIslandManager.h" | |||
| #include "BulletCollision/BroadphaseCollision/btDispatcher.h" | |||
| #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionWorld.h" | |||
| //#include <stdio.h> | |||
| #include "LinearMath/btQuickprof.h" | |||
| btSimulationIslandManager::btSimulationIslandManager(): | |||
| m_splitIslands(true) | |||
| { | |||
| } | |||
| btSimulationIslandManager::~btSimulationIslandManager() | |||
| { | |||
| } | |||
| void btSimulationIslandManager::initUnionFind(int n) | |||
| { | |||
| m_unionFind.reset(n); | |||
| } | |||
| void btSimulationIslandManager::findUnions(btDispatcher* /* dispatcher */,btCollisionWorld* colWorld) | |||
| { | |||
| { | |||
| btOverlappingPairCache* pairCachePtr = colWorld->getPairCache(); | |||
| const int numOverlappingPairs = pairCachePtr->getNumOverlappingPairs(); | |||
| if (numOverlappingPairs) | |||
| { | |||
| btBroadphasePair* pairPtr = pairCachePtr->getOverlappingPairArrayPtr(); | |||
| for (int i=0;i<numOverlappingPairs;i++) | |||
| { | |||
| const btBroadphasePair& collisionPair = pairPtr[i]; | |||
| btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject; | |||
| btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject; | |||
| if (((colObj0) && ((colObj0)->mergesSimulationIslands())) && | |||
| ((colObj1) && ((colObj1)->mergesSimulationIslands()))) | |||
| { | |||
| m_unionFind.unite((colObj0)->getIslandTag(), | |||
| (colObj1)->getIslandTag()); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| #ifdef STATIC_SIMULATION_ISLAND_OPTIMIZATION | |||
| void btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher) | |||
| { | |||
| // put the index into m_controllers into m_tag | |||
| int index = 0; | |||
| { | |||
| int i; | |||
| for (i=0;i<colWorld->getCollisionObjectArray().size(); i++) | |||
| { | |||
| btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i]; | |||
| //Adding filtering here | |||
| if (!collisionObject->isStaticOrKinematicObject()) | |||
| { | |||
| collisionObject->setIslandTag(index++); | |||
| } | |||
| collisionObject->setCompanionId(-1); | |||
| collisionObject->setHitFraction(btScalar(1.)); | |||
| } | |||
| } | |||
| // do the union find | |||
| initUnionFind( index ); | |||
| findUnions(dispatcher,colWorld); | |||
| } | |||
| void btSimulationIslandManager::storeIslandActivationState(btCollisionWorld* colWorld) | |||
| { | |||
| // put the islandId ('find' value) into m_tag | |||
| { | |||
| int index = 0; | |||
| int i; | |||
| for (i=0;i<colWorld->getCollisionObjectArray().size();i++) | |||
| { | |||
| btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i]; | |||
| if (!collisionObject->isStaticOrKinematicObject()) | |||
| { | |||
| collisionObject->setIslandTag( m_unionFind.find(index) ); | |||
| //Set the correct object offset in Collision Object Array | |||
| m_unionFind.getElement(index).m_sz = i; | |||
| collisionObject->setCompanionId(-1); | |||
| index++; | |||
| } else | |||
| { | |||
| collisionObject->setIslandTag(-1); | |||
| collisionObject->setCompanionId(-2); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| #else //STATIC_SIMULATION_ISLAND_OPTIMIZATION | |||
| void btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher) | |||
| { | |||
| initUnionFind( int (colWorld->getCollisionObjectArray().size())); | |||
| // put the index into m_controllers into m_tag | |||
| { | |||
| int index = 0; | |||
| int i; | |||
| for (i=0;i<colWorld->getCollisionObjectArray().size(); i++) | |||
| { | |||
| btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i]; | |||
| collisionObject->setIslandTag(index); | |||
| collisionObject->setCompanionId(-1); | |||
| collisionObject->setHitFraction(btScalar(1.)); | |||
| index++; | |||
| } | |||
| } | |||
| // do the union find | |||
| findUnions(dispatcher,colWorld); | |||
| } | |||
| void btSimulationIslandManager::storeIslandActivationState(btCollisionWorld* colWorld) | |||
| { | |||
| // put the islandId ('find' value) into m_tag | |||
| { | |||
| int index = 0; | |||
| int i; | |||
| for (i=0;i<colWorld->getCollisionObjectArray().size();i++) | |||
| { | |||
| btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i]; | |||
| if (!collisionObject->isStaticOrKinematicObject()) | |||
| { | |||
| collisionObject->setIslandTag( m_unionFind.find(index) ); | |||
| collisionObject->setCompanionId(-1); | |||
| } else | |||
| { | |||
| collisionObject->setIslandTag(-1); | |||
| collisionObject->setCompanionId(-2); | |||
| } | |||
| index++; | |||
| } | |||
| } | |||
| } | |||
| #endif //STATIC_SIMULATION_ISLAND_OPTIMIZATION | |||
| inline int getIslandId(const btPersistentManifold* lhs) | |||
| { | |||
| int islandId; | |||
| const btCollisionObject* rcolObj0 = static_cast<const btCollisionObject*>(lhs->getBody0()); | |||
| const btCollisionObject* rcolObj1 = static_cast<const btCollisionObject*>(lhs->getBody1()); | |||
| islandId= rcolObj0->getIslandTag()>=0?rcolObj0->getIslandTag():rcolObj1->getIslandTag(); | |||
| return islandId; | |||
| } | |||
| /// function object that routes calls to operator< | |||
| class btPersistentManifoldSortPredicate | |||
| { | |||
| public: | |||
| SIMD_FORCE_INLINE bool operator() ( const btPersistentManifold* lhs, const btPersistentManifold* rhs ) const | |||
| { | |||
| return getIslandId(lhs) < getIslandId(rhs); | |||
| } | |||
| }; | |||
| void btSimulationIslandManager::buildIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld) | |||
| { | |||
| BT_PROFILE("islandUnionFindAndQuickSort"); | |||
| btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray(); | |||
| m_islandmanifold.resize(0); | |||
| //we are going to sort the unionfind array, and store the element id in the size | |||
| //afterwards, we clean unionfind, to make sure no-one uses it anymore | |||
| getUnionFind().sortIslands(); | |||
| int numElem = getUnionFind().getNumElements(); | |||
| int endIslandIndex=1; | |||
| int startIslandIndex; | |||
| //update the sleeping state for bodies, if all are sleeping | |||
| for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex) | |||
| { | |||
| int islandId = getUnionFind().getElement(startIslandIndex).m_id; | |||
| for (endIslandIndex = startIslandIndex+1;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++) | |||
| { | |||
| } | |||
| //int numSleeping = 0; | |||
| bool allSleeping = true; | |||
| int idx; | |||
| for (idx=startIslandIndex;idx<endIslandIndex;idx++) | |||
| { | |||
| int i = getUnionFind().getElement(idx).m_sz; | |||
| btCollisionObject* colObj0 = collisionObjects[i]; | |||
| if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) | |||
| { | |||
| // printf("error in island management\n"); | |||
| } | |||
| btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); | |||
| if (colObj0->getIslandTag() == islandId) | |||
| { | |||
| if (colObj0->getActivationState()== ACTIVE_TAG) | |||
| { | |||
| allSleeping = false; | |||
| } | |||
| if (colObj0->getActivationState()== DISABLE_DEACTIVATION) | |||
| { | |||
| allSleeping = false; | |||
| } | |||
| } | |||
| } | |||
| if (allSleeping) | |||
| { | |||
| int idx; | |||
| for (idx=startIslandIndex;idx<endIslandIndex;idx++) | |||
| { | |||
| int i = getUnionFind().getElement(idx).m_sz; | |||
| btCollisionObject* colObj0 = collisionObjects[i]; | |||
| if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) | |||
| { | |||
| // printf("error in island management\n"); | |||
| } | |||
| btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); | |||
| if (colObj0->getIslandTag() == islandId) | |||
| { | |||
| colObj0->setActivationState( ISLAND_SLEEPING ); | |||
| } | |||
| } | |||
| } else | |||
| { | |||
| int idx; | |||
| for (idx=startIslandIndex;idx<endIslandIndex;idx++) | |||
| { | |||
| int i = getUnionFind().getElement(idx).m_sz; | |||
| btCollisionObject* colObj0 = collisionObjects[i]; | |||
| if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) | |||
| { | |||
| // printf("error in island management\n"); | |||
| } | |||
| btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); | |||
| if (colObj0->getIslandTag() == islandId) | |||
| { | |||
| if ( colObj0->getActivationState() == ISLAND_SLEEPING) | |||
| { | |||
| colObj0->setActivationState( WANTS_DEACTIVATION); | |||
| colObj0->setDeactivationTime(0.f); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| int i; | |||
| int maxNumManifolds = dispatcher->getNumManifolds(); | |||
| //#define SPLIT_ISLANDS 1 | |||
| //#ifdef SPLIT_ISLANDS | |||
| //#endif //SPLIT_ISLANDS | |||
| for (i=0;i<maxNumManifolds ;i++) | |||
| { | |||
| btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i); | |||
| btCollisionObject* colObj0 = static_cast<btCollisionObject*>(manifold->getBody0()); | |||
| btCollisionObject* colObj1 = static_cast<btCollisionObject*>(manifold->getBody1()); | |||
| ///@todo: check sleeping conditions! | |||
| if (((colObj0) && colObj0->getActivationState() != ISLAND_SLEEPING) || | |||
| ((colObj1) && colObj1->getActivationState() != ISLAND_SLEEPING)) | |||
| { | |||
| //kinematic objects don't merge islands, but wake up all connected objects | |||
| if (colObj0->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING) | |||
| { | |||
| if (colObj0->hasContactResponse()) | |||
| colObj1->activate(); | |||
| } | |||
| if (colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING) | |||
| { | |||
| if (colObj1->hasContactResponse()) | |||
| colObj0->activate(); | |||
| } | |||
| if(m_splitIslands) | |||
| { | |||
| //filtering for response | |||
| if (dispatcher->needsResponse(colObj0,colObj1)) | |||
| m_islandmanifold.push_back(manifold); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| ///@todo: this is random access, it can be walked 'cache friendly'! | |||
| void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld, IslandCallback* callback) | |||
| { | |||
| btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray(); | |||
| buildIslands(dispatcher,collisionWorld); | |||
| int endIslandIndex=1; | |||
| int startIslandIndex; | |||
| int numElem = getUnionFind().getNumElements(); | |||
| BT_PROFILE("processIslands"); | |||
| if(!m_splitIslands) | |||
| { | |||
| btPersistentManifold** manifold = dispatcher->getInternalManifoldPointer(); | |||
| int maxNumManifolds = dispatcher->getNumManifolds(); | |||
| callback->processIsland(&collisionObjects[0],collisionObjects.size(),manifold,maxNumManifolds, -1); | |||
| } | |||
| else | |||
| { | |||
| // Sort manifolds, based on islands | |||
| // Sort the vector using predicate and std::sort | |||
| //std::sort(islandmanifold.begin(), islandmanifold.end(), btPersistentManifoldSortPredicate); | |||
| int numManifolds = int (m_islandmanifold.size()); | |||
| //tried a radix sort, but quicksort/heapsort seems still faster | |||
| //@todo rewrite island management | |||
| m_islandmanifold.quickSort(btPersistentManifoldSortPredicate()); | |||
| //m_islandmanifold.heapSort(btPersistentManifoldSortPredicate()); | |||
| //now process all active islands (sets of manifolds for now) | |||
| int startManifoldIndex = 0; | |||
| int endManifoldIndex = 1; | |||
| //int islandId; | |||
| // printf("Start Islands\n"); | |||
| //traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated | |||
| for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex) | |||
| { | |||
| int islandId = getUnionFind().getElement(startIslandIndex).m_id; | |||
| bool islandSleeping = true; | |||
| for (endIslandIndex = startIslandIndex;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++) | |||
| { | |||
| int i = getUnionFind().getElement(endIslandIndex).m_sz; | |||
| btCollisionObject* colObj0 = collisionObjects[i]; | |||
| m_islandBodies.push_back(colObj0); | |||
| if (colObj0->isActive()) | |||
| islandSleeping = false; | |||
| } | |||
| //find the accompanying contact manifold for this islandId | |||
| int numIslandManifolds = 0; | |||
| btPersistentManifold** startManifold = 0; | |||
| if (startManifoldIndex<numManifolds) | |||
| { | |||
| int curIslandId = getIslandId(m_islandmanifold[startManifoldIndex]); | |||
| if (curIslandId == islandId) | |||
| { | |||
| startManifold = &m_islandmanifold[startManifoldIndex]; | |||
| for (endManifoldIndex = startManifoldIndex+1;(endManifoldIndex<numManifolds) && (islandId == getIslandId(m_islandmanifold[endManifoldIndex]));endManifoldIndex++) | |||
| { | |||
| } | |||
| /// Process the actual simulation, only if not sleeping/deactivated | |||
| numIslandManifolds = endManifoldIndex-startManifoldIndex; | |||
| } | |||
| } | |||
| if (!islandSleeping) | |||
| { | |||
| callback->processIsland(&m_islandBodies[0],m_islandBodies.size(),startManifold,numIslandManifolds, islandId); | |||
| // printf("Island callback of size:%d bodies, %d manifolds\n",islandBodies.size(),numIslandManifolds); | |||
| } | |||
| if (numIslandManifolds) | |||
| { | |||
| startManifoldIndex = endManifoldIndex; | |||
| } | |||
| m_islandBodies.resize(0); | |||
| } | |||
| } // else if(!splitIslands) | |||
| } | |||
| @@ -0,0 +1,81 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_SIMULATION_ISLAND_MANAGER_H | |||
| #define BT_SIMULATION_ISLAND_MANAGER_H | |||
| #include "BulletCollision/CollisionDispatch/btUnionFind.h" | |||
| #include "btCollisionCreateFunc.h" | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| #include "btCollisionObject.h" | |||
| class btCollisionObject; | |||
| class btCollisionWorld; | |||
| class btDispatcher; | |||
| class btPersistentManifold; | |||
| ///SimulationIslandManager creates and handles simulation islands, using btUnionFind | |||
| class btSimulationIslandManager | |||
| { | |||
| btUnionFind m_unionFind; | |||
| btAlignedObjectArray<btPersistentManifold*> m_islandmanifold; | |||
| btAlignedObjectArray<btCollisionObject* > m_islandBodies; | |||
| bool m_splitIslands; | |||
| public: | |||
| btSimulationIslandManager(); | |||
| virtual ~btSimulationIslandManager(); | |||
| void initUnionFind(int n); | |||
| btUnionFind& getUnionFind() { return m_unionFind;} | |||
| virtual void updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher); | |||
| virtual void storeIslandActivationState(btCollisionWorld* world); | |||
| void findUnions(btDispatcher* dispatcher,btCollisionWorld* colWorld); | |||
| struct IslandCallback | |||
| { | |||
| virtual ~IslandCallback() {}; | |||
| virtual void processIsland(btCollisionObject** bodies,int numBodies,class btPersistentManifold** manifolds,int numManifolds, int islandId) = 0; | |||
| }; | |||
| void buildAndProcessIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld, IslandCallback* callback); | |||
| void buildIslands(btDispatcher* dispatcher,btCollisionWorld* colWorld); | |||
| bool getSplitIslands() | |||
| { | |||
| return m_splitIslands; | |||
| } | |||
| void setSplitIslands(bool doSplitIslands) | |||
| { | |||
| m_splitIslands = doSplitIslands; | |||
| } | |||
| }; | |||
| #endif //BT_SIMULATION_ISLAND_MANAGER_H | |||
| @@ -0,0 +1,260 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btSphereBoxCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
| #include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
| #include "BulletCollision/CollisionShapes/btBoxShape.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| //#include <stdio.h> | |||
| btSphereBoxCollisionAlgorithm::btSphereBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped) | |||
| : btActivatingCollisionAlgorithm(ci,col0,col1), | |||
| m_ownManifold(false), | |||
| m_manifoldPtr(mf), | |||
| m_isSwapped(isSwapped) | |||
| { | |||
| btCollisionObject* sphereObj = m_isSwapped? col1 : col0; | |||
| btCollisionObject* boxObj = m_isSwapped? col0 : col1; | |||
| if (!m_manifoldPtr && m_dispatcher->needsCollision(sphereObj,boxObj)) | |||
| { | |||
| m_manifoldPtr = m_dispatcher->getNewManifold(sphereObj,boxObj); | |||
| m_ownManifold = true; | |||
| } | |||
| } | |||
| btSphereBoxCollisionAlgorithm::~btSphereBoxCollisionAlgorithm() | |||
| { | |||
| if (m_ownManifold) | |||
| { | |||
| if (m_manifoldPtr) | |||
| m_dispatcher->releaseManifold(m_manifoldPtr); | |||
| } | |||
| } | |||
| void btSphereBoxCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| (void)dispatchInfo; | |||
| (void)resultOut; | |||
| if (!m_manifoldPtr) | |||
| return; | |||
| btCollisionObject* sphereObj = m_isSwapped? body1 : body0; | |||
| btCollisionObject* boxObj = m_isSwapped? body0 : body1; | |||
| btSphereShape* sphere0 = (btSphereShape*)sphereObj->getCollisionShape(); | |||
| btVector3 normalOnSurfaceB; | |||
| btVector3 pOnBox,pOnSphere; | |||
| btVector3 sphereCenter = sphereObj->getWorldTransform().getOrigin(); | |||
| btScalar radius = sphere0->getRadius(); | |||
| btScalar dist = getSphereDistance(boxObj,pOnBox,pOnSphere,sphereCenter,radius); | |||
| resultOut->setPersistentManifold(m_manifoldPtr); | |||
| if (dist < SIMD_EPSILON) | |||
| { | |||
| btVector3 normalOnSurfaceB = (pOnBox- pOnSphere).normalize(); | |||
| /// report a contact. internally this will be kept persistent, and contact reduction is done | |||
| resultOut->addContactPoint(normalOnSurfaceB,pOnBox,dist); | |||
| } | |||
| if (m_ownManifold) | |||
| { | |||
| if (m_manifoldPtr->getNumContacts()) | |||
| { | |||
| resultOut->refreshContactPoints(); | |||
| } | |||
| } | |||
| } | |||
| btScalar btSphereBoxCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| (void)resultOut; | |||
| (void)dispatchInfo; | |||
| (void)col0; | |||
| (void)col1; | |||
| //not yet | |||
| return btScalar(1.); | |||
| } | |||
| btScalar btSphereBoxCollisionAlgorithm::getSphereDistance(btCollisionObject* boxObj, btVector3& pointOnBox, btVector3& v3PointOnSphere, const btVector3& sphereCenter, btScalar fRadius ) | |||
| { | |||
| btScalar margins; | |||
| btVector3 bounds[2]; | |||
| btBoxShape* boxShape= (btBoxShape*)boxObj->getCollisionShape(); | |||
| bounds[0] = -boxShape->getHalfExtentsWithoutMargin(); | |||
| bounds[1] = boxShape->getHalfExtentsWithoutMargin(); | |||
| margins = boxShape->getMargin();//also add sphereShape margin? | |||
| const btTransform& m44T = boxObj->getWorldTransform(); | |||
| btVector3 boundsVec[2]; | |||
| btScalar fPenetration; | |||
| boundsVec[0] = bounds[0]; | |||
| boundsVec[1] = bounds[1]; | |||
| btVector3 marginsVec( margins, margins, margins ); | |||
| // add margins | |||
| bounds[0] += marginsVec; | |||
| bounds[1] -= marginsVec; | |||
| ///////////////////////////////////////////////// | |||
| btVector3 tmp, prel, n[6], normal, v3P; | |||
| btScalar fSep = btScalar(10000000.0), fSepThis; | |||
| n[0].setValue( btScalar(-1.0), btScalar(0.0), btScalar(0.0) ); | |||
| n[1].setValue( btScalar(0.0), btScalar(-1.0), btScalar(0.0) ); | |||
| n[2].setValue( btScalar(0.0), btScalar(0.0), btScalar(-1.0) ); | |||
| n[3].setValue( btScalar(1.0), btScalar(0.0), btScalar(0.0) ); | |||
| n[4].setValue( btScalar(0.0), btScalar(1.0), btScalar(0.0) ); | |||
| n[5].setValue( btScalar(0.0), btScalar(0.0), btScalar(1.0) ); | |||
| // convert point in local space | |||
| prel = m44T.invXform( sphereCenter); | |||
| bool bFound = false; | |||
| v3P = prel; | |||
| for (int i=0;i<6;i++) | |||
| { | |||
| int j = i<3? 0:1; | |||
| if ( (fSepThis = ((v3P-bounds[j]) .dot(n[i]))) > btScalar(0.0) ) | |||
| { | |||
| v3P = v3P - n[i]*fSepThis; | |||
| bFound = true; | |||
| } | |||
| } | |||
| // | |||
| if ( bFound ) | |||
| { | |||
| bounds[0] = boundsVec[0]; | |||
| bounds[1] = boundsVec[1]; | |||
| normal = (prel - v3P).normalize(); | |||
| pointOnBox = v3P + normal*margins; | |||
| v3PointOnSphere = prel - normal*fRadius; | |||
| if ( ((v3PointOnSphere - pointOnBox) .dot (normal)) > btScalar(0.0) ) | |||
| { | |||
| return btScalar(1.0); | |||
| } | |||
| // transform back in world space | |||
| tmp = m44T( pointOnBox); | |||
| pointOnBox = tmp; | |||
| tmp = m44T( v3PointOnSphere); | |||
| v3PointOnSphere = tmp; | |||
| btScalar fSeps2 = (pointOnBox-v3PointOnSphere).length2(); | |||
| //if this fails, fallback into deeper penetration case, below | |||
| if (fSeps2 > SIMD_EPSILON) | |||
| { | |||
| fSep = - btSqrt(fSeps2); | |||
| normal = (pointOnBox-v3PointOnSphere); | |||
| normal *= btScalar(1.)/fSep; | |||
| } | |||
| return fSep; | |||
| } | |||
| ////////////////////////////////////////////////// | |||
| // Deep penetration case | |||
| fPenetration = getSpherePenetration( boxObj,pointOnBox, v3PointOnSphere, sphereCenter, fRadius,bounds[0],bounds[1] ); | |||
| bounds[0] = boundsVec[0]; | |||
| bounds[1] = boundsVec[1]; | |||
| if ( fPenetration <= btScalar(0.0) ) | |||
| return (fPenetration-margins); | |||
| else | |||
| return btScalar(1.0); | |||
| } | |||
| btScalar btSphereBoxCollisionAlgorithm::getSpherePenetration( btCollisionObject* boxObj,btVector3& pointOnBox, btVector3& v3PointOnSphere, const btVector3& sphereCenter, btScalar fRadius, const btVector3& aabbMin, const btVector3& aabbMax) | |||
| { | |||
| btVector3 bounds[2]; | |||
| bounds[0] = aabbMin; | |||
| bounds[1] = aabbMax; | |||
| btVector3 p0, tmp, prel, n[6], normal; | |||
| btScalar fSep = btScalar(-10000000.0), fSepThis; | |||
| // set p0 and normal to a default value to shup up GCC | |||
| p0.setValue(btScalar(0.), btScalar(0.), btScalar(0.)); | |||
| normal.setValue(btScalar(0.), btScalar(0.), btScalar(0.)); | |||
| n[0].setValue( btScalar(-1.0), btScalar(0.0), btScalar(0.0) ); | |||
| n[1].setValue( btScalar(0.0), btScalar(-1.0), btScalar(0.0) ); | |||
| n[2].setValue( btScalar(0.0), btScalar(0.0), btScalar(-1.0) ); | |||
| n[3].setValue( btScalar(1.0), btScalar(0.0), btScalar(0.0) ); | |||
| n[4].setValue( btScalar(0.0), btScalar(1.0), btScalar(0.0) ); | |||
| n[5].setValue( btScalar(0.0), btScalar(0.0), btScalar(1.0) ); | |||
| const btTransform& m44T = boxObj->getWorldTransform(); | |||
| // convert point in local space | |||
| prel = m44T.invXform( sphereCenter); | |||
| /////////// | |||
| for (int i=0;i<6;i++) | |||
| { | |||
| int j = i<3 ? 0:1; | |||
| if ( (fSepThis = ((prel-bounds[j]) .dot( n[i]))-fRadius) > btScalar(0.0) ) return btScalar(1.0); | |||
| if ( fSepThis > fSep ) | |||
| { | |||
| p0 = bounds[j]; normal = (btVector3&)n[i]; | |||
| fSep = fSepThis; | |||
| } | |||
| } | |||
| pointOnBox = prel - normal*(normal.dot((prel-p0))); | |||
| v3PointOnSphere = pointOnBox + normal*fSep; | |||
| // transform back in world space | |||
| tmp = m44T( pointOnBox); | |||
| pointOnBox = tmp; | |||
| tmp = m44T( v3PointOnSphere); v3PointOnSphere = tmp; | |||
| normal = (pointOnBox-v3PointOnSphere).normalize(); | |||
| return fSep; | |||
| } | |||
| @@ -0,0 +1,75 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_SPHERE_BOX_COLLISION_ALGORITHM_H | |||
| #define BT_SPHERE_BOX_COLLISION_ALGORITHM_H | |||
| #include "btActivatingCollisionAlgorithm.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
| class btPersistentManifold; | |||
| #include "btCollisionDispatcher.h" | |||
| #include "LinearMath/btVector3.h" | |||
| /// btSphereBoxCollisionAlgorithm provides sphere-box collision detection. | |||
| /// Other features are frame-coherency (persistent data) and collision response. | |||
| class btSphereBoxCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
| { | |||
| bool m_ownManifold; | |||
| btPersistentManifold* m_manifoldPtr; | |||
| bool m_isSwapped; | |||
| public: | |||
| btSphereBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped); | |||
| virtual ~btSphereBoxCollisionAlgorithm(); | |||
| virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
| { | |||
| if (m_manifoldPtr && m_ownManifold) | |||
| { | |||
| manifoldArray.push_back(m_manifoldPtr); | |||
| } | |||
| } | |||
| btScalar getSphereDistance( btCollisionObject* boxObj,btVector3& v3PointOnBox, btVector3& v3PointOnSphere, const btVector3& v3SphereCenter, btScalar fRadius ); | |||
| btScalar getSpherePenetration( btCollisionObject* boxObj, btVector3& v3PointOnBox, btVector3& v3PointOnSphere, const btVector3& v3SphereCenter, btScalar fRadius, const btVector3& aabbMin, const btVector3& aabbMax); | |||
| struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereBoxCollisionAlgorithm)); | |||
| if (!m_swapped) | |||
| { | |||
| return new(mem) btSphereBoxCollisionAlgorithm(0,ci,body0,body1,false); | |||
| } else | |||
| { | |||
| return new(mem) btSphereBoxCollisionAlgorithm(0,ci,body0,body1,true); | |||
| } | |||
| } | |||
| }; | |||
| }; | |||
| #endif //BT_SPHERE_BOX_COLLISION_ALGORITHM_H | |||
| @@ -0,0 +1,105 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btSphereSphereCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
| #include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| btSphereSphereCollisionAlgorithm::btSphereSphereCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1) | |||
| : btActivatingCollisionAlgorithm(ci,col0,col1), | |||
| m_ownManifold(false), | |||
| m_manifoldPtr(mf) | |||
| { | |||
| if (!m_manifoldPtr) | |||
| { | |||
| m_manifoldPtr = m_dispatcher->getNewManifold(col0,col1); | |||
| m_ownManifold = true; | |||
| } | |||
| } | |||
| btSphereSphereCollisionAlgorithm::~btSphereSphereCollisionAlgorithm() | |||
| { | |||
| if (m_ownManifold) | |||
| { | |||
| if (m_manifoldPtr) | |||
| m_dispatcher->releaseManifold(m_manifoldPtr); | |||
| } | |||
| } | |||
| void btSphereSphereCollisionAlgorithm::processCollision (btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| (void)dispatchInfo; | |||
| if (!m_manifoldPtr) | |||
| return; | |||
| resultOut->setPersistentManifold(m_manifoldPtr); | |||
| btSphereShape* sphere0 = (btSphereShape*)col0->getCollisionShape(); | |||
| btSphereShape* sphere1 = (btSphereShape*)col1->getCollisionShape(); | |||
| btVector3 diff = col0->getWorldTransform().getOrigin()- col1->getWorldTransform().getOrigin(); | |||
| btScalar len = diff.length(); | |||
| btScalar radius0 = sphere0->getRadius(); | |||
| btScalar radius1 = sphere1->getRadius(); | |||
| #ifdef CLEAR_MANIFOLD | |||
| m_manifoldPtr->clearManifold(); //don't do this, it disables warmstarting | |||
| #endif | |||
| ///iff distance positive, don't generate a new contact | |||
| if ( len > (radius0+radius1)) | |||
| { | |||
| #ifndef CLEAR_MANIFOLD | |||
| resultOut->refreshContactPoints(); | |||
| #endif //CLEAR_MANIFOLD | |||
| return; | |||
| } | |||
| ///distance (negative means penetration) | |||
| btScalar dist = len - (radius0+radius1); | |||
| btVector3 normalOnSurfaceB(1,0,0); | |||
| if (len > SIMD_EPSILON) | |||
| { | |||
| normalOnSurfaceB = diff / len; | |||
| } | |||
| ///point on A (worldspace) | |||
| ///btVector3 pos0 = col0->getWorldTransform().getOrigin() - radius0 * normalOnSurfaceB; | |||
| ///point on B (worldspace) | |||
| btVector3 pos1 = col1->getWorldTransform().getOrigin() + radius1* normalOnSurfaceB; | |||
| /// report a contact. internally this will be kept persistent, and contact reduction is done | |||
| resultOut->addContactPoint(normalOnSurfaceB,pos1,dist); | |||
| #ifndef CLEAR_MANIFOLD | |||
| resultOut->refreshContactPoints(); | |||
| #endif //CLEAR_MANIFOLD | |||
| } | |||
| btScalar btSphereSphereCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| (void)col0; | |||
| (void)col1; | |||
| (void)dispatchInfo; | |||
| (void)resultOut; | |||
| //not yet | |||
| return btScalar(1.); | |||
| } | |||
| @@ -0,0 +1,66 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_SPHERE_SPHERE_COLLISION_ALGORITHM_H | |||
| #define BT_SPHERE_SPHERE_COLLISION_ALGORITHM_H | |||
| #include "btActivatingCollisionAlgorithm.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
| #include "btCollisionDispatcher.h" | |||
| class btPersistentManifold; | |||
| /// btSphereSphereCollisionAlgorithm provides sphere-sphere collision detection. | |||
| /// Other features are frame-coherency (persistent data) and collision response. | |||
| /// Also provides the most basic sample for custom/user btCollisionAlgorithm | |||
| class btSphereSphereCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
| { | |||
| bool m_ownManifold; | |||
| btPersistentManifold* m_manifoldPtr; | |||
| public: | |||
| btSphereSphereCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); | |||
| btSphereSphereCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) | |||
| : btActivatingCollisionAlgorithm(ci) {} | |||
| virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
| { | |||
| if (m_manifoldPtr && m_ownManifold) | |||
| { | |||
| manifoldArray.push_back(m_manifoldPtr); | |||
| } | |||
| } | |||
| virtual ~btSphereSphereCollisionAlgorithm(); | |||
| struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereSphereCollisionAlgorithm)); | |||
| return new(mem) btSphereSphereCollisionAlgorithm(0,ci,body0,body1); | |||
| } | |||
| }; | |||
| }; | |||
| #endif //BT_SPHERE_SPHERE_COLLISION_ALGORITHM_H | |||
| @@ -0,0 +1,84 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btSphereTriangleCollisionAlgorithm.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" | |||
| #include "BulletCollision/CollisionShapes/btSphereShape.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h" | |||
| #include "SphereTriangleDetector.h" | |||
| btSphereTriangleCollisionAlgorithm::btSphereTriangleCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1,bool swapped) | |||
| : btActivatingCollisionAlgorithm(ci,col0,col1), | |||
| m_ownManifold(false), | |||
| m_manifoldPtr(mf), | |||
| m_swapped(swapped) | |||
| { | |||
| if (!m_manifoldPtr) | |||
| { | |||
| m_manifoldPtr = m_dispatcher->getNewManifold(col0,col1); | |||
| m_ownManifold = true; | |||
| } | |||
| } | |||
| btSphereTriangleCollisionAlgorithm::~btSphereTriangleCollisionAlgorithm() | |||
| { | |||
| if (m_ownManifold) | |||
| { | |||
| if (m_manifoldPtr) | |||
| m_dispatcher->releaseManifold(m_manifoldPtr); | |||
| } | |||
| } | |||
| void btSphereTriangleCollisionAlgorithm::processCollision (btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| if (!m_manifoldPtr) | |||
| return; | |||
| btCollisionObject* sphereObj = m_swapped? col1 : col0; | |||
| btCollisionObject* triObj = m_swapped? col0 : col1; | |||
| btSphereShape* sphere = (btSphereShape*)sphereObj->getCollisionShape(); | |||
| btTriangleShape* triangle = (btTriangleShape*)triObj->getCollisionShape(); | |||
| /// report a contact. internally this will be kept persistent, and contact reduction is done | |||
| resultOut->setPersistentManifold(m_manifoldPtr); | |||
| SphereTriangleDetector detector(sphere,triangle, m_manifoldPtr->getContactBreakingThreshold()); | |||
| btDiscreteCollisionDetectorInterface::ClosestPointInput input; | |||
| input.m_maximumDistanceSquared = btScalar(BT_LARGE_FLOAT);///@todo: tighter bounds | |||
| input.m_transformA = sphereObj->getWorldTransform(); | |||
| input.m_transformB = triObj->getWorldTransform(); | |||
| bool swapResults = m_swapped; | |||
| detector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw,swapResults); | |||
| if (m_ownManifold) | |||
| resultOut->refreshContactPoints(); | |||
| } | |||
| btScalar btSphereTriangleCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) | |||
| { | |||
| (void)resultOut; | |||
| (void)dispatchInfo; | |||
| (void)col0; | |||
| (void)col1; | |||
| //not yet | |||
| return btScalar(1.); | |||
| } | |||
| @@ -0,0 +1,69 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_SPHERE_TRIANGLE_COLLISION_ALGORITHM_H | |||
| #define BT_SPHERE_TRIANGLE_COLLISION_ALGORITHM_H | |||
| #include "btActivatingCollisionAlgorithm.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" | |||
| class btPersistentManifold; | |||
| #include "btCollisionDispatcher.h" | |||
| /// btSphereSphereCollisionAlgorithm provides sphere-sphere collision detection. | |||
| /// Other features are frame-coherency (persistent data) and collision response. | |||
| /// Also provides the most basic sample for custom/user btCollisionAlgorithm | |||
| class btSphereTriangleCollisionAlgorithm : public btActivatingCollisionAlgorithm | |||
| { | |||
| bool m_ownManifold; | |||
| btPersistentManifold* m_manifoldPtr; | |||
| bool m_swapped; | |||
| public: | |||
| btSphereTriangleCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool swapped); | |||
| btSphereTriangleCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) | |||
| : btActivatingCollisionAlgorithm(ci) {} | |||
| virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); | |||
| virtual void getAllContactManifolds(btManifoldArray& manifoldArray) | |||
| { | |||
| if (m_manifoldPtr && m_ownManifold) | |||
| { | |||
| manifoldArray.push_back(m_manifoldPtr); | |||
| } | |||
| } | |||
| virtual ~btSphereTriangleCollisionAlgorithm(); | |||
| struct CreateFunc :public btCollisionAlgorithmCreateFunc | |||
| { | |||
| virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) | |||
| { | |||
| void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereTriangleCollisionAlgorithm)); | |||
| return new(mem) btSphereTriangleCollisionAlgorithm(ci.m_manifold,ci,body0,body1,m_swapped); | |||
| } | |||
| }; | |||
| }; | |||
| #endif //BT_SPHERE_TRIANGLE_COLLISION_ALGORITHM_H | |||
| @@ -0,0 +1,82 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btUnionFind.h" | |||
| btUnionFind::~btUnionFind() | |||
| { | |||
| Free(); | |||
| } | |||
| btUnionFind::btUnionFind() | |||
| { | |||
| } | |||
| void btUnionFind::allocate(int N) | |||
| { | |||
| m_elements.resize(N); | |||
| } | |||
| void btUnionFind::Free() | |||
| { | |||
| m_elements.clear(); | |||
| } | |||
| void btUnionFind::reset(int N) | |||
| { | |||
| allocate(N); | |||
| for (int i = 0; i < N; i++) | |||
| { | |||
| m_elements[i].m_id = i; m_elements[i].m_sz = 1; | |||
| } | |||
| } | |||
| class btUnionFindElementSortPredicate | |||
| { | |||
| public: | |||
| bool operator() ( const btElement& lhs, const btElement& rhs ) const | |||
| { | |||
| return lhs.m_id < rhs.m_id; | |||
| } | |||
| }; | |||
| ///this is a special operation, destroying the content of btUnionFind. | |||
| ///it sorts the elements, based on island id, in order to make it easy to iterate over islands | |||
| void btUnionFind::sortIslands() | |||
| { | |||
| //first store the original body index, and islandId | |||
| int numElements = m_elements.size(); | |||
| for (int i=0;i<numElements;i++) | |||
| { | |||
| m_elements[i].m_id = find(i); | |||
| #ifndef STATIC_SIMULATION_ISLAND_OPTIMIZATION | |||
| m_elements[i].m_sz = i; | |||
| #endif //STATIC_SIMULATION_ISLAND_OPTIMIZATION | |||
| } | |||
| // Sort the vector using predicate and std::sort | |||
| //std::sort(m_elements.begin(), m_elements.end(), btUnionFindElementSortPredicate); | |||
| m_elements.quickSort(btUnionFindElementSortPredicate()); | |||
| } | |||
| @@ -0,0 +1,129 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_UNION_FIND_H | |||
| #define BT_UNION_FIND_H | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| #define USE_PATH_COMPRESSION 1 | |||
| ///see for discussion of static island optimizations by Vroonsh here: http://code.google.com/p/bullet/issues/detail?id=406 | |||
| #define STATIC_SIMULATION_ISLAND_OPTIMIZATION 1 | |||
| struct btElement | |||
| { | |||
| int m_id; | |||
| int m_sz; | |||
| }; | |||
| ///UnionFind calculates connected subsets | |||
| // Implements weighted Quick Union with path compression | |||
| // optimization: could use short ints instead of ints (halving memory, would limit the number of rigid bodies to 64k, sounds reasonable) | |||
| class btUnionFind | |||
| { | |||
| private: | |||
| btAlignedObjectArray<btElement> m_elements; | |||
| public: | |||
| btUnionFind(); | |||
| ~btUnionFind(); | |||
| //this is a special operation, destroying the content of btUnionFind. | |||
| //it sorts the elements, based on island id, in order to make it easy to iterate over islands | |||
| void sortIslands(); | |||
| void reset(int N); | |||
| SIMD_FORCE_INLINE int getNumElements() const | |||
| { | |||
| return int(m_elements.size()); | |||
| } | |||
| SIMD_FORCE_INLINE bool isRoot(int x) const | |||
| { | |||
| return (x == m_elements[x].m_id); | |||
| } | |||
| btElement& getElement(int index) | |||
| { | |||
| return m_elements[index]; | |||
| } | |||
| const btElement& getElement(int index) const | |||
| { | |||
| return m_elements[index]; | |||
| } | |||
| void allocate(int N); | |||
| void Free(); | |||
| int find(int p, int q) | |||
| { | |||
| return (find(p) == find(q)); | |||
| } | |||
| void unite(int p, int q) | |||
| { | |||
| int i = find(p), j = find(q); | |||
| if (i == j) | |||
| return; | |||
| #ifndef USE_PATH_COMPRESSION | |||
| //weighted quick union, this keeps the 'trees' balanced, and keeps performance of unite O( log(n) ) | |||
| if (m_elements[i].m_sz < m_elements[j].m_sz) | |||
| { | |||
| m_elements[i].m_id = j; m_elements[j].m_sz += m_elements[i].m_sz; | |||
| } | |||
| else | |||
| { | |||
| m_elements[j].m_id = i; m_elements[i].m_sz += m_elements[j].m_sz; | |||
| } | |||
| #else | |||
| m_elements[i].m_id = j; m_elements[j].m_sz += m_elements[i].m_sz; | |||
| #endif //USE_PATH_COMPRESSION | |||
| } | |||
| int find(int x) | |||
| { | |||
| //btAssert(x < m_N); | |||
| //btAssert(x >= 0); | |||
| while (x != m_elements[x].m_id) | |||
| { | |||
| //not really a reason not to use path compression, and it flattens the trees/improves find performance dramatically | |||
| #ifdef USE_PATH_COMPRESSION | |||
| const btElement* elementPtr = &m_elements[m_elements[x].m_id]; | |||
| m_elements[x].m_id = elementPtr->m_id; | |||
| x = elementPtr->m_id; | |||
| #else// | |||
| x = m_elements[x].m_id; | |||
| #endif | |||
| //btAssert(x < m_N); | |||
| //btAssert(x >= 0); | |||
| } | |||
| return x; | |||
| } | |||
| }; | |||
| #endif //BT_UNION_FIND_H | |||
| @@ -0,0 +1,42 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btBox2dShape.h" | |||
| //{ | |||
| void btBox2dShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const | |||
| { | |||
| btTransformAabb(getHalfExtentsWithoutMargin(),getMargin(),t,aabbMin,aabbMax); | |||
| } | |||
| void btBox2dShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const | |||
| { | |||
| //btScalar margin = btScalar(0.); | |||
| btVector3 halfExtents = getHalfExtentsWithMargin(); | |||
| btScalar lx=btScalar(2.)*(halfExtents.x()); | |||
| btScalar ly=btScalar(2.)*(halfExtents.y()); | |||
| btScalar lz=btScalar(2.)*(halfExtents.z()); | |||
| inertia.setValue(mass/(btScalar(12.0)) * (ly*ly + lz*lz), | |||
| mass/(btScalar(12.0)) * (lx*lx + lz*lz), | |||
| mass/(btScalar(12.0)) * (lx*lx + ly*ly)); | |||
| } | |||
| @@ -0,0 +1,369 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_OBB_BOX_2D_SHAPE_H | |||
| #define BT_OBB_BOX_2D_SHAPE_H | |||
| #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h" | |||
| #include "BulletCollision/CollisionShapes/btCollisionMargin.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "LinearMath/btVector3.h" | |||
| #include "LinearMath/btMinMax.h" | |||
| ///The btBox2dShape is a box primitive around the origin, its sides axis aligned with length specified by half extents, in local shape coordinates. When used as part of a btCollisionObject or btRigidBody it will be an oriented box in world space. | |||
| class btBox2dShape: public btPolyhedralConvexShape | |||
| { | |||
| //btVector3 m_boxHalfExtents1; //use m_implicitShapeDimensions instead | |||
| btVector3 m_centroid; | |||
| btVector3 m_vertices[4]; | |||
| btVector3 m_normals[4]; | |||
| public: | |||
| btVector3 getHalfExtentsWithMargin() const | |||
| { | |||
| btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
| btVector3 margin(getMargin(),getMargin(),getMargin()); | |||
| halfExtents += margin; | |||
| return halfExtents; | |||
| } | |||
| const btVector3& getHalfExtentsWithoutMargin() const | |||
| { | |||
| return m_implicitShapeDimensions;//changed in Bullet 2.63: assume the scaling and margin are included | |||
| } | |||
| virtual btVector3 localGetSupportingVertex(const btVector3& vec) const | |||
| { | |||
| btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
| btVector3 margin(getMargin(),getMargin(),getMargin()); | |||
| halfExtents += margin; | |||
| return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), | |||
| btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), | |||
| btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); | |||
| } | |||
| SIMD_FORCE_INLINE btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const | |||
| { | |||
| const btVector3& halfExtents = getHalfExtentsWithoutMargin(); | |||
| return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), | |||
| btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), | |||
| btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); | |||
| } | |||
| virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
| { | |||
| const btVector3& halfExtents = getHalfExtentsWithoutMargin(); | |||
| for (int i=0;i<numVectors;i++) | |||
| { | |||
| const btVector3& vec = vectors[i]; | |||
| supportVerticesOut[i].setValue(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), | |||
| btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), | |||
| btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); | |||
| } | |||
| } | |||
| ///a btBox2dShape is a flat 2D box in the X-Y plane (Z extents are zero) | |||
| btBox2dShape( const btVector3& boxHalfExtents) | |||
| : btPolyhedralConvexShape(), | |||
| m_centroid(0,0,0) | |||
| { | |||
| m_vertices[0].setValue(-boxHalfExtents.getX(),-boxHalfExtents.getY(),0); | |||
| m_vertices[1].setValue(boxHalfExtents.getX(),-boxHalfExtents.getY(),0); | |||
| m_vertices[2].setValue(boxHalfExtents.getX(),boxHalfExtents.getY(),0); | |||
| m_vertices[3].setValue(-boxHalfExtents.getX(),boxHalfExtents.getY(),0); | |||
| m_normals[0].setValue(0,-1,0); | |||
| m_normals[1].setValue(1,0,0); | |||
| m_normals[2].setValue(0,1,0); | |||
| m_normals[3].setValue(-1,0,0); | |||
| btScalar minDimension = boxHalfExtents.getX(); | |||
| if (minDimension>boxHalfExtents.getY()) | |||
| minDimension = boxHalfExtents.getY(); | |||
| setSafeMargin(minDimension); | |||
| m_shapeType = BOX_2D_SHAPE_PROXYTYPE; | |||
| btVector3 margin(getMargin(),getMargin(),getMargin()); | |||
| m_implicitShapeDimensions = (boxHalfExtents * m_localScaling) - margin; | |||
| }; | |||
| virtual void setMargin(btScalar collisionMargin) | |||
| { | |||
| //correct the m_implicitShapeDimensions for the margin | |||
| btVector3 oldMargin(getMargin(),getMargin(),getMargin()); | |||
| btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; | |||
| btConvexInternalShape::setMargin(collisionMargin); | |||
| btVector3 newMargin(getMargin(),getMargin(),getMargin()); | |||
| m_implicitShapeDimensions = implicitShapeDimensionsWithMargin - newMargin; | |||
| } | |||
| virtual void setLocalScaling(const btVector3& scaling) | |||
| { | |||
| btVector3 oldMargin(getMargin(),getMargin(),getMargin()); | |||
| btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; | |||
| btVector3 unScaledImplicitShapeDimensionsWithMargin = implicitShapeDimensionsWithMargin / m_localScaling; | |||
| btConvexInternalShape::setLocalScaling(scaling); | |||
| m_implicitShapeDimensions = (unScaledImplicitShapeDimensionsWithMargin * m_localScaling) - oldMargin; | |||
| } | |||
| virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
| virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; | |||
| int getVertexCount() const | |||
| { | |||
| return 4; | |||
| } | |||
| virtual int getNumVertices()const | |||
| { | |||
| return 4; | |||
| } | |||
| const btVector3* getVertices() const | |||
| { | |||
| return &m_vertices[0]; | |||
| } | |||
| const btVector3* getNormals() const | |||
| { | |||
| return &m_normals[0]; | |||
| } | |||
| virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i ) const | |||
| { | |||
| //this plane might not be aligned... | |||
| btVector4 plane ; | |||
| getPlaneEquation(plane,i); | |||
| planeNormal = btVector3(plane.getX(),plane.getY(),plane.getZ()); | |||
| planeSupport = localGetSupportingVertex(-planeNormal); | |||
| } | |||
| const btVector3& getCentroid() const | |||
| { | |||
| return m_centroid; | |||
| } | |||
| virtual int getNumPlanes() const | |||
| { | |||
| return 6; | |||
| } | |||
| virtual int getNumEdges() const | |||
| { | |||
| return 12; | |||
| } | |||
| virtual void getVertex(int i,btVector3& vtx) const | |||
| { | |||
| btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
| vtx = btVector3( | |||
| halfExtents.x() * (1-(i&1)) - halfExtents.x() * (i&1), | |||
| halfExtents.y() * (1-((i&2)>>1)) - halfExtents.y() * ((i&2)>>1), | |||
| halfExtents.z() * (1-((i&4)>>2)) - halfExtents.z() * ((i&4)>>2)); | |||
| } | |||
| virtual void getPlaneEquation(btVector4& plane,int i) const | |||
| { | |||
| btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
| switch (i) | |||
| { | |||
| case 0: | |||
| plane.setValue(btScalar(1.),btScalar(0.),btScalar(0.),-halfExtents.x()); | |||
| break; | |||
| case 1: | |||
| plane.setValue(btScalar(-1.),btScalar(0.),btScalar(0.),-halfExtents.x()); | |||
| break; | |||
| case 2: | |||
| plane.setValue(btScalar(0.),btScalar(1.),btScalar(0.),-halfExtents.y()); | |||
| break; | |||
| case 3: | |||
| plane.setValue(btScalar(0.),btScalar(-1.),btScalar(0.),-halfExtents.y()); | |||
| break; | |||
| case 4: | |||
| plane.setValue(btScalar(0.),btScalar(0.),btScalar(1.),-halfExtents.z()); | |||
| break; | |||
| case 5: | |||
| plane.setValue(btScalar(0.),btScalar(0.),btScalar(-1.),-halfExtents.z()); | |||
| break; | |||
| default: | |||
| btAssert(0); | |||
| } | |||
| } | |||
| virtual void getEdge(int i,btVector3& pa,btVector3& pb) const | |||
| //virtual void getEdge(int i,Edge& edge) const | |||
| { | |||
| int edgeVert0 = 0; | |||
| int edgeVert1 = 0; | |||
| switch (i) | |||
| { | |||
| case 0: | |||
| edgeVert0 = 0; | |||
| edgeVert1 = 1; | |||
| break; | |||
| case 1: | |||
| edgeVert0 = 0; | |||
| edgeVert1 = 2; | |||
| break; | |||
| case 2: | |||
| edgeVert0 = 1; | |||
| edgeVert1 = 3; | |||
| break; | |||
| case 3: | |||
| edgeVert0 = 2; | |||
| edgeVert1 = 3; | |||
| break; | |||
| case 4: | |||
| edgeVert0 = 0; | |||
| edgeVert1 = 4; | |||
| break; | |||
| case 5: | |||
| edgeVert0 = 1; | |||
| edgeVert1 = 5; | |||
| break; | |||
| case 6: | |||
| edgeVert0 = 2; | |||
| edgeVert1 = 6; | |||
| break; | |||
| case 7: | |||
| edgeVert0 = 3; | |||
| edgeVert1 = 7; | |||
| break; | |||
| case 8: | |||
| edgeVert0 = 4; | |||
| edgeVert1 = 5; | |||
| break; | |||
| case 9: | |||
| edgeVert0 = 4; | |||
| edgeVert1 = 6; | |||
| break; | |||
| case 10: | |||
| edgeVert0 = 5; | |||
| edgeVert1 = 7; | |||
| break; | |||
| case 11: | |||
| edgeVert0 = 6; | |||
| edgeVert1 = 7; | |||
| break; | |||
| default: | |||
| btAssert(0); | |||
| } | |||
| getVertex(edgeVert0,pa ); | |||
| getVertex(edgeVert1,pb ); | |||
| } | |||
| virtual bool isInside(const btVector3& pt,btScalar tolerance) const | |||
| { | |||
| btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
| //btScalar minDist = 2*tolerance; | |||
| bool result = (pt.x() <= (halfExtents.x()+tolerance)) && | |||
| (pt.x() >= (-halfExtents.x()-tolerance)) && | |||
| (pt.y() <= (halfExtents.y()+tolerance)) && | |||
| (pt.y() >= (-halfExtents.y()-tolerance)) && | |||
| (pt.z() <= (halfExtents.z()+tolerance)) && | |||
| (pt.z() >= (-halfExtents.z()-tolerance)); | |||
| return result; | |||
| } | |||
| //debugging | |||
| virtual const char* getName()const | |||
| { | |||
| return "Box2d"; | |||
| } | |||
| virtual int getNumPreferredPenetrationDirections() const | |||
| { | |||
| return 6; | |||
| } | |||
| virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const | |||
| { | |||
| switch (index) | |||
| { | |||
| case 0: | |||
| penetrationVector.setValue(btScalar(1.),btScalar(0.),btScalar(0.)); | |||
| break; | |||
| case 1: | |||
| penetrationVector.setValue(btScalar(-1.),btScalar(0.),btScalar(0.)); | |||
| break; | |||
| case 2: | |||
| penetrationVector.setValue(btScalar(0.),btScalar(1.),btScalar(0.)); | |||
| break; | |||
| case 3: | |||
| penetrationVector.setValue(btScalar(0.),btScalar(-1.),btScalar(0.)); | |||
| break; | |||
| case 4: | |||
| penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(1.)); | |||
| break; | |||
| case 5: | |||
| penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(-1.)); | |||
| break; | |||
| default: | |||
| btAssert(0); | |||
| } | |||
| } | |||
| }; | |||
| #endif //BT_OBB_BOX_2D_SHAPE_H | |||
| @@ -0,0 +1,51 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btBoxShape.h" | |||
| btBoxShape::btBoxShape( const btVector3& boxHalfExtents) | |||
| : btPolyhedralConvexShape() | |||
| { | |||
| m_shapeType = BOX_SHAPE_PROXYTYPE; | |||
| setSafeMargin(boxHalfExtents); | |||
| btVector3 margin(getMargin(),getMargin(),getMargin()); | |||
| m_implicitShapeDimensions = (boxHalfExtents * m_localScaling) - margin; | |||
| }; | |||
| void btBoxShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const | |||
| { | |||
| btTransformAabb(getHalfExtentsWithoutMargin(),getMargin(),t,aabbMin,aabbMax); | |||
| } | |||
| void btBoxShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const | |||
| { | |||
| //btScalar margin = btScalar(0.); | |||
| btVector3 halfExtents = getHalfExtentsWithMargin(); | |||
| btScalar lx=btScalar(2.)*(halfExtents.x()); | |||
| btScalar ly=btScalar(2.)*(halfExtents.y()); | |||
| btScalar lz=btScalar(2.)*(halfExtents.z()); | |||
| inertia.setValue(mass/(btScalar(12.0)) * (ly*ly + lz*lz), | |||
| mass/(btScalar(12.0)) * (lx*lx + lz*lz), | |||
| mass/(btScalar(12.0)) * (lx*lx + ly*ly)); | |||
| } | |||
| @@ -0,0 +1,312 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_OBB_BOX_MINKOWSKI_H | |||
| #define BT_OBB_BOX_MINKOWSKI_H | |||
| #include "btPolyhedralConvexShape.h" | |||
| #include "btCollisionMargin.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" | |||
| #include "LinearMath/btVector3.h" | |||
| #include "LinearMath/btMinMax.h" | |||
| ///The btBoxShape is a box primitive around the origin, its sides axis aligned with length specified by half extents, in local shape coordinates. When used as part of a btCollisionObject or btRigidBody it will be an oriented box in world space. | |||
| class btBoxShape: public btPolyhedralConvexShape | |||
| { | |||
| //btVector3 m_boxHalfExtents1; //use m_implicitShapeDimensions instead | |||
| public: | |||
| btVector3 getHalfExtentsWithMargin() const | |||
| { | |||
| btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
| btVector3 margin(getMargin(),getMargin(),getMargin()); | |||
| halfExtents += margin; | |||
| return halfExtents; | |||
| } | |||
| const btVector3& getHalfExtentsWithoutMargin() const | |||
| { | |||
| return m_implicitShapeDimensions;//scaling is included, margin is not | |||
| } | |||
| virtual btVector3 localGetSupportingVertex(const btVector3& vec) const | |||
| { | |||
| btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
| btVector3 margin(getMargin(),getMargin(),getMargin()); | |||
| halfExtents += margin; | |||
| return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), | |||
| btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), | |||
| btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); | |||
| } | |||
| SIMD_FORCE_INLINE btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const | |||
| { | |||
| const btVector3& halfExtents = getHalfExtentsWithoutMargin(); | |||
| return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), | |||
| btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), | |||
| btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); | |||
| } | |||
| virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
| { | |||
| const btVector3& halfExtents = getHalfExtentsWithoutMargin(); | |||
| for (int i=0;i<numVectors;i++) | |||
| { | |||
| const btVector3& vec = vectors[i]; | |||
| supportVerticesOut[i].setValue(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), | |||
| btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), | |||
| btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); | |||
| } | |||
| } | |||
| btBoxShape( const btVector3& boxHalfExtents); | |||
| virtual void setMargin(btScalar collisionMargin) | |||
| { | |||
| //correct the m_implicitShapeDimensions for the margin | |||
| btVector3 oldMargin(getMargin(),getMargin(),getMargin()); | |||
| btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; | |||
| btConvexInternalShape::setMargin(collisionMargin); | |||
| btVector3 newMargin(getMargin(),getMargin(),getMargin()); | |||
| m_implicitShapeDimensions = implicitShapeDimensionsWithMargin - newMargin; | |||
| } | |||
| virtual void setLocalScaling(const btVector3& scaling) | |||
| { | |||
| btVector3 oldMargin(getMargin(),getMargin(),getMargin()); | |||
| btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; | |||
| btVector3 unScaledImplicitShapeDimensionsWithMargin = implicitShapeDimensionsWithMargin / m_localScaling; | |||
| btConvexInternalShape::setLocalScaling(scaling); | |||
| m_implicitShapeDimensions = (unScaledImplicitShapeDimensionsWithMargin * m_localScaling) - oldMargin; | |||
| } | |||
| virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
| virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; | |||
| virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i ) const | |||
| { | |||
| //this plane might not be aligned... | |||
| btVector4 plane ; | |||
| getPlaneEquation(plane,i); | |||
| planeNormal = btVector3(plane.getX(),plane.getY(),plane.getZ()); | |||
| planeSupport = localGetSupportingVertex(-planeNormal); | |||
| } | |||
| virtual int getNumPlanes() const | |||
| { | |||
| return 6; | |||
| } | |||
| virtual int getNumVertices() const | |||
| { | |||
| return 8; | |||
| } | |||
| virtual int getNumEdges() const | |||
| { | |||
| return 12; | |||
| } | |||
| virtual void getVertex(int i,btVector3& vtx) const | |||
| { | |||
| btVector3 halfExtents = getHalfExtentsWithMargin(); | |||
| vtx = btVector3( | |||
| halfExtents.x() * (1-(i&1)) - halfExtents.x() * (i&1), | |||
| halfExtents.y() * (1-((i&2)>>1)) - halfExtents.y() * ((i&2)>>1), | |||
| halfExtents.z() * (1-((i&4)>>2)) - halfExtents.z() * ((i&4)>>2)); | |||
| } | |||
| virtual void getPlaneEquation(btVector4& plane,int i) const | |||
| { | |||
| btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
| switch (i) | |||
| { | |||
| case 0: | |||
| plane.setValue(btScalar(1.),btScalar(0.),btScalar(0.),-halfExtents.x()); | |||
| break; | |||
| case 1: | |||
| plane.setValue(btScalar(-1.),btScalar(0.),btScalar(0.),-halfExtents.x()); | |||
| break; | |||
| case 2: | |||
| plane.setValue(btScalar(0.),btScalar(1.),btScalar(0.),-halfExtents.y()); | |||
| break; | |||
| case 3: | |||
| plane.setValue(btScalar(0.),btScalar(-1.),btScalar(0.),-halfExtents.y()); | |||
| break; | |||
| case 4: | |||
| plane.setValue(btScalar(0.),btScalar(0.),btScalar(1.),-halfExtents.z()); | |||
| break; | |||
| case 5: | |||
| plane.setValue(btScalar(0.),btScalar(0.),btScalar(-1.),-halfExtents.z()); | |||
| break; | |||
| default: | |||
| btAssert(0); | |||
| } | |||
| } | |||
| virtual void getEdge(int i,btVector3& pa,btVector3& pb) const | |||
| //virtual void getEdge(int i,Edge& edge) const | |||
| { | |||
| int edgeVert0 = 0; | |||
| int edgeVert1 = 0; | |||
| switch (i) | |||
| { | |||
| case 0: | |||
| edgeVert0 = 0; | |||
| edgeVert1 = 1; | |||
| break; | |||
| case 1: | |||
| edgeVert0 = 0; | |||
| edgeVert1 = 2; | |||
| break; | |||
| case 2: | |||
| edgeVert0 = 1; | |||
| edgeVert1 = 3; | |||
| break; | |||
| case 3: | |||
| edgeVert0 = 2; | |||
| edgeVert1 = 3; | |||
| break; | |||
| case 4: | |||
| edgeVert0 = 0; | |||
| edgeVert1 = 4; | |||
| break; | |||
| case 5: | |||
| edgeVert0 = 1; | |||
| edgeVert1 = 5; | |||
| break; | |||
| case 6: | |||
| edgeVert0 = 2; | |||
| edgeVert1 = 6; | |||
| break; | |||
| case 7: | |||
| edgeVert0 = 3; | |||
| edgeVert1 = 7; | |||
| break; | |||
| case 8: | |||
| edgeVert0 = 4; | |||
| edgeVert1 = 5; | |||
| break; | |||
| case 9: | |||
| edgeVert0 = 4; | |||
| edgeVert1 = 6; | |||
| break; | |||
| case 10: | |||
| edgeVert0 = 5; | |||
| edgeVert1 = 7; | |||
| break; | |||
| case 11: | |||
| edgeVert0 = 6; | |||
| edgeVert1 = 7; | |||
| break; | |||
| default: | |||
| btAssert(0); | |||
| } | |||
| getVertex(edgeVert0,pa ); | |||
| getVertex(edgeVert1,pb ); | |||
| } | |||
| virtual bool isInside(const btVector3& pt,btScalar tolerance) const | |||
| { | |||
| btVector3 halfExtents = getHalfExtentsWithoutMargin(); | |||
| //btScalar minDist = 2*tolerance; | |||
| bool result = (pt.x() <= (halfExtents.x()+tolerance)) && | |||
| (pt.x() >= (-halfExtents.x()-tolerance)) && | |||
| (pt.y() <= (halfExtents.y()+tolerance)) && | |||
| (pt.y() >= (-halfExtents.y()-tolerance)) && | |||
| (pt.z() <= (halfExtents.z()+tolerance)) && | |||
| (pt.z() >= (-halfExtents.z()-tolerance)); | |||
| return result; | |||
| } | |||
| //debugging | |||
| virtual const char* getName()const | |||
| { | |||
| return "Box"; | |||
| } | |||
| virtual int getNumPreferredPenetrationDirections() const | |||
| { | |||
| return 6; | |||
| } | |||
| virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const | |||
| { | |||
| switch (index) | |||
| { | |||
| case 0: | |||
| penetrationVector.setValue(btScalar(1.),btScalar(0.),btScalar(0.)); | |||
| break; | |||
| case 1: | |||
| penetrationVector.setValue(btScalar(-1.),btScalar(0.),btScalar(0.)); | |||
| break; | |||
| case 2: | |||
| penetrationVector.setValue(btScalar(0.),btScalar(1.),btScalar(0.)); | |||
| break; | |||
| case 3: | |||
| penetrationVector.setValue(btScalar(0.),btScalar(-1.),btScalar(0.)); | |||
| break; | |||
| case 4: | |||
| penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(1.)); | |||
| break; | |||
| case 5: | |||
| penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(-1.)); | |||
| break; | |||
| default: | |||
| btAssert(0); | |||
| } | |||
| } | |||
| }; | |||
| #endif //BT_OBB_BOX_MINKOWSKI_H | |||
| @@ -0,0 +1,466 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| //#define DISABLE_BVH | |||
| #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" | |||
| #include "BulletCollision/CollisionShapes/btOptimizedBvh.h" | |||
| #include "LinearMath/btSerializer.h" | |||
| ///Bvh Concave triangle mesh is a static-triangle mesh shape with Bounding Volume Hierarchy optimization. | |||
| ///Uses an interface to access the triangles to allow for sharing graphics/physics triangles. | |||
| btBvhTriangleMeshShape::btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh) | |||
| :btTriangleMeshShape(meshInterface), | |||
| m_bvh(0), | |||
| m_triangleInfoMap(0), | |||
| m_useQuantizedAabbCompression(useQuantizedAabbCompression), | |||
| m_ownsBvh(false) | |||
| { | |||
| m_shapeType = TRIANGLE_MESH_SHAPE_PROXYTYPE; | |||
| //construct bvh from meshInterface | |||
| #ifndef DISABLE_BVH | |||
| if (buildBvh) | |||
| { | |||
| buildOptimizedBvh(); | |||
| } | |||
| #endif //DISABLE_BVH | |||
| } | |||
| btBvhTriangleMeshShape::btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,bool buildBvh) | |||
| :btTriangleMeshShape(meshInterface), | |||
| m_bvh(0), | |||
| m_triangleInfoMap(0), | |||
| m_useQuantizedAabbCompression(useQuantizedAabbCompression), | |||
| m_ownsBvh(false) | |||
| { | |||
| m_shapeType = TRIANGLE_MESH_SHAPE_PROXYTYPE; | |||
| //construct bvh from meshInterface | |||
| #ifndef DISABLE_BVH | |||
| if (buildBvh) | |||
| { | |||
| void* mem = btAlignedAlloc(sizeof(btOptimizedBvh),16); | |||
| m_bvh = new (mem) btOptimizedBvh(); | |||
| m_bvh->build(meshInterface,m_useQuantizedAabbCompression,bvhAabbMin,bvhAabbMax); | |||
| m_ownsBvh = true; | |||
| } | |||
| #endif //DISABLE_BVH | |||
| } | |||
| void btBvhTriangleMeshShape::partialRefitTree(const btVector3& aabbMin,const btVector3& aabbMax) | |||
| { | |||
| m_bvh->refitPartial( m_meshInterface,aabbMin,aabbMax ); | |||
| m_localAabbMin.setMin(aabbMin); | |||
| m_localAabbMax.setMax(aabbMax); | |||
| } | |||
| void btBvhTriangleMeshShape::refitTree(const btVector3& aabbMin,const btVector3& aabbMax) | |||
| { | |||
| m_bvh->refit( m_meshInterface, aabbMin,aabbMax ); | |||
| recalcLocalAabb(); | |||
| } | |||
| btBvhTriangleMeshShape::~btBvhTriangleMeshShape() | |||
| { | |||
| if (m_ownsBvh) | |||
| { | |||
| m_bvh->~btOptimizedBvh(); | |||
| btAlignedFree(m_bvh); | |||
| } | |||
| } | |||
| void btBvhTriangleMeshShape::performRaycast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget) | |||
| { | |||
| struct MyNodeOverlapCallback : public btNodeOverlapCallback | |||
| { | |||
| btStridingMeshInterface* m_meshInterface; | |||
| btTriangleCallback* m_callback; | |||
| MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface) | |||
| :m_meshInterface(meshInterface), | |||
| m_callback(callback) | |||
| { | |||
| } | |||
| virtual void processNode(int nodeSubPart, int nodeTriangleIndex) | |||
| { | |||
| btVector3 m_triangle[3]; | |||
| const unsigned char *vertexbase; | |||
| int numverts; | |||
| PHY_ScalarType type; | |||
| int stride; | |||
| const unsigned char *indexbase; | |||
| int indexstride; | |||
| int numfaces; | |||
| PHY_ScalarType indicestype; | |||
| m_meshInterface->getLockedReadOnlyVertexIndexBase( | |||
| &vertexbase, | |||
| numverts, | |||
| type, | |||
| stride, | |||
| &indexbase, | |||
| indexstride, | |||
| numfaces, | |||
| indicestype, | |||
| nodeSubPart); | |||
| unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride); | |||
| btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT); | |||
| const btVector3& meshScaling = m_meshInterface->getScaling(); | |||
| for (int j=2;j>=0;j--) | |||
| { | |||
| int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; | |||
| if (type == PHY_FLOAT) | |||
| { | |||
| float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); | |||
| m_triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ()); | |||
| } | |||
| else | |||
| { | |||
| double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); | |||
| m_triangle[j] = btVector3(btScalar(graphicsbase[0])*meshScaling.getX(),btScalar(graphicsbase[1])*meshScaling.getY(),btScalar(graphicsbase[2])*meshScaling.getZ()); | |||
| } | |||
| } | |||
| /* Perform ray vs. triangle collision here */ | |||
| m_callback->processTriangle(m_triangle,nodeSubPart,nodeTriangleIndex); | |||
| m_meshInterface->unLockReadOnlyVertexBase(nodeSubPart); | |||
| } | |||
| }; | |||
| MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface); | |||
| m_bvh->reportRayOverlappingNodex(&myNodeCallback,raySource,rayTarget); | |||
| } | |||
| void btBvhTriangleMeshShape::performConvexcast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax) | |||
| { | |||
| struct MyNodeOverlapCallback : public btNodeOverlapCallback | |||
| { | |||
| btStridingMeshInterface* m_meshInterface; | |||
| btTriangleCallback* m_callback; | |||
| MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface) | |||
| :m_meshInterface(meshInterface), | |||
| m_callback(callback) | |||
| { | |||
| } | |||
| virtual void processNode(int nodeSubPart, int nodeTriangleIndex) | |||
| { | |||
| btVector3 m_triangle[3]; | |||
| const unsigned char *vertexbase; | |||
| int numverts; | |||
| PHY_ScalarType type; | |||
| int stride; | |||
| const unsigned char *indexbase; | |||
| int indexstride; | |||
| int numfaces; | |||
| PHY_ScalarType indicestype; | |||
| m_meshInterface->getLockedReadOnlyVertexIndexBase( | |||
| &vertexbase, | |||
| numverts, | |||
| type, | |||
| stride, | |||
| &indexbase, | |||
| indexstride, | |||
| numfaces, | |||
| indicestype, | |||
| nodeSubPart); | |||
| unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride); | |||
| btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT); | |||
| const btVector3& meshScaling = m_meshInterface->getScaling(); | |||
| for (int j=2;j>=0;j--) | |||
| { | |||
| int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; | |||
| if (type == PHY_FLOAT) | |||
| { | |||
| float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); | |||
| m_triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ()); | |||
| } | |||
| else | |||
| { | |||
| double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); | |||
| m_triangle[j] = btVector3(btScalar(graphicsbase[0])*meshScaling.getX(),btScalar(graphicsbase[1])*meshScaling.getY(),btScalar(graphicsbase[2])*meshScaling.getZ()); | |||
| } | |||
| } | |||
| /* Perform ray vs. triangle collision here */ | |||
| m_callback->processTriangle(m_triangle,nodeSubPart,nodeTriangleIndex); | |||
| m_meshInterface->unLockReadOnlyVertexBase(nodeSubPart); | |||
| } | |||
| }; | |||
| MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface); | |||
| m_bvh->reportBoxCastOverlappingNodex (&myNodeCallback, raySource, rayTarget, aabbMin, aabbMax); | |||
| } | |||
| //perform bvh tree traversal and report overlapping triangles to 'callback' | |||
| void btBvhTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const | |||
| { | |||
| #ifdef DISABLE_BVH | |||
| //brute force traverse all triangles | |||
| btTriangleMeshShape::processAllTriangles(callback,aabbMin,aabbMax); | |||
| #else | |||
| //first get all the nodes | |||
| struct MyNodeOverlapCallback : public btNodeOverlapCallback | |||
| { | |||
| btStridingMeshInterface* m_meshInterface; | |||
| btTriangleCallback* m_callback; | |||
| btVector3 m_triangle[3]; | |||
| MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface) | |||
| :m_meshInterface(meshInterface), | |||
| m_callback(callback) | |||
| { | |||
| } | |||
| virtual void processNode(int nodeSubPart, int nodeTriangleIndex) | |||
| { | |||
| const unsigned char *vertexbase; | |||
| int numverts; | |||
| PHY_ScalarType type; | |||
| int stride; | |||
| const unsigned char *indexbase; | |||
| int indexstride; | |||
| int numfaces; | |||
| PHY_ScalarType indicestype; | |||
| m_meshInterface->getLockedReadOnlyVertexIndexBase( | |||
| &vertexbase, | |||
| numverts, | |||
| type, | |||
| stride, | |||
| &indexbase, | |||
| indexstride, | |||
| numfaces, | |||
| indicestype, | |||
| nodeSubPart); | |||
| unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride); | |||
| btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT||indicestype==PHY_UCHAR); | |||
| const btVector3& meshScaling = m_meshInterface->getScaling(); | |||
| for (int j=2;j>=0;j--) | |||
| { | |||
| int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:indicestype==PHY_INTEGER?gfxbase[j]:((unsigned char*)gfxbase)[j]; | |||
| #ifdef DEBUG_TRIANGLE_MESH | |||
| printf("%d ,",graphicsindex); | |||
| #endif //DEBUG_TRIANGLE_MESH | |||
| if (type == PHY_FLOAT) | |||
| { | |||
| float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); | |||
| m_triangle[j] = btVector3( | |||
| graphicsbase[0]*meshScaling.getX(), | |||
| graphicsbase[1]*meshScaling.getY(), | |||
| graphicsbase[2]*meshScaling.getZ()); | |||
| } | |||
| else | |||
| { | |||
| double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); | |||
| m_triangle[j] = btVector3( | |||
| btScalar(graphicsbase[0])*meshScaling.getX(), | |||
| btScalar(graphicsbase[1])*meshScaling.getY(), | |||
| btScalar(graphicsbase[2])*meshScaling.getZ()); | |||
| } | |||
| #ifdef DEBUG_TRIANGLE_MESH | |||
| printf("triangle vertices:%f,%f,%f\n",triangle[j].x(),triangle[j].y(),triangle[j].z()); | |||
| #endif //DEBUG_TRIANGLE_MESH | |||
| } | |||
| m_callback->processTriangle(m_triangle,nodeSubPart,nodeTriangleIndex); | |||
| m_meshInterface->unLockReadOnlyVertexBase(nodeSubPart); | |||
| } | |||
| }; | |||
| MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface); | |||
| m_bvh->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax); | |||
| #endif//DISABLE_BVH | |||
| } | |||
| void btBvhTriangleMeshShape::setLocalScaling(const btVector3& scaling) | |||
| { | |||
| if ((getLocalScaling() -scaling).length2() > SIMD_EPSILON) | |||
| { | |||
| btTriangleMeshShape::setLocalScaling(scaling); | |||
| buildOptimizedBvh(); | |||
| } | |||
| } | |||
| void btBvhTriangleMeshShape::buildOptimizedBvh() | |||
| { | |||
| if (m_ownsBvh) | |||
| { | |||
| m_bvh->~btOptimizedBvh(); | |||
| btAlignedFree(m_bvh); | |||
| } | |||
| ///m_localAabbMin/m_localAabbMax is already re-calculated in btTriangleMeshShape. We could just scale aabb, but this needs some more work | |||
| void* mem = btAlignedAlloc(sizeof(btOptimizedBvh),16); | |||
| m_bvh = new(mem) btOptimizedBvh(); | |||
| //rebuild the bvh... | |||
| m_bvh->build(m_meshInterface,m_useQuantizedAabbCompression,m_localAabbMin,m_localAabbMax); | |||
| m_ownsBvh = true; | |||
| } | |||
| void btBvhTriangleMeshShape::setOptimizedBvh(btOptimizedBvh* bvh, const btVector3& scaling) | |||
| { | |||
| btAssert(!m_bvh); | |||
| btAssert(!m_ownsBvh); | |||
| m_bvh = bvh; | |||
| m_ownsBvh = false; | |||
| // update the scaling without rebuilding the bvh | |||
| if ((getLocalScaling() -scaling).length2() > SIMD_EPSILON) | |||
| { | |||
| btTriangleMeshShape::setLocalScaling(scaling); | |||
| } | |||
| } | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| const char* btBvhTriangleMeshShape::serialize(void* dataBuffer, btSerializer* serializer) const | |||
| { | |||
| btTriangleMeshShapeData* trimeshData = (btTriangleMeshShapeData*) dataBuffer; | |||
| btCollisionShape::serialize(&trimeshData->m_collisionShapeData,serializer); | |||
| m_meshInterface->serialize(&trimeshData->m_meshInterface, serializer); | |||
| trimeshData->m_collisionMargin = float(m_collisionMargin); | |||
| if (m_bvh && !(serializer->getSerializationFlags()&BT_SERIALIZE_NO_BVH)) | |||
| { | |||
| void* chunk = serializer->findPointer(m_bvh); | |||
| if (chunk) | |||
| { | |||
| #ifdef BT_USE_DOUBLE_PRECISION | |||
| trimeshData->m_quantizedDoubleBvh = (btQuantizedBvhData*)chunk; | |||
| trimeshData->m_quantizedFloatBvh = 0; | |||
| #else | |||
| trimeshData->m_quantizedFloatBvh = (btQuantizedBvhData*)chunk; | |||
| trimeshData->m_quantizedDoubleBvh= 0; | |||
| #endif //BT_USE_DOUBLE_PRECISION | |||
| } else | |||
| { | |||
| #ifdef BT_USE_DOUBLE_PRECISION | |||
| trimeshData->m_quantizedDoubleBvh = (btQuantizedBvhData*)serializer->getUniquePointer(m_bvh); | |||
| trimeshData->m_quantizedFloatBvh = 0; | |||
| #else | |||
| trimeshData->m_quantizedFloatBvh = (btQuantizedBvhData*)serializer->getUniquePointer(m_bvh); | |||
| trimeshData->m_quantizedDoubleBvh= 0; | |||
| #endif //BT_USE_DOUBLE_PRECISION | |||
| int sz = m_bvh->calculateSerializeBufferSizeNew(); | |||
| btChunk* chunk = serializer->allocate(sz,1); | |||
| const char* structType = m_bvh->serialize(chunk->m_oldPtr, serializer); | |||
| serializer->finalizeChunk(chunk,structType,BT_QUANTIZED_BVH_CODE,m_bvh); | |||
| } | |||
| } else | |||
| { | |||
| trimeshData->m_quantizedFloatBvh = 0; | |||
| trimeshData->m_quantizedDoubleBvh = 0; | |||
| } | |||
| if (m_triangleInfoMap && !(serializer->getSerializationFlags()&BT_SERIALIZE_NO_TRIANGLEINFOMAP)) | |||
| { | |||
| void* chunk = serializer->findPointer(m_triangleInfoMap); | |||
| if (chunk) | |||
| { | |||
| trimeshData->m_triangleInfoMap = (btTriangleInfoMapData*)chunk; | |||
| } else | |||
| { | |||
| trimeshData->m_triangleInfoMap = (btTriangleInfoMapData*)serializer->getUniquePointer(m_triangleInfoMap); | |||
| int sz = m_triangleInfoMap->calculateSerializeBufferSize(); | |||
| btChunk* chunk = serializer->allocate(sz,1); | |||
| const char* structType = m_triangleInfoMap->serialize(chunk->m_oldPtr, serializer); | |||
| serializer->finalizeChunk(chunk,structType,BT_TRIANLGE_INFO_MAP,m_triangleInfoMap); | |||
| } | |||
| } else | |||
| { | |||
| trimeshData->m_triangleInfoMap = 0; | |||
| } | |||
| return "btTriangleMeshShapeData"; | |||
| } | |||
| void btBvhTriangleMeshShape::serializeSingleBvh(btSerializer* serializer) const | |||
| { | |||
| if (m_bvh) | |||
| { | |||
| int len = m_bvh->calculateSerializeBufferSizeNew(); //make sure not to use calculateSerializeBufferSize because it is used for in-place | |||
| btChunk* chunk = serializer->allocate(len,1); | |||
| const char* structType = m_bvh->serialize(chunk->m_oldPtr, serializer); | |||
| serializer->finalizeChunk(chunk,structType,BT_QUANTIZED_BVH_CODE,(void*)m_bvh); | |||
| } | |||
| } | |||
| void btBvhTriangleMeshShape::serializeSingleTriangleInfoMap(btSerializer* serializer) const | |||
| { | |||
| if (m_triangleInfoMap) | |||
| { | |||
| int len = m_triangleInfoMap->calculateSerializeBufferSize(); | |||
| btChunk* chunk = serializer->allocate(len,1); | |||
| const char* structType = m_triangleInfoMap->serialize(chunk->m_oldPtr, serializer); | |||
| serializer->finalizeChunk(chunk,structType,BT_TRIANLGE_INFO_MAP,(void*)m_triangleInfoMap); | |||
| } | |||
| } | |||
| @@ -0,0 +1,139 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_BVH_TRIANGLE_MESH_SHAPE_H | |||
| #define BT_BVH_TRIANGLE_MESH_SHAPE_H | |||
| #include "btTriangleMeshShape.h" | |||
| #include "btOptimizedBvh.h" | |||
| #include "LinearMath/btAlignedAllocator.h" | |||
| #include "btTriangleInfoMap.h" | |||
| ///The btBvhTriangleMeshShape is a static-triangle mesh shape with several optimizations, such as bounding volume hierarchy and cache friendly traversal for PlayStation 3 Cell SPU. It is recommended to enable useQuantizedAabbCompression for better memory usage. | |||
| ///It takes a triangle mesh as input, for example a btTriangleMesh or btTriangleIndexVertexArray. The btBvhTriangleMeshShape class allows for triangle mesh deformations by a refit or partialRefit method. | |||
| ///Instead of building the bounding volume hierarchy acceleration structure, it is also possible to serialize (save) and deserialize (load) the structure from disk. | |||
| ///See Demos\ConcaveDemo\ConcavePhysicsDemo.cpp for an example. | |||
| ATTRIBUTE_ALIGNED16(class) btBvhTriangleMeshShape : public btTriangleMeshShape | |||
| { | |||
| btOptimizedBvh* m_bvh; | |||
| btTriangleInfoMap* m_triangleInfoMap; | |||
| bool m_useQuantizedAabbCompression; | |||
| bool m_ownsBvh; | |||
| bool m_pad[11];////need padding due to alignment | |||
| public: | |||
| BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
| btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh = true); | |||
| ///optionally pass in a larger bvh aabb, used for quantization. This allows for deformations within this aabb | |||
| btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax, bool buildBvh = true); | |||
| virtual ~btBvhTriangleMeshShape(); | |||
| bool getOwnsBvh () const | |||
| { | |||
| return m_ownsBvh; | |||
| } | |||
| void performRaycast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget); | |||
| void performConvexcast (btTriangleCallback* callback, const btVector3& boxSource, const btVector3& boxTarget, const btVector3& boxMin, const btVector3& boxMax); | |||
| virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; | |||
| void refitTree(const btVector3& aabbMin,const btVector3& aabbMax); | |||
| ///for a fast incremental refit of parts of the tree. Note: the entire AABB of the tree will become more conservative, it never shrinks | |||
| void partialRefitTree(const btVector3& aabbMin,const btVector3& aabbMax); | |||
| //debugging | |||
| virtual const char* getName()const {return "BVHTRIANGLEMESH";} | |||
| virtual void setLocalScaling(const btVector3& scaling); | |||
| btOptimizedBvh* getOptimizedBvh() | |||
| { | |||
| return m_bvh; | |||
| } | |||
| void setOptimizedBvh(btOptimizedBvh* bvh, const btVector3& localScaling=btVector3(1,1,1)); | |||
| void buildOptimizedBvh(); | |||
| bool usesQuantizedAabbCompression() const | |||
| { | |||
| return m_useQuantizedAabbCompression; | |||
| } | |||
| void setTriangleInfoMap(btTriangleInfoMap* triangleInfoMap) | |||
| { | |||
| m_triangleInfoMap = triangleInfoMap; | |||
| } | |||
| const btTriangleInfoMap* getTriangleInfoMap() const | |||
| { | |||
| return m_triangleInfoMap; | |||
| } | |||
| btTriangleInfoMap* getTriangleInfoMap() | |||
| { | |||
| return m_triangleInfoMap; | |||
| } | |||
| virtual int calculateSerializeBufferSize() const; | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
| virtual void serializeSingleBvh(btSerializer* serializer) const; | |||
| virtual void serializeSingleTriangleInfoMap(btSerializer* serializer) const; | |||
| }; | |||
| ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
| struct btTriangleMeshShapeData | |||
| { | |||
| btCollisionShapeData m_collisionShapeData; | |||
| btStridingMeshInterfaceData m_meshInterface; | |||
| btQuantizedBvhFloatData *m_quantizedFloatBvh; | |||
| btQuantizedBvhDoubleData *m_quantizedDoubleBvh; | |||
| btTriangleInfoMapData *m_triangleInfoMap; | |||
| float m_collisionMargin; | |||
| char m_pad3[4]; | |||
| }; | |||
| SIMD_FORCE_INLINE int btBvhTriangleMeshShape::calculateSerializeBufferSize() const | |||
| { | |||
| return sizeof(btTriangleMeshShapeData); | |||
| } | |||
| #endif //BT_BVH_TRIANGLE_MESH_SHAPE_H | |||
| @@ -0,0 +1,171 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btCapsuleShape.h" | |||
| #include "BulletCollision/CollisionShapes/btCollisionMargin.h" | |||
| #include "LinearMath/btQuaternion.h" | |||
| btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height) : btConvexInternalShape () | |||
| { | |||
| m_shapeType = CAPSULE_SHAPE_PROXYTYPE; | |||
| m_upAxis = 1; | |||
| m_implicitShapeDimensions.setValue(radius,0.5f*height,radius); | |||
| } | |||
| btVector3 btCapsuleShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const | |||
| { | |||
| btVector3 supVec(0,0,0); | |||
| btScalar maxDot(btScalar(-BT_LARGE_FLOAT)); | |||
| btVector3 vec = vec0; | |||
| btScalar lenSqr = vec.length2(); | |||
| if (lenSqr < btScalar(0.0001)) | |||
| { | |||
| vec.setValue(1,0,0); | |||
| } else | |||
| { | |||
| btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); | |||
| vec *= rlen; | |||
| } | |||
| btVector3 vtx; | |||
| btScalar newDot; | |||
| btScalar radius = getRadius(); | |||
| { | |||
| btVector3 pos(0,0,0); | |||
| pos[getUpAxis()] = getHalfHeight(); | |||
| vtx = pos +vec*(radius) - vec * getMargin(); | |||
| newDot = vec.dot(vtx); | |||
| if (newDot > maxDot) | |||
| { | |||
| maxDot = newDot; | |||
| supVec = vtx; | |||
| } | |||
| } | |||
| { | |||
| btVector3 pos(0,0,0); | |||
| pos[getUpAxis()] = -getHalfHeight(); | |||
| vtx = pos +vec*(radius) - vec * getMargin(); | |||
| newDot = vec.dot(vtx); | |||
| if (newDot > maxDot) | |||
| { | |||
| maxDot = newDot; | |||
| supVec = vtx; | |||
| } | |||
| } | |||
| return supVec; | |||
| } | |||
| void btCapsuleShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
| { | |||
| btScalar radius = getRadius(); | |||
| for (int j=0;j<numVectors;j++) | |||
| { | |||
| btScalar maxDot(btScalar(-BT_LARGE_FLOAT)); | |||
| const btVector3& vec = vectors[j]; | |||
| btVector3 vtx; | |||
| btScalar newDot; | |||
| { | |||
| btVector3 pos(0,0,0); | |||
| pos[getUpAxis()] = getHalfHeight(); | |||
| vtx = pos +vec*(radius) - vec * getMargin(); | |||
| newDot = vec.dot(vtx); | |||
| if (newDot > maxDot) | |||
| { | |||
| maxDot = newDot; | |||
| supportVerticesOut[j] = vtx; | |||
| } | |||
| } | |||
| { | |||
| btVector3 pos(0,0,0); | |||
| pos[getUpAxis()] = -getHalfHeight(); | |||
| vtx = pos +vec*(radius) - vec * getMargin(); | |||
| newDot = vec.dot(vtx); | |||
| if (newDot > maxDot) | |||
| { | |||
| maxDot = newDot; | |||
| supportVerticesOut[j] = vtx; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| void btCapsuleShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const | |||
| { | |||
| //as an approximation, take the inertia of the box that bounds the spheres | |||
| btTransform ident; | |||
| ident.setIdentity(); | |||
| btScalar radius = getRadius(); | |||
| btVector3 halfExtents(radius,radius,radius); | |||
| halfExtents[getUpAxis()]+=getHalfHeight(); | |||
| btScalar margin = CONVEX_DISTANCE_MARGIN; | |||
| btScalar lx=btScalar(2.)*(halfExtents[0]+margin); | |||
| btScalar ly=btScalar(2.)*(halfExtents[1]+margin); | |||
| btScalar lz=btScalar(2.)*(halfExtents[2]+margin); | |||
| const btScalar x2 = lx*lx; | |||
| const btScalar y2 = ly*ly; | |||
| const btScalar z2 = lz*lz; | |||
| const btScalar scaledmass = mass * btScalar(.08333333); | |||
| inertia[0] = scaledmass * (y2+z2); | |||
| inertia[1] = scaledmass * (x2+z2); | |||
| inertia[2] = scaledmass * (x2+y2); | |||
| } | |||
| btCapsuleShapeX::btCapsuleShapeX(btScalar radius,btScalar height) | |||
| { | |||
| m_upAxis = 0; | |||
| m_implicitShapeDimensions.setValue(0.5f*height, radius,radius); | |||
| } | |||
| btCapsuleShapeZ::btCapsuleShapeZ(btScalar radius,btScalar height) | |||
| { | |||
| m_upAxis = 2; | |||
| m_implicitShapeDimensions.setValue(radius,radius,0.5f*height); | |||
| } | |||
| @@ -0,0 +1,173 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_CAPSULE_SHAPE_H | |||
| #define BT_CAPSULE_SHAPE_H | |||
| #include "btConvexInternalShape.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types | |||
| ///The btCapsuleShape represents a capsule around the Y axis, there is also the btCapsuleShapeX aligned around the X axis and btCapsuleShapeZ around the Z axis. | |||
| ///The total height is height+2*radius, so the height is just the height between the center of each 'sphere' of the capsule caps. | |||
| ///The btCapsuleShape is a convex hull of two spheres. The btMultiSphereShape is a more general collision shape that takes the convex hull of multiple sphere, so it can also represent a capsule when just using two spheres. | |||
| class btCapsuleShape : public btConvexInternalShape | |||
| { | |||
| protected: | |||
| int m_upAxis; | |||
| protected: | |||
| ///only used for btCapsuleShapeZ and btCapsuleShapeX subclasses. | |||
| btCapsuleShape() : btConvexInternalShape() {m_shapeType = CAPSULE_SHAPE_PROXYTYPE;}; | |||
| public: | |||
| btCapsuleShape(btScalar radius,btScalar height); | |||
| ///CollisionShape Interface | |||
| virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; | |||
| /// btConvexShape Interface | |||
| virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; | |||
| virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; | |||
| virtual void setMargin(btScalar collisionMargin) | |||
| { | |||
| //correct the m_implicitShapeDimensions for the margin | |||
| btVector3 oldMargin(getMargin(),getMargin(),getMargin()); | |||
| btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; | |||
| btConvexInternalShape::setMargin(collisionMargin); | |||
| btVector3 newMargin(getMargin(),getMargin(),getMargin()); | |||
| m_implicitShapeDimensions = implicitShapeDimensionsWithMargin - newMargin; | |||
| } | |||
| virtual void getAabb (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const | |||
| { | |||
| btVector3 halfExtents(getRadius(),getRadius(),getRadius()); | |||
| halfExtents[m_upAxis] = getRadius() + getHalfHeight(); | |||
| halfExtents += btVector3(getMargin(),getMargin(),getMargin()); | |||
| btMatrix3x3 abs_b = t.getBasis().absolute(); | |||
| btVector3 center = t.getOrigin(); | |||
| btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); | |||
| aabbMin = center - extent; | |||
| aabbMax = center + extent; | |||
| } | |||
| virtual const char* getName()const | |||
| { | |||
| return "CapsuleShape"; | |||
| } | |||
| int getUpAxis() const | |||
| { | |||
| return m_upAxis; | |||
| } | |||
| btScalar getRadius() const | |||
| { | |||
| int radiusAxis = (m_upAxis+2)%3; | |||
| return m_implicitShapeDimensions[radiusAxis]; | |||
| } | |||
| btScalar getHalfHeight() const | |||
| { | |||
| return m_implicitShapeDimensions[m_upAxis]; | |||
| } | |||
| virtual void setLocalScaling(const btVector3& scaling) | |||
| { | |||
| btVector3 oldMargin(getMargin(),getMargin(),getMargin()); | |||
| btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; | |||
| btVector3 unScaledImplicitShapeDimensionsWithMargin = implicitShapeDimensionsWithMargin / m_localScaling; | |||
| btConvexInternalShape::setLocalScaling(scaling); | |||
| m_implicitShapeDimensions = (unScaledImplicitShapeDimensionsWithMargin * m_localScaling) - oldMargin; | |||
| } | |||
| virtual int calculateSerializeBufferSize() const; | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
| }; | |||
| ///btCapsuleShapeX represents a capsule around the Z axis | |||
| ///the total height is height+2*radius, so the height is just the height between the center of each 'sphere' of the capsule caps. | |||
| class btCapsuleShapeX : public btCapsuleShape | |||
| { | |||
| public: | |||
| btCapsuleShapeX(btScalar radius,btScalar height); | |||
| //debugging | |||
| virtual const char* getName()const | |||
| { | |||
| return "CapsuleX"; | |||
| } | |||
| }; | |||
| ///btCapsuleShapeZ represents a capsule around the Z axis | |||
| ///the total height is height+2*radius, so the height is just the height between the center of each 'sphere' of the capsule caps. | |||
| class btCapsuleShapeZ : public btCapsuleShape | |||
| { | |||
| public: | |||
| btCapsuleShapeZ(btScalar radius,btScalar height); | |||
| //debugging | |||
| virtual const char* getName()const | |||
| { | |||
| return "CapsuleZ"; | |||
| } | |||
| }; | |||
| ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
| struct btCapsuleShapeData | |||
| { | |||
| btConvexInternalShapeData m_convexInternalShapeData; | |||
| int m_upAxis; | |||
| char m_padding[4]; | |||
| }; | |||
| SIMD_FORCE_INLINE int btCapsuleShape::calculateSerializeBufferSize() const | |||
| { | |||
| return sizeof(btCapsuleShapeData); | |||
| } | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| SIMD_FORCE_INLINE const char* btCapsuleShape::serialize(void* dataBuffer, btSerializer* serializer) const | |||
| { | |||
| btCapsuleShapeData* shapeData = (btCapsuleShapeData*) dataBuffer; | |||
| btConvexInternalShape::serialize(&shapeData->m_convexInternalShapeData,serializer); | |||
| shapeData->m_upAxis = m_upAxis; | |||
| return "btCapsuleShapeData"; | |||
| } | |||
| #endif //BT_CAPSULE_SHAPE_H | |||
| @@ -0,0 +1,27 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_COLLISION_MARGIN_H | |||
| #define BT_COLLISION_MARGIN_H | |||
| ///The CONVEX_DISTANCE_MARGIN is a default collision margin for convex collision shapes derived from btConvexInternalShape. | |||
| ///This collision margin is used by Gjk and some other algorithms | |||
| ///Note that when creating small objects, you need to make sure to set a smaller collision margin, using the 'setMargin' API | |||
| #define CONVEX_DISTANCE_MARGIN btScalar(0.04)// btScalar(0.1)//;//btScalar(0.01) | |||
| #endif //BT_COLLISION_MARGIN_H | |||
| @@ -0,0 +1,119 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "BulletCollision/CollisionShapes/btCollisionShape.h" | |||
| #include "LinearMath/btSerializer.h" | |||
| /* | |||
| Make sure this dummy function never changes so that it | |||
| can be used by probes that are checking whether the | |||
| library is actually installed. | |||
| */ | |||
| extern "C" | |||
| { | |||
| void btBulletCollisionProbe (); | |||
| void btBulletCollisionProbe () {} | |||
| } | |||
| void btCollisionShape::getBoundingSphere(btVector3& center,btScalar& radius) const | |||
| { | |||
| btTransform tr; | |||
| tr.setIdentity(); | |||
| btVector3 aabbMin,aabbMax; | |||
| getAabb(tr,aabbMin,aabbMax); | |||
| radius = (aabbMax-aabbMin).length()*btScalar(0.5); | |||
| center = (aabbMin+aabbMax)*btScalar(0.5); | |||
| } | |||
| btScalar btCollisionShape::getContactBreakingThreshold(btScalar defaultContactThreshold) const | |||
| { | |||
| return getAngularMotionDisc() * defaultContactThreshold; | |||
| } | |||
| btScalar btCollisionShape::getAngularMotionDisc() const | |||
| { | |||
| ///@todo cache this value, to improve performance | |||
| btVector3 center; | |||
| btScalar disc; | |||
| getBoundingSphere(center,disc); | |||
| disc += (center).length(); | |||
| return disc; | |||
| } | |||
| void btCollisionShape::calculateTemporalAabb(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep, btVector3& temporalAabbMin,btVector3& temporalAabbMax) const | |||
| { | |||
| //start with static aabb | |||
| getAabb(curTrans,temporalAabbMin,temporalAabbMax); | |||
| btScalar temporalAabbMaxx = temporalAabbMax.getX(); | |||
| btScalar temporalAabbMaxy = temporalAabbMax.getY(); | |||
| btScalar temporalAabbMaxz = temporalAabbMax.getZ(); | |||
| btScalar temporalAabbMinx = temporalAabbMin.getX(); | |||
| btScalar temporalAabbMiny = temporalAabbMin.getY(); | |||
| btScalar temporalAabbMinz = temporalAabbMin.getZ(); | |||
| // add linear motion | |||
| btVector3 linMotion = linvel*timeStep; | |||
| ///@todo: simd would have a vector max/min operation, instead of per-element access | |||
| if (linMotion.x() > btScalar(0.)) | |||
| temporalAabbMaxx += linMotion.x(); | |||
| else | |||
| temporalAabbMinx += linMotion.x(); | |||
| if (linMotion.y() > btScalar(0.)) | |||
| temporalAabbMaxy += linMotion.y(); | |||
| else | |||
| temporalAabbMiny += linMotion.y(); | |||
| if (linMotion.z() > btScalar(0.)) | |||
| temporalAabbMaxz += linMotion.z(); | |||
| else | |||
| temporalAabbMinz += linMotion.z(); | |||
| //add conservative angular motion | |||
| btScalar angularMotion = angvel.length() * getAngularMotionDisc() * timeStep; | |||
| btVector3 angularMotion3d(angularMotion,angularMotion,angularMotion); | |||
| temporalAabbMin = btVector3(temporalAabbMinx,temporalAabbMiny,temporalAabbMinz); | |||
| temporalAabbMax = btVector3(temporalAabbMaxx,temporalAabbMaxy,temporalAabbMaxz); | |||
| temporalAabbMin -= angularMotion3d; | |||
| temporalAabbMax += angularMotion3d; | |||
| } | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| const char* btCollisionShape::serialize(void* dataBuffer, btSerializer* serializer) const | |||
| { | |||
| btCollisionShapeData* shapeData = (btCollisionShapeData*) dataBuffer; | |||
| char* name = (char*) serializer->findNameForPointer(this); | |||
| shapeData->m_name = (char*)serializer->getUniquePointer(name); | |||
| if (shapeData->m_name) | |||
| { | |||
| serializer->serializeName(name); | |||
| } | |||
| shapeData->m_shapeType = m_shapeType; | |||
| //shapeData->m_padding//?? | |||
| return "btCollisionShapeData"; | |||
| } | |||
| void btCollisionShape::serializeSingleShape(btSerializer* serializer) const | |||
| { | |||
| int len = calculateSerializeBufferSize(); | |||
| btChunk* chunk = serializer->allocate(len,1); | |||
| const char* structType = serialize(chunk->m_oldPtr, serializer); | |||
| serializer->finalizeChunk(chunk,structType,BT_SHAPE_CODE,(void*)this); | |||
| } | |||
| @@ -0,0 +1,150 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_COLLISION_SHAPE_H | |||
| #define BT_COLLISION_SHAPE_H | |||
| #include "LinearMath/btTransform.h" | |||
| #include "LinearMath/btVector3.h" | |||
| #include "LinearMath/btMatrix3x3.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" //for the shape types | |||
| class btSerializer; | |||
| ///The btCollisionShape class provides an interface for collision shapes that can be shared among btCollisionObjects. | |||
| class btCollisionShape | |||
| { | |||
| protected: | |||
| int m_shapeType; | |||
| void* m_userPointer; | |||
| public: | |||
| btCollisionShape() : m_shapeType (INVALID_SHAPE_PROXYTYPE), m_userPointer(0) | |||
| { | |||
| } | |||
| virtual ~btCollisionShape() | |||
| { | |||
| } | |||
| ///getAabb returns the axis aligned bounding box in the coordinate frame of the given transform t. | |||
| virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const =0; | |||
| virtual void getBoundingSphere(btVector3& center,btScalar& radius) const; | |||
| ///getAngularMotionDisc returns the maximus radius needed for Conservative Advancement to handle time-of-impact with rotations. | |||
| virtual btScalar getAngularMotionDisc() const; | |||
| virtual btScalar getContactBreakingThreshold(btScalar defaultContactThresholdFactor) const; | |||
| ///calculateTemporalAabb calculates the enclosing aabb for the moving object over interval [0..timeStep) | |||
| ///result is conservative | |||
| void calculateTemporalAabb(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep, btVector3& temporalAabbMin,btVector3& temporalAabbMax) const; | |||
| SIMD_FORCE_INLINE bool isPolyhedral() const | |||
| { | |||
| return btBroadphaseProxy::isPolyhedral(getShapeType()); | |||
| } | |||
| SIMD_FORCE_INLINE bool isConvex2d() const | |||
| { | |||
| return btBroadphaseProxy::isConvex2d(getShapeType()); | |||
| } | |||
| SIMD_FORCE_INLINE bool isConvex() const | |||
| { | |||
| return btBroadphaseProxy::isConvex(getShapeType()); | |||
| } | |||
| SIMD_FORCE_INLINE bool isNonMoving() const | |||
| { | |||
| return btBroadphaseProxy::isNonMoving(getShapeType()); | |||
| } | |||
| SIMD_FORCE_INLINE bool isConcave() const | |||
| { | |||
| return btBroadphaseProxy::isConcave(getShapeType()); | |||
| } | |||
| SIMD_FORCE_INLINE bool isCompound() const | |||
| { | |||
| return btBroadphaseProxy::isCompound(getShapeType()); | |||
| } | |||
| SIMD_FORCE_INLINE bool isSoftBody() const | |||
| { | |||
| return btBroadphaseProxy::isSoftBody(getShapeType()); | |||
| } | |||
| ///isInfinite is used to catch simulation error (aabb check) | |||
| SIMD_FORCE_INLINE bool isInfinite() const | |||
| { | |||
| return btBroadphaseProxy::isInfinite(getShapeType()); | |||
| } | |||
| #ifndef __SPU__ | |||
| virtual void setLocalScaling(const btVector3& scaling) =0; | |||
| virtual const btVector3& getLocalScaling() const =0; | |||
| virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const = 0; | |||
| //debugging support | |||
| virtual const char* getName()const =0 ; | |||
| #endif //__SPU__ | |||
| int getShapeType() const { return m_shapeType; } | |||
| virtual void setMargin(btScalar margin) = 0; | |||
| virtual btScalar getMargin() const = 0; | |||
| ///optional user data pointer | |||
| void setUserPointer(void* userPtr) | |||
| { | |||
| m_userPointer = userPtr; | |||
| } | |||
| void* getUserPointer() const | |||
| { | |||
| return m_userPointer; | |||
| } | |||
| virtual int calculateSerializeBufferSize() const; | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
| virtual void serializeSingleShape(btSerializer* serializer) const; | |||
| }; | |||
| ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
| struct btCollisionShapeData | |||
| { | |||
| char *m_name; | |||
| int m_shapeType; | |||
| char m_padding[4]; | |||
| }; | |||
| SIMD_FORCE_INLINE int btCollisionShape::calculateSerializeBufferSize() const | |||
| { | |||
| return sizeof(btCollisionShapeData); | |||
| } | |||
| #endif //BT_COLLISION_SHAPE_H | |||
| @@ -0,0 +1,356 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btCompoundShape.h" | |||
| #include "btCollisionShape.h" | |||
| #include "BulletCollision/BroadphaseCollision/btDbvt.h" | |||
| #include "LinearMath/btSerializer.h" | |||
| btCompoundShape::btCompoundShape(bool enableDynamicAabbTree) | |||
| : m_localAabbMin(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)), | |||
| m_localAabbMax(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)), | |||
| m_dynamicAabbTree(0), | |||
| m_updateRevision(1), | |||
| m_collisionMargin(btScalar(0.)), | |||
| m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.)) | |||
| { | |||
| m_shapeType = COMPOUND_SHAPE_PROXYTYPE; | |||
| if (enableDynamicAabbTree) | |||
| { | |||
| void* mem = btAlignedAlloc(sizeof(btDbvt),16); | |||
| m_dynamicAabbTree = new(mem) btDbvt(); | |||
| btAssert(mem==m_dynamicAabbTree); | |||
| } | |||
| } | |||
| btCompoundShape::~btCompoundShape() | |||
| { | |||
| if (m_dynamicAabbTree) | |||
| { | |||
| m_dynamicAabbTree->~btDbvt(); | |||
| btAlignedFree(m_dynamicAabbTree); | |||
| } | |||
| } | |||
| void btCompoundShape::addChildShape(const btTransform& localTransform,btCollisionShape* shape) | |||
| { | |||
| m_updateRevision++; | |||
| //m_childTransforms.push_back(localTransform); | |||
| //m_childShapes.push_back(shape); | |||
| btCompoundShapeChild child; | |||
| child.m_node = 0; | |||
| child.m_transform = localTransform; | |||
| child.m_childShape = shape; | |||
| child.m_childShapeType = shape->getShapeType(); | |||
| child.m_childMargin = shape->getMargin(); | |||
| //extend the local aabbMin/aabbMax | |||
| btVector3 localAabbMin,localAabbMax; | |||
| shape->getAabb(localTransform,localAabbMin,localAabbMax); | |||
| for (int i=0;i<3;i++) | |||
| { | |||
| if (m_localAabbMin[i] > localAabbMin[i]) | |||
| { | |||
| m_localAabbMin[i] = localAabbMin[i]; | |||
| } | |||
| if (m_localAabbMax[i] < localAabbMax[i]) | |||
| { | |||
| m_localAabbMax[i] = localAabbMax[i]; | |||
| } | |||
| } | |||
| if (m_dynamicAabbTree) | |||
| { | |||
| const btDbvtVolume bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); | |||
| int index = m_children.size(); | |||
| child.m_node = m_dynamicAabbTree->insert(bounds,(void*)index); | |||
| } | |||
| m_children.push_back(child); | |||
| } | |||
| void btCompoundShape::updateChildTransform(int childIndex, const btTransform& newChildTransform,bool shouldRecalculateLocalAabb) | |||
| { | |||
| m_children[childIndex].m_transform = newChildTransform; | |||
| if (m_dynamicAabbTree) | |||
| { | |||
| ///update the dynamic aabb tree | |||
| btVector3 localAabbMin,localAabbMax; | |||
| m_children[childIndex].m_childShape->getAabb(newChildTransform,localAabbMin,localAabbMax); | |||
| ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); | |||
| //int index = m_children.size()-1; | |||
| m_dynamicAabbTree->update(m_children[childIndex].m_node,bounds); | |||
| } | |||
| if (shouldRecalculateLocalAabb) | |||
| { | |||
| recalculateLocalAabb(); | |||
| } | |||
| } | |||
| void btCompoundShape::removeChildShapeByIndex(int childShapeIndex) | |||
| { | |||
| m_updateRevision++; | |||
| btAssert(childShapeIndex >=0 && childShapeIndex < m_children.size()); | |||
| if (m_dynamicAabbTree) | |||
| { | |||
| m_dynamicAabbTree->remove(m_children[childShapeIndex].m_node); | |||
| } | |||
| m_children.swap(childShapeIndex,m_children.size()-1); | |||
| if (m_dynamicAabbTree) | |||
| m_children[childShapeIndex].m_node->dataAsInt = childShapeIndex; | |||
| m_children.pop_back(); | |||
| } | |||
| void btCompoundShape::removeChildShape(btCollisionShape* shape) | |||
| { | |||
| m_updateRevision++; | |||
| // Find the children containing the shape specified, and remove those children. | |||
| //note: there might be multiple children using the same shape! | |||
| for(int i = m_children.size()-1; i >= 0 ; i--) | |||
| { | |||
| if(m_children[i].m_childShape == shape) | |||
| { | |||
| removeChildShapeByIndex(i); | |||
| } | |||
| } | |||
| recalculateLocalAabb(); | |||
| } | |||
| void btCompoundShape::recalculateLocalAabb() | |||
| { | |||
| // Recalculate the local aabb | |||
| // Brute force, it iterates over all the shapes left. | |||
| m_localAabbMin = btVector3(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); | |||
| m_localAabbMax = btVector3(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); | |||
| //extend the local aabbMin/aabbMax | |||
| for (int j = 0; j < m_children.size(); j++) | |||
| { | |||
| btVector3 localAabbMin,localAabbMax; | |||
| m_children[j].m_childShape->getAabb(m_children[j].m_transform, localAabbMin, localAabbMax); | |||
| for (int i=0;i<3;i++) | |||
| { | |||
| if (m_localAabbMin[i] > localAabbMin[i]) | |||
| m_localAabbMin[i] = localAabbMin[i]; | |||
| if (m_localAabbMax[i] < localAabbMax[i]) | |||
| m_localAabbMax[i] = localAabbMax[i]; | |||
| } | |||
| } | |||
| } | |||
| ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version | |||
| void btCompoundShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const | |||
| { | |||
| btVector3 localHalfExtents = btScalar(0.5)*(m_localAabbMax-m_localAabbMin); | |||
| btVector3 localCenter = btScalar(0.5)*(m_localAabbMax+m_localAabbMin); | |||
| //avoid an illegal AABB when there are no children | |||
| if (!m_children.size()) | |||
| { | |||
| localHalfExtents.setValue(0,0,0); | |||
| localCenter.setValue(0,0,0); | |||
| } | |||
| localHalfExtents += btVector3(getMargin(),getMargin(),getMargin()); | |||
| btMatrix3x3 abs_b = trans.getBasis().absolute(); | |||
| btVector3 center = trans(localCenter); | |||
| btVector3 extent = btVector3(abs_b[0].dot(localHalfExtents), | |||
| abs_b[1].dot(localHalfExtents), | |||
| abs_b[2].dot(localHalfExtents)); | |||
| aabbMin = center-extent; | |||
| aabbMax = center+extent; | |||
| } | |||
| void btCompoundShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const | |||
| { | |||
| //approximation: take the inertia from the aabb for now | |||
| btTransform ident; | |||
| ident.setIdentity(); | |||
| btVector3 aabbMin,aabbMax; | |||
| getAabb(ident,aabbMin,aabbMax); | |||
| btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5); | |||
| btScalar lx=btScalar(2.)*(halfExtents.x()); | |||
| btScalar ly=btScalar(2.)*(halfExtents.y()); | |||
| btScalar lz=btScalar(2.)*(halfExtents.z()); | |||
| inertia[0] = mass/(btScalar(12.0)) * (ly*ly + lz*lz); | |||
| inertia[1] = mass/(btScalar(12.0)) * (lx*lx + lz*lz); | |||
| inertia[2] = mass/(btScalar(12.0)) * (lx*lx + ly*ly); | |||
| } | |||
| void btCompoundShape::calculatePrincipalAxisTransform(btScalar* masses, btTransform& principal, btVector3& inertia) const | |||
| { | |||
| int n = m_children.size(); | |||
| btScalar totalMass = 0; | |||
| btVector3 center(0, 0, 0); | |||
| int k; | |||
| for (k = 0; k < n; k++) | |||
| { | |||
| btAssert(masses[k]>0); | |||
| center += m_children[k].m_transform.getOrigin() * masses[k]; | |||
| totalMass += masses[k]; | |||
| } | |||
| btAssert(totalMass>0); | |||
| center /= totalMass; | |||
| principal.setOrigin(center); | |||
| btMatrix3x3 tensor(0, 0, 0, 0, 0, 0, 0, 0, 0); | |||
| for ( k = 0; k < n; k++) | |||
| { | |||
| btVector3 i; | |||
| m_children[k].m_childShape->calculateLocalInertia(masses[k], i); | |||
| const btTransform& t = m_children[k].m_transform; | |||
| btVector3 o = t.getOrigin() - center; | |||
| //compute inertia tensor in coordinate system of compound shape | |||
| btMatrix3x3 j = t.getBasis().transpose(); | |||
| j[0] *= i[0]; | |||
| j[1] *= i[1]; | |||
| j[2] *= i[2]; | |||
| j = t.getBasis() * j; | |||
| //add inertia tensor | |||
| tensor[0] += j[0]; | |||
| tensor[1] += j[1]; | |||
| tensor[2] += j[2]; | |||
| //compute inertia tensor of pointmass at o | |||
| btScalar o2 = o.length2(); | |||
| j[0].setValue(o2, 0, 0); | |||
| j[1].setValue(0, o2, 0); | |||
| j[2].setValue(0, 0, o2); | |||
| j[0] += o * -o.x(); | |||
| j[1] += o * -o.y(); | |||
| j[2] += o * -o.z(); | |||
| //add inertia tensor of pointmass | |||
| tensor[0] += masses[k] * j[0]; | |||
| tensor[1] += masses[k] * j[1]; | |||
| tensor[2] += masses[k] * j[2]; | |||
| } | |||
| tensor.diagonalize(principal.getBasis(), btScalar(0.00001), 20); | |||
| inertia.setValue(tensor[0][0], tensor[1][1], tensor[2][2]); | |||
| } | |||
| void btCompoundShape::setLocalScaling(const btVector3& scaling) | |||
| { | |||
| for(int i = 0; i < m_children.size(); i++) | |||
| { | |||
| btTransform childTrans = getChildTransform(i); | |||
| btVector3 childScale = m_children[i].m_childShape->getLocalScaling(); | |||
| // childScale = childScale * (childTrans.getBasis() * scaling); | |||
| childScale = childScale * scaling / m_localScaling; | |||
| m_children[i].m_childShape->setLocalScaling(childScale); | |||
| childTrans.setOrigin((childTrans.getOrigin())*scaling); | |||
| updateChildTransform(i, childTrans,false); | |||
| } | |||
| m_localScaling = scaling; | |||
| recalculateLocalAabb(); | |||
| } | |||
| void btCompoundShape::createAabbTreeFromChildren() | |||
| { | |||
| if ( !m_dynamicAabbTree ) | |||
| { | |||
| void* mem = btAlignedAlloc(sizeof(btDbvt),16); | |||
| m_dynamicAabbTree = new(mem) btDbvt(); | |||
| btAssert(mem==m_dynamicAabbTree); | |||
| for ( int index = 0; index < m_children.size(); index++ ) | |||
| { | |||
| btCompoundShapeChild &child = m_children[index]; | |||
| //extend the local aabbMin/aabbMax | |||
| btVector3 localAabbMin,localAabbMax; | |||
| child.m_childShape->getAabb(child.m_transform,localAabbMin,localAabbMax); | |||
| const btDbvtVolume bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); | |||
| child.m_node = m_dynamicAabbTree->insert(bounds,(void*)index); | |||
| } | |||
| } | |||
| } | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| const char* btCompoundShape::serialize(void* dataBuffer, btSerializer* serializer) const | |||
| { | |||
| btCompoundShapeData* shapeData = (btCompoundShapeData*) dataBuffer; | |||
| btCollisionShape::serialize(&shapeData->m_collisionShapeData, serializer); | |||
| shapeData->m_collisionMargin = float(m_collisionMargin); | |||
| shapeData->m_numChildShapes = m_children.size(); | |||
| shapeData->m_childShapePtr = 0; | |||
| if (shapeData->m_numChildShapes) | |||
| { | |||
| btChunk* chunk = serializer->allocate(sizeof(btCompoundShapeChildData),shapeData->m_numChildShapes); | |||
| btCompoundShapeChildData* memPtr = (btCompoundShapeChildData*)chunk->m_oldPtr; | |||
| shapeData->m_childShapePtr = (btCompoundShapeChildData*)serializer->getUniquePointer(memPtr); | |||
| for (int i=0;i<shapeData->m_numChildShapes;i++,memPtr++) | |||
| { | |||
| memPtr->m_childMargin = float(m_children[i].m_childMargin); | |||
| memPtr->m_childShape = (btCollisionShapeData*)serializer->getUniquePointer(m_children[i].m_childShape); | |||
| //don't serialize shapes that already have been serialized | |||
| if (!serializer->findPointer(m_children[i].m_childShape)) | |||
| { | |||
| btChunk* chunk = serializer->allocate(m_children[i].m_childShape->calculateSerializeBufferSize(),1); | |||
| const char* structType = m_children[i].m_childShape->serialize(chunk->m_oldPtr,serializer); | |||
| serializer->finalizeChunk(chunk,structType,BT_SHAPE_CODE,m_children[i].m_childShape); | |||
| } | |||
| memPtr->m_childShapeType = m_children[i].m_childShapeType; | |||
| m_children[i].m_transform.serializeFloat(memPtr->m_transform); | |||
| } | |||
| serializer->finalizeChunk(chunk,"btCompoundShapeChildData",BT_ARRAY_CODE,chunk->m_oldPtr); | |||
| } | |||
| return "btCompoundShapeData"; | |||
| } | |||
| @@ -0,0 +1,212 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_COMPOUND_SHAPE_H | |||
| #define BT_COMPOUND_SHAPE_H | |||
| #include "btCollisionShape.h" | |||
| #include "LinearMath/btVector3.h" | |||
| #include "LinearMath/btTransform.h" | |||
| #include "LinearMath/btMatrix3x3.h" | |||
| #include "btCollisionMargin.h" | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| //class btOptimizedBvh; | |||
| struct btDbvt; | |||
| ATTRIBUTE_ALIGNED16(struct) btCompoundShapeChild | |||
| { | |||
| BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
| btTransform m_transform; | |||
| btCollisionShape* m_childShape; | |||
| int m_childShapeType; | |||
| btScalar m_childMargin; | |||
| struct btDbvtNode* m_node; | |||
| }; | |||
| SIMD_FORCE_INLINE bool operator==(const btCompoundShapeChild& c1, const btCompoundShapeChild& c2) | |||
| { | |||
| return ( c1.m_transform == c2.m_transform && | |||
| c1.m_childShape == c2.m_childShape && | |||
| c1.m_childShapeType == c2.m_childShapeType && | |||
| c1.m_childMargin == c2.m_childMargin ); | |||
| } | |||
| /// The btCompoundShape allows to store multiple other btCollisionShapes | |||
| /// This allows for moving concave collision objects. This is more general then the static concave btBvhTriangleMeshShape. | |||
| /// It has an (optional) dynamic aabb tree to accelerate early rejection tests. | |||
| /// @todo: This aabb tree can also be use to speed up ray tests on btCompoundShape, see http://code.google.com/p/bullet/issues/detail?id=25 | |||
| /// Currently, removal of child shapes is only supported when disabling the aabb tree (pass 'false' in the constructor of btCompoundShape) | |||
| ATTRIBUTE_ALIGNED16(class) btCompoundShape : public btCollisionShape | |||
| { | |||
| btAlignedObjectArray<btCompoundShapeChild> m_children; | |||
| btVector3 m_localAabbMin; | |||
| btVector3 m_localAabbMax; | |||
| btDbvt* m_dynamicAabbTree; | |||
| ///increment m_updateRevision when adding/removing/replacing child shapes, so that some caches can be updated | |||
| int m_updateRevision; | |||
| btScalar m_collisionMargin; | |||
| protected: | |||
| btVector3 m_localScaling; | |||
| public: | |||
| BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
| btCompoundShape(bool enableDynamicAabbTree = true); | |||
| virtual ~btCompoundShape(); | |||
| void addChildShape(const btTransform& localTransform,btCollisionShape* shape); | |||
| /// Remove all children shapes that contain the specified shape | |||
| virtual void removeChildShape(btCollisionShape* shape); | |||
| void removeChildShapeByIndex(int childShapeindex); | |||
| int getNumChildShapes() const | |||
| { | |||
| return int (m_children.size()); | |||
| } | |||
| btCollisionShape* getChildShape(int index) | |||
| { | |||
| return m_children[index].m_childShape; | |||
| } | |||
| const btCollisionShape* getChildShape(int index) const | |||
| { | |||
| return m_children[index].m_childShape; | |||
| } | |||
| btTransform& getChildTransform(int index) | |||
| { | |||
| return m_children[index].m_transform; | |||
| } | |||
| const btTransform& getChildTransform(int index) const | |||
| { | |||
| return m_children[index].m_transform; | |||
| } | |||
| ///set a new transform for a child, and update internal data structures (local aabb and dynamic tree) | |||
| void updateChildTransform(int childIndex, const btTransform& newChildTransform, bool shouldRecalculateLocalAabb = true); | |||
| btCompoundShapeChild* getChildList() | |||
| { | |||
| return &m_children[0]; | |||
| } | |||
| ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version | |||
| virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
| /** Re-calculate the local Aabb. Is called at the end of removeChildShapes. | |||
| Use this yourself if you modify the children or their transforms. */ | |||
| virtual void recalculateLocalAabb(); | |||
| virtual void setLocalScaling(const btVector3& scaling); | |||
| virtual const btVector3& getLocalScaling() const | |||
| { | |||
| return m_localScaling; | |||
| } | |||
| virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; | |||
| virtual void setMargin(btScalar margin) | |||
| { | |||
| m_collisionMargin = margin; | |||
| } | |||
| virtual btScalar getMargin() const | |||
| { | |||
| return m_collisionMargin; | |||
| } | |||
| virtual const char* getName()const | |||
| { | |||
| return "Compound"; | |||
| } | |||
| const btDbvt* getDynamicAabbTree() const | |||
| { | |||
| return m_dynamicAabbTree; | |||
| } | |||
| btDbvt* getDynamicAabbTree() | |||
| { | |||
| return m_dynamicAabbTree; | |||
| } | |||
| void createAabbTreeFromChildren(); | |||
| ///computes the exact moment of inertia and the transform from the coordinate system defined by the principal axes of the moment of inertia | |||
| ///and the center of mass to the current coordinate system. "masses" points to an array of masses of the children. The resulting transform | |||
| ///"principal" has to be applied inversely to all children transforms in order for the local coordinate system of the compound | |||
| ///shape to be centered at the center of mass and to coincide with the principal axes. This also necessitates a correction of the world transform | |||
| ///of the collision object by the principal transform. | |||
| void calculatePrincipalAxisTransform(btScalar* masses, btTransform& principal, btVector3& inertia) const; | |||
| int getUpdateRevision() const | |||
| { | |||
| return m_updateRevision; | |||
| } | |||
| virtual int calculateSerializeBufferSize() const; | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
| }; | |||
| ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
| struct btCompoundShapeChildData | |||
| { | |||
| btTransformFloatData m_transform; | |||
| btCollisionShapeData *m_childShape; | |||
| int m_childShapeType; | |||
| float m_childMargin; | |||
| }; | |||
| ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
| struct btCompoundShapeData | |||
| { | |||
| btCollisionShapeData m_collisionShapeData; | |||
| btCompoundShapeChildData *m_childShapePtr; | |||
| int m_numChildShapes; | |||
| float m_collisionMargin; | |||
| }; | |||
| SIMD_FORCE_INLINE int btCompoundShape::calculateSerializeBufferSize() const | |||
| { | |||
| return sizeof(btCompoundShapeData); | |||
| } | |||
| #endif //BT_COMPOUND_SHAPE_H | |||
| @@ -0,0 +1,27 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btConcaveShape.h" | |||
| btConcaveShape::btConcaveShape() : m_collisionMargin(btScalar(0.)) | |||
| { | |||
| } | |||
| btConcaveShape::~btConcaveShape() | |||
| { | |||
| } | |||
| @@ -0,0 +1,60 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_CONCAVE_SHAPE_H | |||
| #define BT_CONCAVE_SHAPE_H | |||
| #include "btCollisionShape.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types | |||
| #include "btTriangleCallback.h" | |||
| /// PHY_ScalarType enumerates possible scalar types. | |||
| /// See the btStridingMeshInterface or btHeightfieldTerrainShape for its use | |||
| typedef enum PHY_ScalarType { | |||
| PHY_FLOAT, | |||
| PHY_DOUBLE, | |||
| PHY_INTEGER, | |||
| PHY_SHORT, | |||
| PHY_FIXEDPOINT88, | |||
| PHY_UCHAR | |||
| } PHY_ScalarType; | |||
| ///The btConcaveShape class provides an interface for non-moving (static) concave shapes. | |||
| ///It has been implemented by the btStaticPlaneShape, btBvhTriangleMeshShape and btHeightfieldTerrainShape. | |||
| class btConcaveShape : public btCollisionShape | |||
| { | |||
| protected: | |||
| btScalar m_collisionMargin; | |||
| public: | |||
| btConcaveShape(); | |||
| virtual ~btConcaveShape(); | |||
| virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const = 0; | |||
| virtual btScalar getMargin() const { | |||
| return m_collisionMargin; | |||
| } | |||
| virtual void setMargin(btScalar collisionMargin) | |||
| { | |||
| m_collisionMargin = collisionMargin; | |||
| } | |||
| }; | |||
| #endif //BT_CONCAVE_SHAPE_H | |||
| @@ -0,0 +1,143 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btConeShape.h" | |||
| btConeShape::btConeShape (btScalar radius,btScalar height): btConvexInternalShape (), | |||
| m_radius (radius), | |||
| m_height(height) | |||
| { | |||
| m_shapeType = CONE_SHAPE_PROXYTYPE; | |||
| setConeUpIndex(1); | |||
| btVector3 halfExtents; | |||
| m_sinAngle = (m_radius / btSqrt(m_radius * m_radius + m_height * m_height)); | |||
| } | |||
| btConeShapeZ::btConeShapeZ (btScalar radius,btScalar height): | |||
| btConeShape(radius,height) | |||
| { | |||
| setConeUpIndex(2); | |||
| } | |||
| btConeShapeX::btConeShapeX (btScalar radius,btScalar height): | |||
| btConeShape(radius,height) | |||
| { | |||
| setConeUpIndex(0); | |||
| } | |||
| ///choose upAxis index | |||
| void btConeShape::setConeUpIndex(int upIndex) | |||
| { | |||
| switch (upIndex) | |||
| { | |||
| case 0: | |||
| m_coneIndices[0] = 1; | |||
| m_coneIndices[1] = 0; | |||
| m_coneIndices[2] = 2; | |||
| break; | |||
| case 1: | |||
| m_coneIndices[0] = 0; | |||
| m_coneIndices[1] = 1; | |||
| m_coneIndices[2] = 2; | |||
| break; | |||
| case 2: | |||
| m_coneIndices[0] = 0; | |||
| m_coneIndices[1] = 2; | |||
| m_coneIndices[2] = 1; | |||
| break; | |||
| default: | |||
| btAssert(0); | |||
| }; | |||
| } | |||
| btVector3 btConeShape::coneLocalSupport(const btVector3& v) const | |||
| { | |||
| btScalar halfHeight = m_height * btScalar(0.5); | |||
| if (v[m_coneIndices[1]] > v.length() * m_sinAngle) | |||
| { | |||
| btVector3 tmp; | |||
| tmp[m_coneIndices[0]] = btScalar(0.); | |||
| tmp[m_coneIndices[1]] = halfHeight; | |||
| tmp[m_coneIndices[2]] = btScalar(0.); | |||
| return tmp; | |||
| } | |||
| else { | |||
| btScalar s = btSqrt(v[m_coneIndices[0]] * v[m_coneIndices[0]] + v[m_coneIndices[2]] * v[m_coneIndices[2]]); | |||
| if (s > SIMD_EPSILON) { | |||
| btScalar d = m_radius / s; | |||
| btVector3 tmp; | |||
| tmp[m_coneIndices[0]] = v[m_coneIndices[0]] * d; | |||
| tmp[m_coneIndices[1]] = -halfHeight; | |||
| tmp[m_coneIndices[2]] = v[m_coneIndices[2]] * d; | |||
| return tmp; | |||
| } | |||
| else { | |||
| btVector3 tmp; | |||
| tmp[m_coneIndices[0]] = btScalar(0.); | |||
| tmp[m_coneIndices[1]] = -halfHeight; | |||
| tmp[m_coneIndices[2]] = btScalar(0.); | |||
| return tmp; | |||
| } | |||
| } | |||
| } | |||
| btVector3 btConeShape::localGetSupportingVertexWithoutMargin(const btVector3& vec) const | |||
| { | |||
| return coneLocalSupport(vec); | |||
| } | |||
| void btConeShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
| { | |||
| for (int i=0;i<numVectors;i++) | |||
| { | |||
| const btVector3& vec = vectors[i]; | |||
| supportVerticesOut[i] = coneLocalSupport(vec); | |||
| } | |||
| } | |||
| btVector3 btConeShape::localGetSupportingVertex(const btVector3& vec) const | |||
| { | |||
| btVector3 supVertex = coneLocalSupport(vec); | |||
| if ( getMargin()!=btScalar(0.) ) | |||
| { | |||
| btVector3 vecnorm = vec; | |||
| if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) | |||
| { | |||
| vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); | |||
| } | |||
| vecnorm.normalize(); | |||
| supVertex+= getMargin() * vecnorm; | |||
| } | |||
| return supVertex; | |||
| } | |||
| void btConeShape::setLocalScaling(const btVector3& scaling) | |||
| { | |||
| int axis = m_coneIndices[1]; | |||
| int r1 = m_coneIndices[0]; | |||
| int r2 = m_coneIndices[2]; | |||
| m_height *= scaling[axis] / m_localScaling[axis]; | |||
| m_radius *= (scaling[r1] / m_localScaling[r1] + scaling[r2] / m_localScaling[r2]) / 2; | |||
| m_sinAngle = (m_radius / btSqrt(m_radius * m_radius + m_height * m_height)); | |||
| btConvexInternalShape::setLocalScaling(scaling); | |||
| } | |||
| @@ -0,0 +1,103 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_CONE_MINKOWSKI_H | |||
| #define BT_CONE_MINKOWSKI_H | |||
| #include "btConvexInternalShape.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types | |||
| ///The btConeShape implements a cone shape primitive, centered around the origin and aligned with the Y axis. The btConeShapeX is aligned around the X axis and btConeShapeZ around the Z axis. | |||
| class btConeShape : public btConvexInternalShape | |||
| { | |||
| btScalar m_sinAngle; | |||
| btScalar m_radius; | |||
| btScalar m_height; | |||
| int m_coneIndices[3]; | |||
| btVector3 coneLocalSupport(const btVector3& v) const; | |||
| public: | |||
| btConeShape (btScalar radius,btScalar height); | |||
| virtual btVector3 localGetSupportingVertex(const btVector3& vec) const; | |||
| virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec) const; | |||
| virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; | |||
| btScalar getRadius() const { return m_radius;} | |||
| btScalar getHeight() const { return m_height;} | |||
| virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const | |||
| { | |||
| btTransform identity; | |||
| identity.setIdentity(); | |||
| btVector3 aabbMin,aabbMax; | |||
| getAabb(identity,aabbMin,aabbMax); | |||
| btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5); | |||
| btScalar margin = getMargin(); | |||
| btScalar lx=btScalar(2.)*(halfExtents.x()+margin); | |||
| btScalar ly=btScalar(2.)*(halfExtents.y()+margin); | |||
| btScalar lz=btScalar(2.)*(halfExtents.z()+margin); | |||
| const btScalar x2 = lx*lx; | |||
| const btScalar y2 = ly*ly; | |||
| const btScalar z2 = lz*lz; | |||
| const btScalar scaledmass = mass * btScalar(0.08333333); | |||
| inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2)); | |||
| // inertia.x() = scaledmass * (y2+z2); | |||
| // inertia.y() = scaledmass * (x2+z2); | |||
| // inertia.z() = scaledmass * (x2+y2); | |||
| } | |||
| virtual const char* getName()const | |||
| { | |||
| return "Cone"; | |||
| } | |||
| ///choose upAxis index | |||
| void setConeUpIndex(int upIndex); | |||
| int getConeUpIndex() const | |||
| { | |||
| return m_coneIndices[1]; | |||
| } | |||
| virtual void setLocalScaling(const btVector3& scaling); | |||
| }; | |||
| ///btConeShape implements a Cone shape, around the X axis | |||
| class btConeShapeX : public btConeShape | |||
| { | |||
| public: | |||
| btConeShapeX(btScalar radius,btScalar height); | |||
| }; | |||
| ///btConeShapeZ implements a Cone shape, around the Z axis | |||
| class btConeShapeZ : public btConeShape | |||
| { | |||
| public: | |||
| btConeShapeZ(btScalar radius,btScalar height); | |||
| }; | |||
| #endif //BT_CONE_MINKOWSKI_H | |||
| @@ -0,0 +1,92 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btConvex2dShape.h" | |||
| btConvex2dShape::btConvex2dShape( btConvexShape* convexChildShape): | |||
| btConvexShape (), m_childConvexShape(convexChildShape) | |||
| { | |||
| m_shapeType = CONVEX_2D_SHAPE_PROXYTYPE; | |||
| } | |||
| btConvex2dShape::~btConvex2dShape() | |||
| { | |||
| } | |||
| btVector3 btConvex2dShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const | |||
| { | |||
| return m_childConvexShape->localGetSupportingVertexWithoutMargin(vec); | |||
| } | |||
| void btConvex2dShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
| { | |||
| m_childConvexShape->batchedUnitVectorGetSupportingVertexWithoutMargin(vectors,supportVerticesOut,numVectors); | |||
| } | |||
| btVector3 btConvex2dShape::localGetSupportingVertex(const btVector3& vec)const | |||
| { | |||
| return m_childConvexShape->localGetSupportingVertex(vec); | |||
| } | |||
| void btConvex2dShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const | |||
| { | |||
| ///this linear upscaling is not realistic, but we don't deal with large mass ratios... | |||
| m_childConvexShape->calculateLocalInertia(mass,inertia); | |||
| } | |||
| ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version | |||
| void btConvex2dShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const | |||
| { | |||
| m_childConvexShape->getAabb(t,aabbMin,aabbMax); | |||
| } | |||
| void btConvex2dShape::getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const | |||
| { | |||
| m_childConvexShape->getAabbSlow(t,aabbMin,aabbMax); | |||
| } | |||
| void btConvex2dShape::setLocalScaling(const btVector3& scaling) | |||
| { | |||
| m_childConvexShape->setLocalScaling(scaling); | |||
| } | |||
| const btVector3& btConvex2dShape::getLocalScaling() const | |||
| { | |||
| return m_childConvexShape->getLocalScaling(); | |||
| } | |||
| void btConvex2dShape::setMargin(btScalar margin) | |||
| { | |||
| m_childConvexShape->setMargin(margin); | |||
| } | |||
| btScalar btConvex2dShape::getMargin() const | |||
| { | |||
| return m_childConvexShape->getMargin(); | |||
| } | |||
| int btConvex2dShape::getNumPreferredPenetrationDirections() const | |||
| { | |||
| return m_childConvexShape->getNumPreferredPenetrationDirections(); | |||
| } | |||
| void btConvex2dShape::getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const | |||
| { | |||
| m_childConvexShape->getPreferredPenetrationDirection(index,penetrationVector); | |||
| } | |||
| @@ -0,0 +1,80 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_CONVEX_2D_SHAPE_H | |||
| #define BT_CONVEX_2D_SHAPE_H | |||
| #include "BulletCollision/CollisionShapes/btConvexShape.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types | |||
| ///The btConvex2dShape allows to use arbitrary convex shapes as 2d convex shapes, with the Z component assumed to be 0. | |||
| ///For 2d boxes, the btBox2dShape is recommended. | |||
| class btConvex2dShape : public btConvexShape | |||
| { | |||
| btConvexShape* m_childConvexShape; | |||
| public: | |||
| btConvex2dShape( btConvexShape* convexChildShape); | |||
| virtual ~btConvex2dShape(); | |||
| virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; | |||
| virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; | |||
| virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; | |||
| virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; | |||
| btConvexShape* getChildShape() | |||
| { | |||
| return m_childConvexShape; | |||
| } | |||
| const btConvexShape* getChildShape() const | |||
| { | |||
| return m_childConvexShape; | |||
| } | |||
| virtual const char* getName()const | |||
| { | |||
| return "Convex2dShape"; | |||
| } | |||
| /////////////////////////// | |||
| ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version | |||
| void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
| virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
| virtual void setLocalScaling(const btVector3& scaling) ; | |||
| virtual const btVector3& getLocalScaling() const ; | |||
| virtual void setMargin(btScalar margin); | |||
| virtual btScalar getMargin() const; | |||
| virtual int getNumPreferredPenetrationDirections() const; | |||
| virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const; | |||
| }; | |||
| #endif //BT_CONVEX_2D_SHAPE_H | |||
| @@ -0,0 +1,255 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btConvexHullShape.h" | |||
| #include "BulletCollision/CollisionShapes/btCollisionMargin.h" | |||
| #include "LinearMath/btQuaternion.h" | |||
| #include "LinearMath/btSerializer.h" | |||
| btConvexHullShape ::btConvexHullShape (const btScalar* points,int numPoints,int stride) : btPolyhedralConvexAabbCachingShape () | |||
| { | |||
| m_shapeType = CONVEX_HULL_SHAPE_PROXYTYPE; | |||
| m_unscaledPoints.resize(numPoints); | |||
| unsigned char* pointsAddress = (unsigned char*)points; | |||
| for (int i=0;i<numPoints;i++) | |||
| { | |||
| btScalar* point = (btScalar*)pointsAddress; | |||
| m_unscaledPoints[i] = btVector3(point[0], point[1], point[2]); | |||
| pointsAddress += stride; | |||
| } | |||
| recalcLocalAabb(); | |||
| } | |||
| void btConvexHullShape::setLocalScaling(const btVector3& scaling) | |||
| { | |||
| m_localScaling = scaling; | |||
| recalcLocalAabb(); | |||
| } | |||
| void btConvexHullShape::addPoint(const btVector3& point) | |||
| { | |||
| m_unscaledPoints.push_back(point); | |||
| recalcLocalAabb(); | |||
| } | |||
| btVector3 btConvexHullShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const | |||
| { | |||
| btVector3 supVec(btScalar(0.),btScalar(0.),btScalar(0.)); | |||
| btScalar newDot,maxDot = btScalar(-BT_LARGE_FLOAT); | |||
| for (int i=0;i<m_unscaledPoints.size();i++) | |||
| { | |||
| btVector3 vtx = m_unscaledPoints[i] * m_localScaling; | |||
| newDot = vec.dot(vtx); | |||
| if (newDot > maxDot) | |||
| { | |||
| maxDot = newDot; | |||
| supVec = vtx; | |||
| } | |||
| } | |||
| return supVec; | |||
| } | |||
| void btConvexHullShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
| { | |||
| btScalar newDot; | |||
| //use 'w' component of supportVerticesOut? | |||
| { | |||
| for (int i=0;i<numVectors;i++) | |||
| { | |||
| supportVerticesOut[i][3] = btScalar(-BT_LARGE_FLOAT); | |||
| } | |||
| } | |||
| for (int i=0;i<m_unscaledPoints.size();i++) | |||
| { | |||
| btVector3 vtx = getScaledPoint(i); | |||
| for (int j=0;j<numVectors;j++) | |||
| { | |||
| const btVector3& vec = vectors[j]; | |||
| newDot = vec.dot(vtx); | |||
| if (newDot > supportVerticesOut[j][3]) | |||
| { | |||
| //WARNING: don't swap next lines, the w component would get overwritten! | |||
| supportVerticesOut[j] = vtx; | |||
| supportVerticesOut[j][3] = newDot; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| btVector3 btConvexHullShape::localGetSupportingVertex(const btVector3& vec)const | |||
| { | |||
| btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); | |||
| if ( getMargin()!=btScalar(0.) ) | |||
| { | |||
| btVector3 vecnorm = vec; | |||
| if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) | |||
| { | |||
| vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); | |||
| } | |||
| vecnorm.normalize(); | |||
| supVertex+= getMargin() * vecnorm; | |||
| } | |||
| return supVertex; | |||
| } | |||
| //currently just for debugging (drawing), perhaps future support for algebraic continuous collision detection | |||
| //Please note that you can debug-draw btConvexHullShape with the Raytracer Demo | |||
| int btConvexHullShape::getNumVertices() const | |||
| { | |||
| return m_unscaledPoints.size(); | |||
| } | |||
| int btConvexHullShape::getNumEdges() const | |||
| { | |||
| return m_unscaledPoints.size(); | |||
| } | |||
| void btConvexHullShape::getEdge(int i,btVector3& pa,btVector3& pb) const | |||
| { | |||
| int index0 = i%m_unscaledPoints.size(); | |||
| int index1 = (i+1)%m_unscaledPoints.size(); | |||
| pa = getScaledPoint(index0); | |||
| pb = getScaledPoint(index1); | |||
| } | |||
| void btConvexHullShape::getVertex(int i,btVector3& vtx) const | |||
| { | |||
| vtx = getScaledPoint(i); | |||
| } | |||
| int btConvexHullShape::getNumPlanes() const | |||
| { | |||
| return 0; | |||
| } | |||
| void btConvexHullShape::getPlane(btVector3& ,btVector3& ,int ) const | |||
| { | |||
| btAssert(0); | |||
| } | |||
| //not yet | |||
| bool btConvexHullShape::isInside(const btVector3& ,btScalar ) const | |||
| { | |||
| btAssert(0); | |||
| return false; | |||
| } | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| const char* btConvexHullShape::serialize(void* dataBuffer, btSerializer* serializer) const | |||
| { | |||
| //int szc = sizeof(btConvexHullShapeData); | |||
| btConvexHullShapeData* shapeData = (btConvexHullShapeData*) dataBuffer; | |||
| btConvexInternalShape::serialize(&shapeData->m_convexInternalShapeData, serializer); | |||
| int numElem = m_unscaledPoints.size(); | |||
| shapeData->m_numUnscaledPoints = numElem; | |||
| #ifdef BT_USE_DOUBLE_PRECISION | |||
| shapeData->m_unscaledPointsFloatPtr = 0; | |||
| shapeData->m_unscaledPointsDoublePtr = numElem ? (btVector3Data*)serializer->getUniquePointer((void*)&m_unscaledPoints[0]): 0; | |||
| #else | |||
| shapeData->m_unscaledPointsFloatPtr = numElem ? (btVector3Data*)serializer->getUniquePointer((void*)&m_unscaledPoints[0]): 0; | |||
| shapeData->m_unscaledPointsDoublePtr = 0; | |||
| #endif | |||
| if (numElem) | |||
| { | |||
| int sz = sizeof(btVector3Data); | |||
| // int sz2 = sizeof(btVector3DoubleData); | |||
| // int sz3 = sizeof(btVector3FloatData); | |||
| btChunk* chunk = serializer->allocate(sz,numElem); | |||
| btVector3Data* memPtr = (btVector3Data*)chunk->m_oldPtr; | |||
| for (int i=0;i<numElem;i++,memPtr++) | |||
| { | |||
| m_unscaledPoints[i].serialize(*memPtr); | |||
| } | |||
| serializer->finalizeChunk(chunk,btVector3DataName,BT_ARRAY_CODE,(void*)&m_unscaledPoints[0]); | |||
| } | |||
| return "btConvexHullShapeData"; | |||
| } | |||
| void btConvexHullShape::project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const | |||
| { | |||
| #if 1 | |||
| min = FLT_MAX; | |||
| max = -FLT_MAX; | |||
| btVector3 witnesPtMin; | |||
| btVector3 witnesPtMax; | |||
| int numVerts = m_unscaledPoints.size(); | |||
| for(int i=0;i<numVerts;i++) | |||
| { | |||
| btVector3 vtx = m_unscaledPoints[i] * m_localScaling; | |||
| btVector3 pt = trans * vtx; | |||
| btScalar dp = pt.dot(dir); | |||
| if(dp < min) | |||
| { | |||
| min = dp; | |||
| witnesPtMin = pt; | |||
| } | |||
| if(dp > max) | |||
| { | |||
| max = dp; | |||
| witnesPtMax=pt; | |||
| } | |||
| } | |||
| #else | |||
| btVector3 localAxis = dir*trans.getBasis(); | |||
| btVector3 vtx1 = trans(localGetSupportingVertex(localAxis)); | |||
| btVector3 vtx2 = trans(localGetSupportingVertex(-localAxis)); | |||
| min = vtx1.dot(dir); | |||
| max = vtx2.dot(dir); | |||
| #endif | |||
| if(min>max) | |||
| { | |||
| btScalar tmp = min; | |||
| min = max; | |||
| max = tmp; | |||
| } | |||
| } | |||
| @@ -0,0 +1,122 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_CONVEX_HULL_SHAPE_H | |||
| #define BT_CONVEX_HULL_SHAPE_H | |||
| #include "btPolyhedralConvexShape.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| ///The btConvexHullShape implements an implicit convex hull of an array of vertices. | |||
| ///Bullet provides a general and fast collision detector for convex shapes based on GJK and EPA using localGetSupportingVertex. | |||
| ATTRIBUTE_ALIGNED16(class) btConvexHullShape : public btPolyhedralConvexAabbCachingShape | |||
| { | |||
| btAlignedObjectArray<btVector3> m_unscaledPoints; | |||
| public: | |||
| BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
| ///this constructor optionally takes in a pointer to points. Each point is assumed to be 3 consecutive btScalar (x,y,z), the striding defines the number of bytes between each point, in memory. | |||
| ///It is easier to not pass any points in the constructor, and just add one point at a time, using addPoint. | |||
| ///btConvexHullShape make an internal copy of the points. | |||
| btConvexHullShape(const btScalar* points=0,int numPoints=0, int stride=sizeof(btVector3)); | |||
| void addPoint(const btVector3& point); | |||
| btVector3* getUnscaledPoints() | |||
| { | |||
| return &m_unscaledPoints[0]; | |||
| } | |||
| const btVector3* getUnscaledPoints() const | |||
| { | |||
| return &m_unscaledPoints[0]; | |||
| } | |||
| ///getPoints is obsolete, please use getUnscaledPoints | |||
| const btVector3* getPoints() const | |||
| { | |||
| return getUnscaledPoints(); | |||
| } | |||
| SIMD_FORCE_INLINE btVector3 getScaledPoint(int i) const | |||
| { | |||
| return m_unscaledPoints[i] * m_localScaling; | |||
| } | |||
| SIMD_FORCE_INLINE int getNumPoints() const | |||
| { | |||
| return m_unscaledPoints.size(); | |||
| } | |||
| virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; | |||
| virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; | |||
| virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; | |||
| virtual void project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const; | |||
| //debugging | |||
| virtual const char* getName()const {return "Convex";} | |||
| virtual int getNumVertices() const; | |||
| virtual int getNumEdges() const; | |||
| virtual void getEdge(int i,btVector3& pa,btVector3& pb) const; | |||
| virtual void getVertex(int i,btVector3& vtx) const; | |||
| virtual int getNumPlanes() const; | |||
| virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i ) const; | |||
| virtual bool isInside(const btVector3& pt,btScalar tolerance) const; | |||
| ///in case we receive negative scaling | |||
| virtual void setLocalScaling(const btVector3& scaling); | |||
| virtual int calculateSerializeBufferSize() const; | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
| }; | |||
| ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
| struct btConvexHullShapeData | |||
| { | |||
| btConvexInternalShapeData m_convexInternalShapeData; | |||
| btVector3FloatData *m_unscaledPointsFloatPtr; | |||
| btVector3DoubleData *m_unscaledPointsDoublePtr; | |||
| int m_numUnscaledPoints; | |||
| char m_padding3[4]; | |||
| }; | |||
| SIMD_FORCE_INLINE int btConvexHullShape::calculateSerializeBufferSize() const | |||
| { | |||
| return sizeof(btConvexHullShapeData); | |||
| } | |||
| #endif //BT_CONVEX_HULL_SHAPE_H | |||
| @@ -0,0 +1,151 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btConvexInternalShape.h" | |||
| btConvexInternalShape::btConvexInternalShape() | |||
| : m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.)), | |||
| m_collisionMargin(CONVEX_DISTANCE_MARGIN) | |||
| { | |||
| } | |||
| void btConvexInternalShape::setLocalScaling(const btVector3& scaling) | |||
| { | |||
| m_localScaling = scaling.absolute(); | |||
| } | |||
| void btConvexInternalShape::getAabbSlow(const btTransform& trans,btVector3&minAabb,btVector3&maxAabb) const | |||
| { | |||
| #ifndef __SPU__ | |||
| //use localGetSupportingVertexWithoutMargin? | |||
| btScalar margin = getMargin(); | |||
| for (int i=0;i<3;i++) | |||
| { | |||
| btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); | |||
| vec[i] = btScalar(1.); | |||
| btVector3 sv = localGetSupportingVertex(vec*trans.getBasis()); | |||
| btVector3 tmp = trans(sv); | |||
| maxAabb[i] = tmp[i]+margin; | |||
| vec[i] = btScalar(-1.); | |||
| tmp = trans(localGetSupportingVertex(vec*trans.getBasis())); | |||
| minAabb[i] = tmp[i]-margin; | |||
| } | |||
| #endif | |||
| } | |||
| btVector3 btConvexInternalShape::localGetSupportingVertex(const btVector3& vec)const | |||
| { | |||
| #ifndef __SPU__ | |||
| btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); | |||
| if ( getMargin()!=btScalar(0.) ) | |||
| { | |||
| btVector3 vecnorm = vec; | |||
| if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) | |||
| { | |||
| vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); | |||
| } | |||
| vecnorm.normalize(); | |||
| supVertex+= getMargin() * vecnorm; | |||
| } | |||
| return supVertex; | |||
| #else | |||
| btAssert(0); | |||
| return btVector3(0,0,0); | |||
| #endif //__SPU__ | |||
| } | |||
| btConvexInternalAabbCachingShape::btConvexInternalAabbCachingShape() | |||
| : btConvexInternalShape(), | |||
| m_localAabbMin(1,1,1), | |||
| m_localAabbMax(-1,-1,-1), | |||
| m_isLocalAabbValid(false) | |||
| { | |||
| } | |||
| void btConvexInternalAabbCachingShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const | |||
| { | |||
| getNonvirtualAabb(trans,aabbMin,aabbMax,getMargin()); | |||
| } | |||
| void btConvexInternalAabbCachingShape::setLocalScaling(const btVector3& scaling) | |||
| { | |||
| btConvexInternalShape::setLocalScaling(scaling); | |||
| recalcLocalAabb(); | |||
| } | |||
| void btConvexInternalAabbCachingShape::recalcLocalAabb() | |||
| { | |||
| m_isLocalAabbValid = true; | |||
| #if 1 | |||
| static const btVector3 _directions[] = | |||
| { | |||
| btVector3( 1., 0., 0.), | |||
| btVector3( 0., 1., 0.), | |||
| btVector3( 0., 0., 1.), | |||
| btVector3( -1., 0., 0.), | |||
| btVector3( 0., -1., 0.), | |||
| btVector3( 0., 0., -1.) | |||
| }; | |||
| btVector3 _supporting[] = | |||
| { | |||
| btVector3( 0., 0., 0.), | |||
| btVector3( 0., 0., 0.), | |||
| btVector3( 0., 0., 0.), | |||
| btVector3( 0., 0., 0.), | |||
| btVector3( 0., 0., 0.), | |||
| btVector3( 0., 0., 0.) | |||
| }; | |||
| batchedUnitVectorGetSupportingVertexWithoutMargin(_directions, _supporting, 6); | |||
| for ( int i = 0; i < 3; ++i ) | |||
| { | |||
| m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin; | |||
| m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin; | |||
| } | |||
| #else | |||
| for (int i=0;i<3;i++) | |||
| { | |||
| btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); | |||
| vec[i] = btScalar(1.); | |||
| btVector3 tmp = localGetSupportingVertex(vec); | |||
| m_localAabbMax[i] = tmp[i]+m_collisionMargin; | |||
| vec[i] = btScalar(-1.); | |||
| tmp = localGetSupportingVertex(vec); | |||
| m_localAabbMin[i] = tmp[i]-m_collisionMargin; | |||
| } | |||
| #endif | |||
| } | |||
| @@ -0,0 +1,224 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_CONVEX_INTERNAL_SHAPE_H | |||
| #define BT_CONVEX_INTERNAL_SHAPE_H | |||
| #include "btConvexShape.h" | |||
| #include "LinearMath/btAabbUtil2.h" | |||
| ///The btConvexInternalShape is an internal base class, shared by most convex shape implementations. | |||
| ///The btConvexInternalShape uses a default collision margin set to CONVEX_DISTANCE_MARGIN. | |||
| ///This collision margin used by Gjk and some other algorithms, see also btCollisionMargin.h | |||
| ///Note that when creating small shapes (derived from btConvexInternalShape), | |||
| ///you need to make sure to set a smaller collision margin, using the 'setMargin' API | |||
| ///There is a automatic mechanism 'setSafeMargin' used by btBoxShape and btCylinderShape | |||
| class btConvexInternalShape : public btConvexShape | |||
| { | |||
| protected: | |||
| //local scaling. collisionMargin is not scaled ! | |||
| btVector3 m_localScaling; | |||
| btVector3 m_implicitShapeDimensions; | |||
| btScalar m_collisionMargin; | |||
| btScalar m_padding; | |||
| btConvexInternalShape(); | |||
| public: | |||
| virtual ~btConvexInternalShape() | |||
| { | |||
| } | |||
| virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; | |||
| const btVector3& getImplicitShapeDimensions() const | |||
| { | |||
| return m_implicitShapeDimensions; | |||
| } | |||
| ///warning: use setImplicitShapeDimensions with care | |||
| ///changing a collision shape while the body is in the world is not recommended, | |||
| ///it is best to remove the body from the world, then make the change, and re-add it | |||
| ///alternatively flush the contact points, see documentation for 'cleanProxyFromPairs' | |||
| void setImplicitShapeDimensions(const btVector3& dimensions) | |||
| { | |||
| m_implicitShapeDimensions = dimensions; | |||
| } | |||
| void setSafeMargin(btScalar minDimension, btScalar defaultMarginMultiplier = 0.1f) | |||
| { | |||
| btScalar safeMargin = defaultMarginMultiplier*minDimension; | |||
| if (safeMargin < getMargin()) | |||
| { | |||
| setMargin(safeMargin); | |||
| } | |||
| } | |||
| void setSafeMargin(const btVector3& halfExtents, btScalar defaultMarginMultiplier = 0.1f) | |||
| { | |||
| //see http://code.google.com/p/bullet/issues/detail?id=349 | |||
| //this margin check could could be added to other collision shapes too, | |||
| //or add some assert/warning somewhere | |||
| btScalar minDimension=halfExtents[halfExtents.minAxis()]; | |||
| setSafeMargin(minDimension, defaultMarginMultiplier); | |||
| } | |||
| ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version | |||
| void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const | |||
| { | |||
| getAabbSlow(t,aabbMin,aabbMax); | |||
| } | |||
| virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
| virtual void setLocalScaling(const btVector3& scaling); | |||
| virtual const btVector3& getLocalScaling() const | |||
| { | |||
| return m_localScaling; | |||
| } | |||
| const btVector3& getLocalScalingNV() const | |||
| { | |||
| return m_localScaling; | |||
| } | |||
| virtual void setMargin(btScalar margin) | |||
| { | |||
| m_collisionMargin = margin; | |||
| } | |||
| virtual btScalar getMargin() const | |||
| { | |||
| return m_collisionMargin; | |||
| } | |||
| btScalar getMarginNV() const | |||
| { | |||
| return m_collisionMargin; | |||
| } | |||
| virtual int getNumPreferredPenetrationDirections() const | |||
| { | |||
| return 0; | |||
| } | |||
| virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const | |||
| { | |||
| (void)penetrationVector; | |||
| (void)index; | |||
| btAssert(0); | |||
| } | |||
| virtual int calculateSerializeBufferSize() const; | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; | |||
| }; | |||
| ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 | |||
| struct btConvexInternalShapeData | |||
| { | |||
| btCollisionShapeData m_collisionShapeData; | |||
| btVector3FloatData m_localScaling; | |||
| btVector3FloatData m_implicitShapeDimensions; | |||
| float m_collisionMargin; | |||
| int m_padding; | |||
| }; | |||
| SIMD_FORCE_INLINE int btConvexInternalShape::calculateSerializeBufferSize() const | |||
| { | |||
| return sizeof(btConvexInternalShapeData); | |||
| } | |||
| ///fills the dataBuffer and returns the struct name (and 0 on failure) | |||
| SIMD_FORCE_INLINE const char* btConvexInternalShape::serialize(void* dataBuffer, btSerializer* serializer) const | |||
| { | |||
| btConvexInternalShapeData* shapeData = (btConvexInternalShapeData*) dataBuffer; | |||
| btCollisionShape::serialize(&shapeData->m_collisionShapeData, serializer); | |||
| m_implicitShapeDimensions.serializeFloat(shapeData->m_implicitShapeDimensions); | |||
| m_localScaling.serializeFloat(shapeData->m_localScaling); | |||
| shapeData->m_collisionMargin = float(m_collisionMargin); | |||
| return "btConvexInternalShapeData"; | |||
| } | |||
| ///btConvexInternalAabbCachingShape adds local aabb caching for convex shapes, to avoid expensive bounding box calculations | |||
| class btConvexInternalAabbCachingShape : public btConvexInternalShape | |||
| { | |||
| btVector3 m_localAabbMin; | |||
| btVector3 m_localAabbMax; | |||
| bool m_isLocalAabbValid; | |||
| protected: | |||
| btConvexInternalAabbCachingShape(); | |||
| void setCachedLocalAabb (const btVector3& aabbMin, const btVector3& aabbMax) | |||
| { | |||
| m_isLocalAabbValid = true; | |||
| m_localAabbMin = aabbMin; | |||
| m_localAabbMax = aabbMax; | |||
| } | |||
| inline void getCachedLocalAabb (btVector3& aabbMin, btVector3& aabbMax) const | |||
| { | |||
| btAssert(m_isLocalAabbValid); | |||
| aabbMin = m_localAabbMin; | |||
| aabbMax = m_localAabbMax; | |||
| } | |||
| inline void getNonvirtualAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax, btScalar margin) const | |||
| { | |||
| //lazy evaluation of local aabb | |||
| btAssert(m_isLocalAabbValid); | |||
| btTransformAabb(m_localAabbMin,m_localAabbMax,margin,trans,aabbMin,aabbMax); | |||
| } | |||
| public: | |||
| virtual void setLocalScaling(const btVector3& scaling); | |||
| virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; | |||
| void recalcLocalAabb(); | |||
| }; | |||
| #endif //BT_CONVEX_INTERNAL_SHAPE_H | |||
| @@ -0,0 +1,157 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btConvexPointCloudShape.h" | |||
| #include "BulletCollision/CollisionShapes/btCollisionMargin.h" | |||
| #include "LinearMath/btQuaternion.h" | |||
| void btConvexPointCloudShape::setLocalScaling(const btVector3& scaling) | |||
| { | |||
| m_localScaling = scaling; | |||
| recalcLocalAabb(); | |||
| } | |||
| #ifndef __SPU__ | |||
| btVector3 btConvexPointCloudShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const | |||
| { | |||
| btVector3 supVec(btScalar(0.),btScalar(0.),btScalar(0.)); | |||
| btScalar newDot,maxDot = btScalar(-BT_LARGE_FLOAT); | |||
| btVector3 vec = vec0; | |||
| btScalar lenSqr = vec.length2(); | |||
| if (lenSqr < btScalar(0.0001)) | |||
| { | |||
| vec.setValue(1,0,0); | |||
| } else | |||
| { | |||
| btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); | |||
| vec *= rlen; | |||
| } | |||
| for (int i=0;i<m_numPoints;i++) | |||
| { | |||
| btVector3 vtx = getScaledPoint(i); | |||
| newDot = vec.dot(vtx); | |||
| if (newDot > maxDot) | |||
| { | |||
| maxDot = newDot; | |||
| supVec = vtx; | |||
| } | |||
| } | |||
| return supVec; | |||
| } | |||
| void btConvexPointCloudShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const | |||
| { | |||
| btScalar newDot; | |||
| //use 'w' component of supportVerticesOut? | |||
| { | |||
| for (int i=0;i<numVectors;i++) | |||
| { | |||
| supportVerticesOut[i][3] = btScalar(-BT_LARGE_FLOAT); | |||
| } | |||
| } | |||
| for (int i=0;i<m_numPoints;i++) | |||
| { | |||
| btVector3 vtx = getScaledPoint(i); | |||
| for (int j=0;j<numVectors;j++) | |||
| { | |||
| const btVector3& vec = vectors[j]; | |||
| newDot = vec.dot(vtx); | |||
| if (newDot > supportVerticesOut[j][3]) | |||
| { | |||
| //WARNING: don't swap next lines, the w component would get overwritten! | |||
| supportVerticesOut[j] = vtx; | |||
| supportVerticesOut[j][3] = newDot; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| btVector3 btConvexPointCloudShape::localGetSupportingVertex(const btVector3& vec)const | |||
| { | |||
| btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); | |||
| if ( getMargin()!=btScalar(0.) ) | |||
| { | |||
| btVector3 vecnorm = vec; | |||
| if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) | |||
| { | |||
| vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); | |||
| } | |||
| vecnorm.normalize(); | |||
| supVertex+= getMargin() * vecnorm; | |||
| } | |||
| return supVertex; | |||
| } | |||
| #endif | |||
| //currently just for debugging (drawing), perhaps future support for algebraic continuous collision detection | |||
| //Please note that you can debug-draw btConvexHullShape with the Raytracer Demo | |||
| int btConvexPointCloudShape::getNumVertices() const | |||
| { | |||
| return m_numPoints; | |||
| } | |||
| int btConvexPointCloudShape::getNumEdges() const | |||
| { | |||
| return 0; | |||
| } | |||
| void btConvexPointCloudShape::getEdge(int i,btVector3& pa,btVector3& pb) const | |||
| { | |||
| btAssert (0); | |||
| } | |||
| void btConvexPointCloudShape::getVertex(int i,btVector3& vtx) const | |||
| { | |||
| vtx = m_unscaledPoints[i]*m_localScaling; | |||
| } | |||
| int btConvexPointCloudShape::getNumPlanes() const | |||
| { | |||
| return 0; | |||
| } | |||
| void btConvexPointCloudShape::getPlane(btVector3& ,btVector3& ,int ) const | |||
| { | |||
| btAssert(0); | |||
| } | |||
| //not yet | |||
| bool btConvexPointCloudShape::isInside(const btVector3& ,btScalar ) const | |||
| { | |||
| btAssert(0); | |||
| return false; | |||
| } | |||
| @@ -0,0 +1,105 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #ifndef BT_CONVEX_POINT_CLOUD_SHAPE_H | |||
| #define BT_CONVEX_POINT_CLOUD_SHAPE_H | |||
| #include "btPolyhedralConvexShape.h" | |||
| #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| ///The btConvexPointCloudShape implements an implicit convex hull of an array of vertices. | |||
| ATTRIBUTE_ALIGNED16(class) btConvexPointCloudShape : public btPolyhedralConvexAabbCachingShape | |||
| { | |||
| btVector3* m_unscaledPoints; | |||
| int m_numPoints; | |||
| public: | |||
| BT_DECLARE_ALIGNED_ALLOCATOR(); | |||
| btConvexPointCloudShape() | |||
| { | |||
| m_localScaling.setValue(1.f,1.f,1.f); | |||
| m_shapeType = CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE; | |||
| m_unscaledPoints = 0; | |||
| m_numPoints = 0; | |||
| } | |||
| btConvexPointCloudShape(btVector3* points,int numPoints, const btVector3& localScaling,bool computeAabb = true) | |||
| { | |||
| m_localScaling = localScaling; | |||
| m_shapeType = CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE; | |||
| m_unscaledPoints = points; | |||
| m_numPoints = numPoints; | |||
| if (computeAabb) | |||
| recalcLocalAabb(); | |||
| } | |||
| void setPoints (btVector3* points, int numPoints, bool computeAabb = true,const btVector3& localScaling=btVector3(1.f,1.f,1.f)) | |||
| { | |||
| m_unscaledPoints = points; | |||
| m_numPoints = numPoints; | |||
| m_localScaling = localScaling; | |||
| if (computeAabb) | |||
| recalcLocalAabb(); | |||
| } | |||
| SIMD_FORCE_INLINE btVector3* getUnscaledPoints() | |||
| { | |||
| return m_unscaledPoints; | |||
| } | |||
| SIMD_FORCE_INLINE const btVector3* getUnscaledPoints() const | |||
| { | |||
| return m_unscaledPoints; | |||
| } | |||
| SIMD_FORCE_INLINE int getNumPoints() const | |||
| { | |||
| return m_numPoints; | |||
| } | |||
| SIMD_FORCE_INLINE btVector3 getScaledPoint( int index) const | |||
| { | |||
| return m_unscaledPoints[index] * m_localScaling; | |||
| } | |||
| #ifndef __SPU__ | |||
| virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; | |||
| virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; | |||
| virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; | |||
| #endif | |||
| //debugging | |||
| virtual const char* getName()const {return "ConvexPointCloud";} | |||
| virtual int getNumVertices() const; | |||
| virtual int getNumEdges() const; | |||
| virtual void getEdge(int i,btVector3& pa,btVector3& pb) const; | |||
| virtual void getVertex(int i,btVector3& vtx) const; | |||
| virtual int getNumPlanes() const; | |||
| virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i ) const; | |||
| virtual bool isInside(const btVector3& pt,btScalar tolerance) const; | |||
| ///in case we receive negative scaling | |||
| virtual void setLocalScaling(const btVector3& scaling); | |||
| }; | |||
| #endif //BT_CONVEX_POINT_CLOUD_SHAPE_H | |||
| @@ -0,0 +1,296 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2011 Advanced Micro Devices, Inc. http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| ///This file was written by Erwin Coumans | |||
| ///Separating axis rest based on work from Pierre Terdiman, see | |||
| ///And contact clipping based on work from Simon Hobbs | |||
| #include "btConvexPolyhedron.h" | |||
| #include "LinearMath/btHashMap.h" | |||
| btConvexPolyhedron::btConvexPolyhedron() | |||
| { | |||
| } | |||
| btConvexPolyhedron::~btConvexPolyhedron() | |||
| { | |||
| } | |||
| inline bool IsAlmostZero(const btVector3& v) | |||
| { | |||
| if(fabsf(v.x())>1e-6 || fabsf(v.y())>1e-6 || fabsf(v.z())>1e-6) return false; | |||
| return true; | |||
| } | |||
| struct btInternalVertexPair | |||
| { | |||
| btInternalVertexPair(short int v0,short int v1) | |||
| :m_v0(v0), | |||
| m_v1(v1) | |||
| { | |||
| if (m_v1>m_v0) | |||
| btSwap(m_v0,m_v1); | |||
| } | |||
| short int m_v0; | |||
| short int m_v1; | |||
| int getHash() const | |||
| { | |||
| return m_v0+(m_v1<<16); | |||
| } | |||
| bool equals(const btInternalVertexPair& other) const | |||
| { | |||
| return m_v0==other.m_v0 && m_v1==other.m_v1; | |||
| } | |||
| }; | |||
| struct btInternalEdge | |||
| { | |||
| btInternalEdge() | |||
| :m_face0(-1), | |||
| m_face1(-1) | |||
| { | |||
| } | |||
| short int m_face0; | |||
| short int m_face1; | |||
| }; | |||
| // | |||
| #ifdef TEST_INTERNAL_OBJECTS | |||
| bool btConvexPolyhedron::testContainment() const | |||
| { | |||
| for(int p=0;p<8;p++) | |||
| { | |||
| btVector3 LocalPt; | |||
| if(p==0) LocalPt = m_localCenter + btVector3(m_extents[0], m_extents[1], m_extents[2]); | |||
| else if(p==1) LocalPt = m_localCenter + btVector3(m_extents[0], m_extents[1], -m_extents[2]); | |||
| else if(p==2) LocalPt = m_localCenter + btVector3(m_extents[0], -m_extents[1], m_extents[2]); | |||
| else if(p==3) LocalPt = m_localCenter + btVector3(m_extents[0], -m_extents[1], -m_extents[2]); | |||
| else if(p==4) LocalPt = m_localCenter + btVector3(-m_extents[0], m_extents[1], m_extents[2]); | |||
| else if(p==5) LocalPt = m_localCenter + btVector3(-m_extents[0], m_extents[1], -m_extents[2]); | |||
| else if(p==6) LocalPt = m_localCenter + btVector3(-m_extents[0], -m_extents[1], m_extents[2]); | |||
| else if(p==7) LocalPt = m_localCenter + btVector3(-m_extents[0], -m_extents[1], -m_extents[2]); | |||
| for(int i=0;i<m_faces.size();i++) | |||
| { | |||
| const btVector3 Normal(m_faces[i].m_plane[0], m_faces[i].m_plane[1], m_faces[i].m_plane[2]); | |||
| const btScalar d = LocalPt.dot(Normal) + m_faces[i].m_plane[3]; | |||
| if(d>0.0f) | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| #endif | |||
| void btConvexPolyhedron::initialize() | |||
| { | |||
| btHashMap<btInternalVertexPair,btInternalEdge> edges; | |||
| btScalar TotalArea = 0.0f; | |||
| m_localCenter.setValue(0, 0, 0); | |||
| for(int i=0;i<m_faces.size();i++) | |||
| { | |||
| int numVertices = m_faces[i].m_indices.size(); | |||
| int NbTris = numVertices; | |||
| for(int j=0;j<NbTris;j++) | |||
| { | |||
| int k = (j+1)%numVertices; | |||
| btInternalVertexPair vp(m_faces[i].m_indices[j],m_faces[i].m_indices[k]); | |||
| btInternalEdge* edptr = edges.find(vp); | |||
| btVector3 edge = m_vertices[vp.m_v1]-m_vertices[vp.m_v0]; | |||
| edge.normalize(); | |||
| bool found = false; | |||
| for (int p=0;p<m_uniqueEdges.size();p++) | |||
| { | |||
| if (IsAlmostZero(m_uniqueEdges[p]-edge) || | |||
| IsAlmostZero(m_uniqueEdges[p]+edge)) | |||
| { | |||
| found = true; | |||
| break; | |||
| } | |||
| } | |||
| if (!found) | |||
| { | |||
| m_uniqueEdges.push_back(edge); | |||
| } | |||
| if (edptr) | |||
| { | |||
| btAssert(edptr->m_face0>=0); | |||
| btAssert(edptr->m_face1<0); | |||
| edptr->m_face1 = i; | |||
| } else | |||
| { | |||
| btInternalEdge ed; | |||
| ed.m_face0 = i; | |||
| edges.insert(vp,ed); | |||
| } | |||
| } | |||
| } | |||
| #ifdef USE_CONNECTED_FACES | |||
| for(int i=0;i<m_faces.size();i++) | |||
| { | |||
| int numVertices = m_faces[i].m_indices.size(); | |||
| m_faces[i].m_connectedFaces.resize(numVertices); | |||
| for(int j=0;j<numVertices;j++) | |||
| { | |||
| int k = (j+1)%numVertices; | |||
| btInternalVertexPair vp(m_faces[i].m_indices[j],m_faces[i].m_indices[k]); | |||
| btInternalEdge* edptr = edges.find(vp); | |||
| btAssert(edptr); | |||
| btAssert(edptr->m_face0>=0); | |||
| btAssert(edptr->m_face1>=0); | |||
| int connectedFace = (edptr->m_face0==i)?edptr->m_face1:edptr->m_face0; | |||
| m_faces[i].m_connectedFaces[j] = connectedFace; | |||
| } | |||
| } | |||
| #endif//USE_CONNECTED_FACES | |||
| for(int i=0;i<m_faces.size();i++) | |||
| { | |||
| int numVertices = m_faces[i].m_indices.size(); | |||
| int NbTris = numVertices-2; | |||
| const btVector3& p0 = m_vertices[m_faces[i].m_indices[0]]; | |||
| for(int j=1;j<=NbTris;j++) | |||
| { | |||
| int k = (j+1)%numVertices; | |||
| const btVector3& p1 = m_vertices[m_faces[i].m_indices[j]]; | |||
| const btVector3& p2 = m_vertices[m_faces[i].m_indices[k]]; | |||
| btScalar Area = ((p0 - p1).cross(p0 - p2)).length() * 0.5f; | |||
| btVector3 Center = (p0+p1+p2)/3.0f; | |||
| m_localCenter += Area * Center; | |||
| TotalArea += Area; | |||
| } | |||
| } | |||
| m_localCenter /= TotalArea; | |||
| #ifdef TEST_INTERNAL_OBJECTS | |||
| if(1) | |||
| { | |||
| m_radius = FLT_MAX; | |||
| for(int i=0;i<m_faces.size();i++) | |||
| { | |||
| const btVector3 Normal(m_faces[i].m_plane[0], m_faces[i].m_plane[1], m_faces[i].m_plane[2]); | |||
| const btScalar dist = btFabs(m_localCenter.dot(Normal) + m_faces[i].m_plane[3]); | |||
| if(dist<m_radius) | |||
| m_radius = dist; | |||
| } | |||
| btScalar MinX = FLT_MAX; | |||
| btScalar MinY = FLT_MAX; | |||
| btScalar MinZ = FLT_MAX; | |||
| btScalar MaxX = -FLT_MAX; | |||
| btScalar MaxY = -FLT_MAX; | |||
| btScalar MaxZ = -FLT_MAX; | |||
| for(int i=0; i<m_vertices.size(); i++) | |||
| { | |||
| const btVector3& pt = m_vertices[i]; | |||
| if(pt.x()<MinX) MinX = pt.x(); | |||
| if(pt.x()>MaxX) MaxX = pt.x(); | |||
| if(pt.y()<MinY) MinY = pt.y(); | |||
| if(pt.y()>MaxY) MaxY = pt.y(); | |||
| if(pt.z()<MinZ) MinZ = pt.z(); | |||
| if(pt.z()>MaxZ) MaxZ = pt.z(); | |||
| } | |||
| mC.setValue(MaxX+MinX, MaxY+MinY, MaxZ+MinZ); | |||
| mE.setValue(MaxX-MinX, MaxY-MinY, MaxZ-MinZ); | |||
| // const btScalar r = m_radius / sqrtf(2.0f); | |||
| const btScalar r = m_radius / sqrtf(3.0f); | |||
| const int LargestExtent = mE.maxAxis(); | |||
| const btScalar Step = (mE[LargestExtent]*0.5f - r)/1024.0f; | |||
| m_extents[0] = m_extents[1] = m_extents[2] = r; | |||
| m_extents[LargestExtent] = mE[LargestExtent]*0.5f; | |||
| bool FoundBox = false; | |||
| for(int j=0;j<1024;j++) | |||
| { | |||
| if(testContainment()) | |||
| { | |||
| FoundBox = true; | |||
| break; | |||
| } | |||
| m_extents[LargestExtent] -= Step; | |||
| } | |||
| if(!FoundBox) | |||
| { | |||
| m_extents[0] = m_extents[1] = m_extents[2] = r; | |||
| } | |||
| else | |||
| { | |||
| // Refine the box | |||
| const btScalar Step = (m_radius - r)/1024.0f; | |||
| const int e0 = (1<<LargestExtent) & 3; | |||
| const int e1 = (1<<e0) & 3; | |||
| for(int j=0;j<1024;j++) | |||
| { | |||
| const btScalar Saved0 = m_extents[e0]; | |||
| const btScalar Saved1 = m_extents[e1]; | |||
| m_extents[e0] += Step; | |||
| m_extents[e1] += Step; | |||
| if(!testContainment()) | |||
| { | |||
| m_extents[e0] = Saved0; | |||
| m_extents[e1] = Saved1; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| #endif | |||
| } | |||
| void btConvexPolyhedron::project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const | |||
| { | |||
| min = FLT_MAX; | |||
| max = -FLT_MAX; | |||
| int numVerts = m_vertices.size(); | |||
| for(int i=0;i<numVerts;i++) | |||
| { | |||
| btVector3 pt = trans * m_vertices[i]; | |||
| btScalar dp = pt.dot(dir); | |||
| if(dp < min) min = dp; | |||
| if(dp > max) max = dp; | |||
| } | |||
| if(min>max) | |||
| { | |||
| btScalar tmp = min; | |||
| min = max; | |||
| max = tmp; | |||
| } | |||
| } | |||
| @@ -0,0 +1,62 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2011 Advanced Micro Devices, Inc. http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| ///This file was written by Erwin Coumans | |||
| #ifndef _BT_POLYHEDRAL_FEATURES_H | |||
| #define _BT_POLYHEDRAL_FEATURES_H | |||
| #include "LinearMath/btTransform.h" | |||
| #include "LinearMath/btAlignedObjectArray.h" | |||
| #define TEST_INTERNAL_OBJECTS 1 | |||
| struct btFace | |||
| { | |||
| btAlignedObjectArray<int> m_indices; | |||
| // btAlignedObjectArray<int> m_connectedFaces; | |||
| btScalar m_plane[4]; | |||
| }; | |||
| class btConvexPolyhedron | |||
| { | |||
| public: | |||
| btConvexPolyhedron(); | |||
| virtual ~btConvexPolyhedron(); | |||
| btAlignedObjectArray<btVector3> m_vertices; | |||
| btAlignedObjectArray<btFace> m_faces; | |||
| btAlignedObjectArray<btVector3> m_uniqueEdges; | |||
| btVector3 m_localCenter; | |||
| btVector3 m_extents; | |||
| btScalar m_radius; | |||
| btVector3 mC; | |||
| btVector3 mE; | |||
| void initialize(); | |||
| bool testContainment() const; | |||
| void project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const; | |||
| }; | |||
| #endif //_BT_POLYHEDRAL_FEATURES_H | |||
| @@ -0,0 +1,446 @@ | |||
| /* | |||
| Bullet Continuous Collision Detection and Physics Library | |||
| Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org | |||
| This software is provided 'as-is', without any express or implied warranty. | |||
| In no event will the authors be held liable for any damages arising from the use of this software. | |||
| Permission is granted to anyone to use this software for any purpose, | |||
| including commercial applications, and to alter it and redistribute it freely, | |||
| subject to the following restrictions: | |||
| 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. | |||
| 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. | |||
| 3. This notice may not be removed or altered from any source distribution. | |||
| */ | |||
| #include "btConvexShape.h" | |||
| #include "btTriangleShape.h" | |||
| #include "btSphereShape.h" | |||
| #include "btCylinderShape.h" | |||
| #include "btCapsuleShape.h" | |||
| #include "btConvexHullShape.h" | |||
| #include "btConvexPointCloudShape.h" | |||
| ///not supported on IBM SDK, until we fix the alignment of btVector3 | |||
| #if defined (__CELLOS_LV2__) && defined (__SPU__) | |||
| #include <spu_intrinsics.h> | |||
| static inline vec_float4 vec_dot3( vec_float4 vec0, vec_float4 vec1 ) | |||
| { | |||
| vec_float4 result; | |||
| result = spu_mul( vec0, vec1 ); | |||
| result = spu_madd( spu_rlqwbyte( vec0, 4 ), spu_rlqwbyte( vec1, 4 ), result ); | |||
| return spu_madd( spu_rlqwbyte( vec0, 8 ), spu_rlqwbyte( vec1, 8 ), result ); | |||
| } | |||
| #endif //__SPU__ | |||
| btConvexShape::btConvexShape () | |||
| { | |||
| } | |||
| btConvexShape::~btConvexShape() | |||
| { | |||
| } | |||
| void btConvexShape::project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const | |||
| { | |||
| btVector3 localAxis = dir*trans.getBasis(); | |||
| btVector3 vtx1 = trans(localGetSupportingVertex(localAxis)); | |||
| btVector3 vtx2 = trans(localGetSupportingVertex(-localAxis)); | |||
| min = vtx1.dot(dir); | |||
| max = vtx2.dot(dir); | |||
| if(min>max) | |||
| { | |||
| btScalar tmp = min; | |||
| min = max; | |||
| max = tmp; | |||
| } | |||
| } | |||
| static btVector3 convexHullSupport (const btVector3& localDirOrg, const btVector3* points, int numPoints, const btVector3& localScaling) | |||
| { | |||
| btVector3 vec = localDirOrg * localScaling; | |||
| #if defined (__CELLOS_LV2__) && defined (__SPU__) | |||
| btVector3 localDir = vec; | |||
| vec_float4 v_distMax = {-FLT_MAX,0,0,0}; | |||
| vec_int4 v_idxMax = {-999,0,0,0}; | |||
| int v=0; | |||
| int numverts = numPoints; | |||
| for(;v<(int)numverts-4;v+=4) { | |||
| vec_float4 p0 = vec_dot3(points[v ].get128(),localDir.get128()); | |||
| vec_float4 p1 = vec_dot3(points[v+1].get128(),localDir.get128()); | |||
| vec_float4 p2 = vec_dot3(points[v+2].get128(),localDir.get128()); | |||
| vec_float4 p3 = vec_dot3(points[v+3].get128(),localDir.get128()); | |||
| const vec_int4 i0 = {v ,0,0,0}; | |||
| const vec_int4 i1 = {v+1,0,0,0}; | |||
| const vec_int4 i2 = {v+2,0,0,0}; | |||
| const vec_int4 i3 = {v+3,0,0,0}; | |||
| vec_uint4 retGt01 = spu_cmpgt(p0,p1); | |||
| vec_float4 pmax01 = spu_sel(p1,p0,retGt01); | |||
| vec_int4 imax01 = spu_sel(i1,i0,retGt01); | |||
| vec_uint4 retGt23 = spu_cmpgt(p2,p3); | |||
| vec_float4 pmax23 = spu_sel(p3,p2,retGt23); | |||
| vec_int4 imax23 = spu_sel(i3,i2,retGt23); | |||
| vec_uint4 retGt0123 = spu_cmpgt(pmax01,pmax23); | |||
| vec_float4 pmax0123 = spu_sel(pmax23,pmax01,retGt0123); | |||
| vec_int4 imax0123 = spu_sel(imax23,imax01,retGt0123); | |||
| vec_uint4 retGtMax = spu_cmpgt(v_distMax,pmax0123); | |||
| v_distMax = spu_sel(pmax0123,v_distMax,retGtMax); | |||
| v_idxMax = spu_sel(imax0123,v_idxMax,retGtMax); | |||
| } | |||
| for(;v<(int)numverts;v++) { | |||
| vec_float4 p = vec_dot3(points[v].get128(),localDir.get128()); | |||
| const vec_int4 i = {v,0,0,0}; | |||
| vec_uint4 retGtMax = spu_cmpgt(v_distMax,p); | |||
| v_distMax = spu_sel(p,v_distMax,retGtMax); | |||
| v_idxMax = spu_sel(i,v_idxMax,retGtMax); | |||
| } | |||
| int ptIndex = spu_extract(v_idxMax,0); | |||
| const btVector3& supVec= points[ptIndex] * localScaling; | |||
| return supVec; | |||
| #else | |||
| btScalar newDot,maxDot = btScalar(-BT_LARGE_FLOAT); | |||
| int ptIndex = -1; | |||
| for (int i=0;i<numPoints;i++) | |||
| { | |||
| newDot = vec.dot(points[i]); | |||
| if (newDot > maxDot) | |||
| { | |||
| maxDot = newDot; | |||
| ptIndex = i; | |||
| } | |||
| } | |||
| btAssert(ptIndex >= 0); | |||
| btVector3 supVec = points[ptIndex] * localScaling; | |||
| return supVec; | |||
| #endif //__SPU__ | |||
| } | |||
| btVector3 btConvexShape::localGetSupportVertexWithoutMarginNonVirtual (const btVector3& localDir) const | |||
| { | |||
| switch (m_shapeType) | |||
| { | |||
| case SPHERE_SHAPE_PROXYTYPE: | |||
| { | |||
| return btVector3(0,0,0); | |||
| } | |||
| case BOX_SHAPE_PROXYTYPE: | |||
| { | |||
| btBoxShape* convexShape = (btBoxShape*)this; | |||
| const btVector3& halfExtents = convexShape->getImplicitShapeDimensions(); | |||
| return btVector3(btFsels(localDir.x(), halfExtents.x(), -halfExtents.x()), | |||
| btFsels(localDir.y(), halfExtents.y(), -halfExtents.y()), | |||
| btFsels(localDir.z(), halfExtents.z(), -halfExtents.z())); | |||
| } | |||
| case TRIANGLE_SHAPE_PROXYTYPE: | |||
| { | |||
| btTriangleShape* triangleShape = (btTriangleShape*)this; | |||
| btVector3 dir(localDir.getX(),localDir.getY(),localDir.getZ()); | |||
| btVector3* vertices = &triangleShape->m_vertices1[0]; | |||
| btVector3 dots(dir.dot(vertices[0]), dir.dot(vertices[1]), dir.dot(vertices[2])); | |||
| btVector3 sup = vertices[dots.maxAxis()]; | |||
| return btVector3(sup.getX(),sup.getY(),sup.getZ()); | |||
| } | |||
| case CYLINDER_SHAPE_PROXYTYPE: | |||
| { | |||
| btCylinderShape* cylShape = (btCylinderShape*)this; | |||
| //mapping of halfextents/dimension onto radius/height depends on how cylinder local orientation is (upAxis) | |||
| btVector3 halfExtents = cylShape->getImplicitShapeDimensions(); | |||
| btVector3 v(localDir.getX(),localDir.getY(),localDir.getZ()); | |||
| int cylinderUpAxis = cylShape->getUpAxis(); | |||
| int XX(1),YY(0),ZZ(2); | |||
| switch (cylinderUpAxis) | |||
| { | |||
| case 0: | |||
| { | |||
| XX = 1; | |||
| YY = 0; | |||
| ZZ = 2; | |||
| } | |||
| break; | |||
| case 1: | |||
| { | |||
| XX = 0; | |||
| YY = 1; | |||
| ZZ = 2; | |||
| } | |||
| break; | |||
| case 2: | |||
| { | |||
| XX = 0; | |||
| YY = 2; | |||
| ZZ = 1; | |||
| } | |||
| break; | |||
| default: | |||
| btAssert(0); | |||
| break; | |||
| }; | |||
| btScalar radius = halfExtents[XX]; | |||
| btScalar halfHeight = halfExtents[cylinderUpAxis]; | |||
| btVector3 tmp; | |||
| btScalar d ; | |||
| btScalar s = btSqrt(v[XX] * v[XX] + v[ZZ] * v[ZZ]); | |||
| if (s != btScalar(0.0)) | |||
| { | |||
| d = radius / s; | |||
| tmp[XX] = v[XX] * d; | |||
| tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; | |||
| tmp[ZZ] = v[ZZ] * d; | |||
| return btVector3(tmp.getX(),tmp.getY(),tmp.getZ()); | |||
| } else { | |||
| tmp[XX] = radius; | |||
| tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; | |||
| tmp[ZZ] = btScalar(0.0); | |||
| return btVector3(tmp.getX(),tmp.getY(),tmp.getZ()); | |||
| } | |||
| } | |||
| case CAPSULE_SHAPE_PROXYTYPE: | |||
| { | |||
| btVector3 vec0(localDir.getX(),localDir.getY(),localDir.getZ()); | |||
| btCapsuleShape* capsuleShape = (btCapsuleShape*)this; | |||
| btScalar halfHeight = capsuleShape->getHalfHeight(); | |||
| int capsuleUpAxis = capsuleShape->getUpAxis(); | |||
| btScalar radius = capsuleShape->getRadius(); | |||
| btVector3 supVec(0,0,0); | |||
| btScalar maxDot(btScalar(-BT_LARGE_FLOAT)); | |||
| btVector3 vec = vec0; | |||
| btScalar lenSqr = vec.length2(); | |||
| if (lenSqr < btScalar(0.0001)) | |||
| { | |||
| vec.setValue(1,0,0); | |||
| } else | |||
| { | |||
| btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); | |||
| vec *= rlen; | |||
| } | |||
| btVector3 vtx; | |||
| btScalar newDot; | |||
| { | |||
| btVector3 pos(0,0,0); | |||
| pos[capsuleUpAxis] = halfHeight; | |||
| //vtx = pos +vec*(radius); | |||
| vtx = pos +vec*(radius) - vec * capsuleShape->getMarginNV(); | |||
| newDot = vec.dot(vtx); | |||
| if (newDot > maxDot) | |||
| { | |||
| maxDot = newDot; | |||
| supVec = vtx; | |||
| } | |||
| } | |||
| { | |||
| btVector3 pos(0,0,0); | |||
| pos[capsuleUpAxis] = -halfHeight; | |||
| //vtx = pos +vec*(radius); | |||
| vtx = pos +vec*(radius) - vec * capsuleShape->getMarginNV(); | |||
| newDot = vec.dot(vtx); | |||
| if (newDot > maxDot) | |||
| { | |||
| maxDot = newDot; | |||
| supVec = vtx; | |||
| } | |||
| } | |||
| return btVector3(supVec.getX(),supVec.getY(),supVec.getZ()); | |||
| } | |||
| case CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: | |||
| { | |||
| btConvexPointCloudShape* convexPointCloudShape = (btConvexPointCloudShape*)this; | |||
| btVector3* points = convexPointCloudShape->getUnscaledPoints (); | |||
| int numPoints = convexPointCloudShape->getNumPoints (); | |||
| return convexHullSupport (localDir, points, numPoints,convexPointCloudShape->getLocalScalingNV()); | |||
| } | |||
| case CONVEX_HULL_SHAPE_PROXYTYPE: | |||
| { | |||
| btConvexHullShape* convexHullShape = (btConvexHullShape*)this; | |||
| btVector3* points = convexHullShape->getUnscaledPoints(); | |||
| int numPoints = convexHullShape->getNumPoints (); | |||
| return convexHullSupport (localDir, points, numPoints,convexHullShape->getLocalScalingNV()); | |||
| } | |||
| default: | |||
| #ifndef __SPU__ | |||
| return this->localGetSupportingVertexWithoutMargin (localDir); | |||
| #else | |||
| btAssert (0); | |||
| #endif | |||
| } | |||
| // should never reach here | |||
| btAssert (0); | |||
| return btVector3 (btScalar(0.0f), btScalar(0.0f), btScalar(0.0f)); | |||
| } | |||
| btVector3 btConvexShape::localGetSupportVertexNonVirtual (const btVector3& localDir) const | |||
| { | |||
| btVector3 localDirNorm = localDir; | |||
| if (localDirNorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) | |||
| { | |||
| localDirNorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); | |||
| } | |||
| localDirNorm.normalize (); | |||
| return localGetSupportVertexWithoutMarginNonVirtual(localDirNorm)+ getMarginNonVirtual() * localDirNorm; | |||
| } | |||
| /* TODO: This should be bumped up to btCollisionShape () */ | |||
| btScalar btConvexShape::getMarginNonVirtual () const | |||
| { | |||
| switch (m_shapeType) | |||
| { | |||
| case SPHERE_SHAPE_PROXYTYPE: | |||
| { | |||
| btSphereShape* sphereShape = (btSphereShape*)this; | |||
| return sphereShape->getRadius (); | |||
| } | |||
| case BOX_SHAPE_PROXYTYPE: | |||
| { | |||
| btBoxShape* convexShape = (btBoxShape*)this; | |||
| return convexShape->getMarginNV (); | |||
| } | |||
| case TRIANGLE_SHAPE_PROXYTYPE: | |||
| { | |||
| btTriangleShape* triangleShape = (btTriangleShape*)this; | |||
| return triangleShape->getMarginNV (); | |||
| } | |||
| case CYLINDER_SHAPE_PROXYTYPE: | |||
| { | |||
| btCylinderShape* cylShape = (btCylinderShape*)this; | |||
| return cylShape->getMarginNV(); | |||
| } | |||
| case CAPSULE_SHAPE_PROXYTYPE: | |||
| { | |||
| btCapsuleShape* capsuleShape = (btCapsuleShape*)this; | |||
| return capsuleShape->getMarginNV(); | |||
| } | |||
| case CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: | |||
| /* fall through */ | |||
| case CONVEX_HULL_SHAPE_PROXYTYPE: | |||
| { | |||
| btPolyhedralConvexShape* convexHullShape = (btPolyhedralConvexShape*)this; | |||
| return convexHullShape->getMarginNV(); | |||
| } | |||
| default: | |||
| #ifndef __SPU__ | |||
| return this->getMargin (); | |||
| #else | |||
| btAssert (0); | |||
| #endif | |||
| } | |||
| // should never reach here | |||
| btAssert (0); | |||
| return btScalar(0.0f); | |||
| } | |||
| #ifndef __SPU__ | |||
| void btConvexShape::getAabbNonVirtual (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const | |||
| { | |||
| switch (m_shapeType) | |||
| { | |||
| case SPHERE_SHAPE_PROXYTYPE: | |||
| { | |||
| btSphereShape* sphereShape = (btSphereShape*)this; | |||
| btScalar radius = sphereShape->getImplicitShapeDimensions().getX();// * convexShape->getLocalScaling().getX(); | |||
| btScalar margin = radius + sphereShape->getMarginNonVirtual(); | |||
| const btVector3& center = t.getOrigin(); | |||
| btVector3 extent(margin,margin,margin); | |||
| aabbMin = center - extent; | |||
| aabbMax = center + extent; | |||
| } | |||
| break; | |||
| case CYLINDER_SHAPE_PROXYTYPE: | |||
| /* fall through */ | |||
| case BOX_SHAPE_PROXYTYPE: | |||
| { | |||
| btBoxShape* convexShape = (btBoxShape*)this; | |||
| btScalar margin=convexShape->getMarginNonVirtual(); | |||
| btVector3 halfExtents = convexShape->getImplicitShapeDimensions(); | |||
| halfExtents += btVector3(margin,margin,margin); | |||
| btMatrix3x3 abs_b = t.getBasis().absolute(); | |||
| btVector3 center = t.getOrigin(); | |||
| btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); | |||
| aabbMin = center - extent; | |||
| aabbMax = center + extent; | |||
| break; | |||
| } | |||
| case TRIANGLE_SHAPE_PROXYTYPE: | |||
| { | |||
| btTriangleShape* triangleShape = (btTriangleShape*)this; | |||
| btScalar margin = triangleShape->getMarginNonVirtual(); | |||
| for (int i=0;i<3;i++) | |||
| { | |||
| btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); | |||
| vec[i] = btScalar(1.); | |||
| btVector3 sv = localGetSupportVertexWithoutMarginNonVirtual(vec*t.getBasis()); | |||
| btVector3 tmp = t(sv); | |||
| aabbMax[i] = tmp[i]+margin; | |||
| vec[i] = btScalar(-1.); | |||
| tmp = t(localGetSupportVertexWithoutMarginNonVirtual(vec*t.getBasis())); | |||
| aabbMin[i] = tmp[i]-margin; | |||
| } | |||
| } | |||
| break; | |||
| case CAPSULE_SHAPE_PROXYTYPE: | |||
| { | |||
| btCapsuleShape* capsuleShape = (btCapsuleShape*)this; | |||
| btVector3 halfExtents(capsuleShape->getRadius(),capsuleShape->getRadius(),capsuleShape->getRadius()); | |||
| int m_upAxis = capsuleShape->getUpAxis(); | |||
| halfExtents[m_upAxis] = capsuleShape->getRadius() + capsuleShape->getHalfHeight(); | |||
| halfExtents += btVector3(capsuleShape->getMarginNonVirtual(),capsuleShape->getMarginNonVirtual(),capsuleShape->getMarginNonVirtual()); | |||
| btMatrix3x3 abs_b = t.getBasis().absolute(); | |||
| btVector3 center = t.getOrigin(); | |||
| btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); | |||
| aabbMin = center - extent; | |||
| aabbMax = center + extent; | |||
| } | |||
| break; | |||
| case CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: | |||
| case CONVEX_HULL_SHAPE_PROXYTYPE: | |||
| { | |||
| btPolyhedralConvexAabbCachingShape* convexHullShape = (btPolyhedralConvexAabbCachingShape*)this; | |||
| btScalar margin = convexHullShape->getMarginNonVirtual(); | |||
| convexHullShape->getNonvirtualAabb (t, aabbMin, aabbMax, margin); | |||
| } | |||
| break; | |||
| default: | |||
| #ifndef __SPU__ | |||
| this->getAabb (t, aabbMin, aabbMax); | |||
| #else | |||
| btAssert (0); | |||
| #endif | |||
| break; | |||
| } | |||
| // should never reach here | |||
| btAssert (0); | |||
| } | |||
| #endif //__SPU__ | |||