/* Physics Effects Copyright(C) 2011 Sony Computer Entertainment Inc. All rights reserved. Physics Effects is open software; you can redistribute it and/or modify it under the terms of the BSD License. Physics Effects is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the BSD License for more details. A copy of the BSD License is distributed with Physics Effects under the filename: physics_effects_license.txt */ #include "btBulletPhysicsEffectsWorld.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" #include "BulletDynamics/ConstraintSolver/btContactConstraint.h" #include "LinearMath/btAabbUtil2.h" #include "BulletMultiThreaded/SequentialThreadSupport.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "LinearMath/btIDebugDraw.h" #include "LinearMath/btQuickprof.h" #include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h" #include "BulletDynamics/ConstraintSolver/btConstraintSolver.h" #include "BulletPhysicsEffects/btLowLevelData.h" #include #include #include "btLowLevelBroadphase.h" #include "BulletCollision/CollisionShapes/btCompoundShape.h"//required for shape conversion #include "BulletCollision/CollisionShapes/btConvexHullShape.h"//required for shape conversion #include "BulletCollision/CollisionShapes/btCylinderShape.h"//required for shape conversion #include "BulletCollision/CollisionShapes/btSphereShape.h"//required for shape conversion #include "BulletCollision/CollisionShapes/btCapsuleShape.h"//required for shape conversion #include "BulletCollision/CollisionShapes/btBoxShape.h"//required for shape conversion #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" #include "BulletMultiThreaded/vectormath2bullet.h" #ifdef _WIN32 #include "BulletMultiThreaded/Win32ThreadSupport.h" #endif #ifdef USE_PE_GATHER_SCATTER_SPURS_TASK #include "SpuDispatch/BulletPEGatherScatterSpursSupport.h" #include "SpuDispatch/SpuPEGatherScatterTaskProcess.h" #endif btBulletPhysicsEffectsWorld::btBulletPhysicsEffectsWorld(btLowLevelData* lowLevelData, btDispatcher* dispatcher,btLowLevelBroadphase* broadphase,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration, btThreadSupportInterface* threadSupport) :btDiscreteDynamicsWorld(dispatcher,broadphase,constraintSolver,collisionConfiguration), m_lowLevelData(lowLevelData) { #ifdef USE_PE_GATHER_SCATTER_SPURS_TASK int numGatherScatterSpus = threadSupport->getNumTasks(); m_PEGatherScatterProcess = new SpuPEGatherScatterTaskProcess(threadSupport,numGatherScatterSpus); #endif //USE_PE_GATHER_SCATTER_SPURS_TASK m_lowLevelStates.resize(broadphase->m_maxHandles);//or use expandNonInitializing? m_lowLevelBodies.resize(broadphase->m_maxHandles); m_lowLevelSolverBodies.resize(broadphase->m_maxHandles); m_lowLevelCollidables.resize(broadphase->m_maxHandles); m_lowLevelData->m_states = &m_lowLevelStates[0]; m_lowLevelData->m_collidables = &m_lowLevelCollidables[0]; m_lowLevelData->m_bodies = &m_lowLevelBodies[0]; m_lowLevelData->m_solverBodies = &m_lowLevelSolverBodies[0]; m_lowLevelData->m_numRigidBodies = broadphase->m_maxHandles; } btBulletPhysicsEffectsWorld::~btBulletPhysicsEffectsWorld() { #ifdef USE_PE_GATHER_SCATTER_SPURS_TASK delete m_PEGatherScatterProcess; #endif } void btBulletPhysicsEffectsWorld::integrateTransforms(btScalar timeStep) { ///integrate transforms #ifdef USE_PE_GATHER_SCATTER_SPURS_TASK if (getDispatchInfo().m_enableSPU) { BT_PROFILE("integrateTransformsSPU"); int numRemainingObjects = m_nonStaticRigidBodies.size(); int batchSize = PARALLEL_BATCH_SIZE; int startIndex = 0; while (numRemainingObjects>0) { int currentBatchSize = numRemainingObjects > batchSize? batchSize : numRemainingObjects; //issue and flush is likely to be called every frame, move the construction and deletion out of the inner loop (at construction/init etc) m_PEGatherScatterProcess->issueTask( CMD_SAMPLE_INTEGRATE_BODIES, &m_nonStaticRigidBodies[0], 0, 0, startIndex, currentBatchSize); numRemainingObjects -= currentBatchSize; startIndex += currentBatchSize; } m_PEGatherScatterProcess->flush(); } else #endif //USE_PE_GATHER_SCATTER_SPURS_TASK { // BT_PROFILE("integrateTransforms"); btDiscreteDynamicsWorld::integrateTransforms(timeStep); } } void btBulletPhysicsEffectsWorld::predictUnconstraintMotion(btScalar timeStep) { #ifdef USE_PE_GATHER_SCATTER_SPURS_TASK if (getDispatchInfo().m_enableSPU) { BT_PROFILE("predictUnconstraintMotionSPU"); int numRemainingObjects = m_nonStaticRigidBodies.size(); int batchSize = PARALLEL_BATCH_SIZE; int startIndex=0; while (numRemainingObjects>0) { int currentBatchSize = numRemainingObjects > batchSize? batchSize : numRemainingObjects; //issue and flush is likely to be called every frame, move the construction and deletion out of the inner loop (at construction/init etc) m_PEGatherScatterProcess->issueTask( CMD_SAMPLE_PREDICT_MOTION_BODIES, &m_nonStaticRigidBodies[0], 0, 0, startIndex, currentBatchSize); numRemainingObjects -= currentBatchSize; startIndex += currentBatchSize; } m_PEGatherScatterProcess->flush(); } else #endif //USE_PE_GATHER_SCATTER_SPURS_TASK { btDiscreteDynamicsWorld::predictUnconstraintMotion( timeStep); } for ( int i=0;isetHitFraction(1.f); if (body->isActive() && (!body->isStaticOrKinematicObject())) { syncRigidBodyState(body); } } } void btBulletPhysicsEffectsWorld::solveConstraints(btContactSolverInfo& solverInfo) { BT_PROFILE("solveConstraints"); btCollisionDispatcher* disp = (btCollisionDispatcher*) getDispatcher(); int numBodies = getNumCollisionObjects(); btPersistentManifold** manifolds = disp->getInternalManifoldPointer(); int numManifolds = disp->getNumManifolds(); if ((getNumCollisionObjects()>0) && (numManifolds + m_constraints.size()>0)) { btCollisionObject** bodies = numBodies ? &getCollisionObjectArray()[0] : 0; btTypedConstraint** constraints = m_constraints.size() ? &m_constraints[0] : 0; getConstraintSolver()->solveGroup( bodies,numBodies, disp->getInternalManifoldPointer(),numManifolds, constraints, m_constraints.size() ,m_solverInfo,m_debugDrawer,m_stackAlloc,disp); } } void btBulletPhysicsEffectsWorld::calculateSimulationIslands() { } static void convertShape(btCollisionShape* bulletShape, btAlignedObjectArray& shapes) { switch (bulletShape->getShapeType()) { case BOX_SHAPE_PROXYTYPE: { btBoxShape* boxshape = (btBoxShape*)bulletShape; sce::PhysicsEffects::PfxBox box(boxshape->getHalfExtentsWithMargin().getX(),boxshape->getHalfExtentsWithMargin().getY(),boxshape->getHalfExtentsWithMargin().getZ()); sce::PhysicsEffects::PfxShape& shape = shapes.expand(); shape.reset(); shape.setBox(box); break; } case TRIANGLE_MESH_SHAPE_PROXYTYPE: { btBvhTriangleMeshShape* trimesh = (btBvhTriangleMeshShape*) bulletShape; int numSubParts = trimesh->getMeshInterface()->getNumSubParts(); btAssert(numSubParts>0); for (int i=0;igetMeshInterface()->getLockedVertexIndexBase(&vertexBase,numVerts,vertexType,vertexStride,&indexBase,indexStride,numFaces,indexType,i); sce::PhysicsEffects::PfxCreateLargeTriMeshParam param; btAssert(param.flag&SCE_PFX_MESH_FLAG_16BIT_INDEX); unsigned short int* copyIndices = new unsigned short int[numFaces*3]; switch (indexType) { case PHY_UCHAR: { for (int p=0;pgetRadius()); sce::PhysicsEffects::PfxShape& shape = shapes.expand(); shape.reset(); shape.setSphere(sphere); break; } case CAPSULE_SHAPE_PROXYTYPE: { btCapsuleShape* capsuleshape= (btCapsuleShape*)bulletShape;//assume btCapsuleShapeX for now sce::PhysicsEffects::PfxCapsule capsule(capsuleshape->getHalfHeight(),capsuleshape->getRadius()); sce::PhysicsEffects::PfxShape& shape = shapes.expand(); shape.reset(); shape.setCapsule(capsule); break; } case CYLINDER_SHAPE_PROXYTYPE: { btCylinderShape* cylindershape= (btCylinderShape*)bulletShape;//assume btCylinderShapeX for now sce::PhysicsEffects::PfxCylinder cylinder(cylindershape->getHalfExtentsWithMargin()[0],cylindershape->getRadius()); sce::PhysicsEffects::PfxShape& shape = shapes.expand(); shape.reset(); shape.setCylinder(cylinder); break; } case CONVEX_HULL_SHAPE_PROXYTYPE: { btConvexHullShape* convexHullShape = (btConvexHullShape*)bulletShape; sce::PhysicsEffects::PfxConvexMesh* convex = new sce::PhysicsEffects::PfxConvexMesh(); convex->m_numVerts = convexHullShape->getNumPoints(); convex->m_numIndices = 0;//todo for ray intersection test support for (int i=0;im_numVerts;i++) { convex->m_verts[i].setX(convexHullShape->getPoints()[i].getX()); convex->m_verts[i].setY(convexHullShape->getPoints()[i].getY()); convex->m_verts[i].setZ(convexHullShape->getPoints()[i].getZ()); } convex->updateAABB(); sce::PhysicsEffects::PfxShape& shape = shapes.expand(); shape.reset(); shape.setConvexMesh(convex); break; } case COMPOUND_SHAPE_PROXYTYPE: { btCompoundShape* compound = (btCompoundShape*) bulletShape; for (int s=0;sgetNumChildShapes();s++) { convertShape(compound->getChildShape(s),shapes); sce::PhysicsEffects::PfxMatrix3 rotMat = getVmMatrix3(compound->getChildTransform(s).getBasis()); sce::PhysicsEffects::PfxVector3 translate = getVmVector3(compound->getChildTransform(s).getOrigin()); sce::PhysicsEffects::PfxTransform3 childtransform(rotMat,translate); shapes[shapes.size()-1].setOffsetTransform(childtransform); } break; } default: { btAssert(0); } }; } void btBulletPhysicsEffectsWorld::createStateAndCollidable(btRigidBody* body) { int objectIndex = body->getBroadphaseProxy()->m_uniqueId; btAssert(objectIndex>=0); //btAssert(objectIndexreset(); pfxbody->reset(); pfxcollidable->reset(); pfxbody->setFriction(body->getFriction()); pfxbody->setRestitution(body->getRestitution()); if (body->getInvMass()) { btScalar mass = 1.f/body->getInvMass(); pfxbody->setMass(mass); Vectormath::Aos::Matrix3 inertiaInv = inertiaInv.identity(); inertiaInv.setElem(0,0,body->getInvInertiaDiagLocal().getX()); inertiaInv.setElem(1,1,body->getInvInertiaDiagLocal().getY()); inertiaInv.setElem(2,2,body->getInvInertiaDiagLocal().getZ()); pfxbody->setInertiaInv(inertiaInv); pfxstate->setMotionType(sce::PhysicsEffects::kPfxMotionTypeActive); } else { pfxstate->setMotionType(sce::PhysicsEffects::kPfxMotionTypeFixed); } btAlignedObjectArray shapes; convertShape(body->getCollisionShape(), shapes); btAssert(shapes.size()>0); if (shapes.size()==1) { pfxcollidable->addShape(shapes[0]); pfxcollidable->finish(); } else { if (shapes.size()>1) { sce::PhysicsEffects::PfxUInt16* ints=new sce::PhysicsEffects::PfxUInt16[shapes.size()]; sce::PhysicsEffects::PfxShape* pfxshapes = new sce::PhysicsEffects::PfxShape[shapes.size()]; int p; for (p=0;preset(pfxshapes,ints,shapes.size()); for (p=0;paddShape(pfxshapes[p]); } pfxcollidable->finish(); } } pfxstate->setRigidBodyId(objectIndex); syncRigidBodyState(body); } void btBulletPhysicsEffectsWorld::syncRigidBodyState(btRigidBody* body) { int objectIndex = body->getBroadphaseProxy()->m_uniqueId; sce::PhysicsEffects::PfxRigidState* pfxstate = &m_lowLevelStates[objectIndex]; pfxstate->setPosition(sce::PhysicsEffects::PfxVector3(body->getWorldTransform().getOrigin()[0],body->getWorldTransform().getOrigin()[1],body->getWorldTransform().getOrigin()[2])); sce::PhysicsEffects::PfxQuat rot(body->getOrientation().getX(),body->getOrientation().getY(),body->getOrientation().getZ(),body->getOrientation().getW()); pfxstate->setOrientation(rot); } void btBulletPhysicsEffectsWorld::addRigidBody(btRigidBody* body) { btDiscreteDynamicsWorld::addRigidBody(body); //create a state and collidable createStateAndCollidable(body); // m_lowLevelData->m_numRigidBodies++; // btAssert(m_lowLevelData->m_numRigidBodiesm_maxNumRigidBodies); } void btBulletPhysicsEffectsWorld::addRigidBody(btRigidBody* body, short group, short mask) { btDiscreteDynamicsWorld::addRigidBody(body,group,mask); } void btBulletPhysicsEffectsWorld::removeRigidBody(btRigidBody* body) { btDiscreteDynamicsWorld::removeRigidBody(body); // m_lowLevelData->m_numRigidBodies--; // btAssert(m_lowLevelData->m_numRigidBodies>=0); }