mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-27 03:26:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			375 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			375 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "physic.hpp"
 | |
| #include <btBulletDynamicsCommon.h>
 | |
| #include <btBulletCollisionCommon.h>
 | |
| #include <components/nifbullet/bullet_nif_loader.hpp>
 | |
| //#include <apps\openmw\mwworld\world.hpp>
 | |
| #include "CMotionState.h"
 | |
| #include "OgreRoot.h"
 | |
| #include "btKinematicCharacterController.h"
 | |
| #include "BtOgrePG.h"
 | |
| #include "BtOgreGP.h"
 | |
| #include "BtOgreExtras.h"
 | |
| 
 | |
| #define BIT(x) (1<<(x))
 | |
| 
 | |
| namespace OEngine {
 | |
| namespace Physic
 | |
| {
 | |
|     enum collisiontypes {
 | |
|         COL_NOTHING = 0, //<Collide with nothing
 | |
|         COL_WORLD = BIT(0), //<Collide with world objects
 | |
|         COL_ACTOR_INTERNAL = BIT(1), //<Collide internal capsule
 | |
|         COL_ACTOR_EXTERNAL = BIT(2) //<collide with external capsule
 | |
|     };
 | |
| 
 | |
|     PhysicActor::PhysicActor(std::string name)
 | |
|     {
 | |
|         mName = name;
 | |
| 
 | |
|         // The capsule is at the origin
 | |
|         btTransform transform;
 | |
|         transform.setIdentity();
 | |
| 
 | |
|         // External capsule
 | |
|         externalGhostObject = new PairCachingGhostObject(name);
 | |
|         externalGhostObject->setWorldTransform( transform );
 | |
| 
 | |
|         btScalar externalCapsuleHeight = 120;
 | |
|         btScalar externalCapsuleWidth = 19;
 | |
| 
 | |
|         externalCollisionShape = new btCapsuleShapeZ( externalCapsuleWidth,  externalCapsuleHeight );
 | |
|         externalCollisionShape->setMargin( 0.1 );
 | |
| 
 | |
|         externalGhostObject->setCollisionShape( externalCollisionShape );
 | |
|         externalGhostObject->setCollisionFlags( btCollisionObject::CF_CHARACTER_OBJECT );
 | |
| 
 | |
|         // Internal capsule
 | |
|         internalGhostObject = new PairCachingGhostObject(name);
 | |
|         internalGhostObject->setWorldTransform( transform );
 | |
|         //internalGhostObject->getBroadphaseHandle()->s
 | |
|         btScalar internalCapsuleHeight =  110;
 | |
|         btScalar internalCapsuleWidth =  17;
 | |
| 
 | |
|         internalCollisionShape = new btCapsuleShapeZ( internalCapsuleWidth, internalCapsuleHeight );
 | |
|         internalCollisionShape->setMargin( 0.1 );
 | |
| 
 | |
|         internalGhostObject->setCollisionShape( internalCollisionShape );
 | |
|         internalGhostObject->setCollisionFlags( btCollisionObject::CF_CHARACTER_OBJECT );
 | |
| 
 | |
|         mCharacter = new btKinematicCharacterController( externalGhostObject,internalGhostObject,btScalar( 40 ),1,4,20,9.8,0.2 );
 | |
|         mCharacter->setUpAxis(btKinematicCharacterController::Z_AXIS);
 | |
|         mCharacter->setUseGhostSweepTest(false);
 | |
| 
 | |
|         mCharacter->mCollision = false;
 | |
|         setGravity(0);
 | |
| 
 | |
|         mTranslation = btVector3(0,0,70);
 | |
|     }
 | |
| 
 | |
|     PhysicActor::~PhysicActor()
 | |
|     {
 | |
|         delete mCharacter;
 | |
|         delete internalGhostObject;
 | |
|         delete internalCollisionShape;
 | |
|         delete externalGhostObject;
 | |
|         delete externalCollisionShape;
 | |
|     }
 | |
| 
 | |
|     void PhysicActor::setGravity(float gravity)
 | |
|     {
 | |
|         mCharacter->setGravity(gravity);
 | |
|         //mCharacter->
 | |
|     }
 | |
| 
 | |
|     void PhysicActor::enableCollisions(bool collision)
 | |
|     {
 | |
|         mCharacter->mCollision = collision;
 | |
|     }
 | |
| 
 | |
|     void PhysicActor::setVerticalVelocity(float z)
 | |
|     {
 | |
|         mCharacter->setVerticalVelocity(z);
 | |
|     }
 | |
| 
 | |
|     bool PhysicActor::getCollisionMode()
 | |
|     {
 | |
|         return mCharacter->mCollision;
 | |
|     }
 | |
| 
 | |
|     void PhysicActor::setWalkDirection(const btVector3& mvt)
 | |
|     {
 | |
|         mCharacter->setWalkDirection( mvt );
 | |
|     }
 | |
| 
 | |
|     void PhysicActor::Rotate(const btQuaternion& quat)
 | |
|     {
 | |
|         externalGhostObject->getWorldTransform().setRotation( externalGhostObject->getWorldTransform().getRotation() * quat );
 | |
|         internalGhostObject->getWorldTransform().setRotation( internalGhostObject->getWorldTransform().getRotation() * quat );
 | |
|     }
 | |
| 
 | |
|     void PhysicActor::setRotation(const btQuaternion& quat)
 | |
|     {
 | |
|         externalGhostObject->getWorldTransform().setRotation( quat );
 | |
|         internalGhostObject->getWorldTransform().setRotation( quat );
 | |
|     }
 | |
| 
 | |
|     btVector3 PhysicActor::getPosition(void)
 | |
|     {
 | |
|         return internalGhostObject->getWorldTransform().getOrigin() -mTranslation;
 | |
|     }
 | |
| 
 | |
|     btQuaternion PhysicActor::getRotation(void)
 | |
|     {
 | |
|         return internalGhostObject->getWorldTransform().getRotation();
 | |
|     }
 | |
| 
 | |
|     void PhysicActor::setPosition(const btVector3& pos)
 | |
|     {
 | |
|         internalGhostObject->getWorldTransform().setOrigin(pos+mTranslation);
 | |
|         externalGhostObject->getWorldTransform().setOrigin(pos+mTranslation);
 | |
|     }
 | |
| 
 | |
|     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 | |
|     //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| 
 | |
|     RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name)
 | |
|         :btRigidBody(CI),mName(name)
 | |
|     {
 | |
| 
 | |
|     };
 | |
| 
 | |
| 
 | |
| 
 | |
|     ///////////////////////////////////////////////////////////////////////////////////////////////////////
 | |
|     ///////////////////////////////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| 
 | |
| 
 | |
|     PhysicEngine::PhysicEngine(BulletShapeLoader* shapeLoader)
 | |
|     {
 | |
|         // Set up the collision configuration and dispatcher
 | |
|         collisionConfiguration = new btDefaultCollisionConfiguration();
 | |
|         dispatcher = new btCollisionDispatcher(collisionConfiguration);
 | |
| 
 | |
|         // The actual physics solver
 | |
|         solver = new btSequentialImpulseConstraintSolver;
 | |
| 
 | |
|         //TODO: memory leak?
 | |
|         btOverlappingPairCache* pairCache = new btSortedOverlappingPairCache();
 | |
|         //pairCache->setInternalGhostPairCallback( new btGhostPairCallback() );
 | |
| 
 | |
|         broadphase = new btDbvtBroadphase(pairCache);
 | |
| 
 | |
|         // The world.
 | |
|         dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);
 | |
|         dynamicsWorld->setGravity(btVector3(0,0,-10));
 | |
| 
 | |
|         if(BulletShapeManager::getSingletonPtr() == NULL)
 | |
|         {
 | |
|             new BulletShapeManager();
 | |
|         }
 | |
|         //TODO:singleton?
 | |
|         mShapeLoader = shapeLoader;
 | |
| 
 | |
|         isDebugCreated = false;
 | |
|     }
 | |
| 
 | |
|     void PhysicEngine::createDebugRendering()
 | |
|     {
 | |
|         if(!isDebugCreated)
 | |
|         {
 | |
|             Ogre::SceneManagerEnumerator::SceneManagerIterator iter = Ogre::Root::getSingleton().getSceneManagerIterator();
 | |
|             iter.begin();
 | |
|             Ogre::SceneManager* scn = iter.getNext();
 | |
|             Ogre::SceneNode* node = scn->getRootSceneNode()->createChildSceneNode();
 | |
|             node->pitch(Ogre::Degree(-90));
 | |
|             mDebugDrawer = new BtOgre::DebugDrawer(node, dynamicsWorld);
 | |
|             dynamicsWorld->setDebugDrawer(mDebugDrawer);
 | |
|             isDebugCreated = true;
 | |
|             dynamicsWorld->debugDrawWorld();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void PhysicEngine::setDebugRenderingMode(int mode)
 | |
|     {
 | |
|         if(!isDebugCreated)
 | |
|         {
 | |
|             createDebugRendering();
 | |
|         }
 | |
|         mDebugDrawer->setDebugMode(mode);
 | |
|     }
 | |
| 
 | |
|     PhysicEngine::~PhysicEngine()
 | |
|     {
 | |
|         delete dynamicsWorld;
 | |
|         delete solver;
 | |
|         delete collisionConfiguration;
 | |
|         delete dispatcher;
 | |
|         delete broadphase;
 | |
|         delete mShapeLoader;
 | |
|     }
 | |
| 
 | |
|     RigidBody* PhysicEngine::createRigidBody(std::string mesh,std::string name,float scale)
 | |
|     {
 | |
|         //get the shape from the .nif
 | |
|         mShapeLoader->load(mesh,"General");
 | |
|         BulletShapeManager::getSingletonPtr()->load(mesh,"General");
 | |
|         BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(mesh,"General");
 | |
|         shape->Shape->setLocalScaling(btVector3(scale,scale,scale));
 | |
| 
 | |
|         //create the motionState
 | |
|         CMotionState* newMotionState = new CMotionState(this,name);
 | |
| 
 | |
|         //create the real body
 | |
|         btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,newMotionState,shape->Shape);
 | |
|         RigidBody* body = new RigidBody(CI,name);
 | |
|         body->collide = shape->collide;
 | |
|         return body;
 | |
|     }
 | |
| 
 | |
|     void PhysicEngine::addRigidBody(RigidBody* body)
 | |
|     {
 | |
|         if(body->collide)
 | |
|         {
 | |
|             dynamicsWorld->addRigidBody(body,COL_WORLD,COL_WORLD|COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             dynamicsWorld->addRigidBody(body,COL_WORLD,COL_NOTHING);
 | |
|         }
 | |
|         body->setActivationState(DISABLE_DEACTIVATION);
 | |
|         RigidBodyMap[body->mName] = body;
 | |
|     }
 | |
| 
 | |
|     void PhysicEngine::removeRigidBody(std::string name)
 | |
|     {
 | |
|         std::map<std::string,RigidBody*>::iterator it = RigidBodyMap.find(name);
 | |
|         if (it != RigidBodyMap.end() )
 | |
|         {
 | |
|             RigidBody* body = it->second;
 | |
|             if(body != NULL)
 | |
|             {
 | |
|                 // broadphase->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(body->getBroadphaseProxy(),dispatcher);
 | |
|                 /*std::map<std::string,PhysicActor*>::iterator it2 = PhysicActorMap.begin();
 | |
|                   for(;it2!=PhysicActorMap.end();it++)
 | |
|                   {
 | |
|                   it2->second->internalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(body->getBroadphaseProxy(),dispatcher);
 | |
|                   it2->second->externalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(body->getBroadphaseProxy(),dispatcher);
 | |
|                   }*/
 | |
|                 dynamicsWorld->removeRigidBody(RigidBodyMap[name]);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void PhysicEngine::deleteRigidBody(std::string name)
 | |
|     {
 | |
|         std::map<std::string,RigidBody*>::iterator it = RigidBodyMap.find(name);
 | |
|         if (it != RigidBodyMap.end() )
 | |
|         {
 | |
|             RigidBody* body = it->second;
 | |
|             if(body != NULL)
 | |
|             {
 | |
|                 delete body;
 | |
|             }
 | |
|             RigidBodyMap.erase(it);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     RigidBody* PhysicEngine::getRigidBody(std::string name)
 | |
|     {
 | |
|         RigidBody* body = RigidBodyMap[name];
 | |
|         return body;
 | |
|     }
 | |
| 
 | |
|     void PhysicEngine::stepSimulation(double deltaT)
 | |
|     {
 | |
|         dynamicsWorld->stepSimulation(deltaT,1,1/50.);
 | |
|         if(isDebugCreated)
 | |
|         {
 | |
|             mDebugDrawer->step();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void PhysicEngine::addCharacter(std::string name)
 | |
|     {
 | |
|         PhysicActor* newActor = new PhysicActor(name);
 | |
|         dynamicsWorld->addCollisionObject( newActor->externalGhostObject, COL_ACTOR_EXTERNAL, COL_WORLD |COL_ACTOR_EXTERNAL );
 | |
|         dynamicsWorld->addCollisionObject( newActor->internalGhostObject, COL_ACTOR_INTERNAL, COL_WORLD |COL_ACTOR_INTERNAL );
 | |
|         dynamicsWorld->addAction( newActor->mCharacter );
 | |
|         PhysicActorMap[name] = newActor;
 | |
|     }
 | |
| 
 | |
|     void PhysicEngine::removeCharacter(std::string name)
 | |
|     {
 | |
|         //std::cout << "remove";
 | |
|         std::map<std::string,PhysicActor*>::iterator it = PhysicActorMap.find(name);
 | |
|         if (it != PhysicActorMap.end() )
 | |
|         {
 | |
|             PhysicActor* act = it->second;
 | |
|             if(act != NULL)
 | |
|             {
 | |
|                 /*broadphase->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(act->externalGhostObject->getBroadphaseHandle(),dispatcher);
 | |
|                   broadphase->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(act->internalGhostObject->getBroadphaseHandle(),dispatcher);
 | |
|                   std::map<std::string,PhysicActor*>::iterator it2 = PhysicActorMap.begin();
 | |
|                   for(;it2!=PhysicActorMap.end();it++)
 | |
|                   {
 | |
|                   it->second->internalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(act->externalGhostObject->getBroadphaseHandle(),dispatcher);
 | |
|                   it->second->externalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(act->externalGhostObject->getBroadphaseHandle(),dispatcher);
 | |
|                   it->second->internalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(act->internalGhostObject->getBroadphaseHandle(),dispatcher);
 | |
|                   it->second->externalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(act->internalGhostObject->getBroadphaseHandle(),dispatcher);
 | |
|                   }*/
 | |
|                 //act->externalGhostObject->
 | |
|                 dynamicsWorld->removeCollisionObject(act->externalGhostObject);
 | |
|                 dynamicsWorld->removeCollisionObject(act->internalGhostObject);
 | |
|                 dynamicsWorld->removeAction(act->mCharacter);
 | |
|                 delete act;
 | |
|             }
 | |
|             PhysicActorMap.erase(it);
 | |
|         }
 | |
|         //std::cout << "ok";
 | |
|     }
 | |
| 
 | |
|     PhysicActor* PhysicEngine::getCharacter(std::string name)
 | |
|     {
 | |
|         PhysicActor* act = PhysicActorMap[name];
 | |
|         return act;
 | |
|     }
 | |
| 
 | |
|     void PhysicEngine::emptyEventLists(void)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     std::pair<std::string,float> PhysicEngine::rayTest(btVector3& from,btVector3& to)
 | |
|     {
 | |
|         std::string name = "";
 | |
|         float d = -1;
 | |
| 
 | |
|         float d1 = 10000.;
 | |
|         btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to);
 | |
|         resultCallback1.m_collisionFilterMask = COL_WORLD;
 | |
|         dynamicsWorld->rayTest(from, to, resultCallback1);
 | |
|         if (resultCallback1.hasHit())
 | |
|         {
 | |
|             name = static_cast<RigidBody&>(*resultCallback1.m_collisionObject).mName;
 | |
|             d1 = resultCallback1.m_closestHitFraction;
 | |
|             d = d1;
 | |
|         }
 | |
| 
 | |
|         btCollisionWorld::ClosestRayResultCallback resultCallback2(from, to);
 | |
|         resultCallback2.m_collisionFilterMask = COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL;
 | |
|         dynamicsWorld->rayTest(from, to, resultCallback2);
 | |
|         float d2 = 10000.;
 | |
|         if (resultCallback2.hasHit())
 | |
|         {
 | |
|             d2 = resultCallback1.m_closestHitFraction;
 | |
|             if(d2<=d1)
 | |
|             {
 | |
|                 name = static_cast<PairCachingGhostObject&>(*resultCallback2.m_collisionObject).mName;
 | |
|                 d = d2;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return std::pair<std::string,float>(name,d);
 | |
|     }
 | |
| }};
 |