Danbias/Code/Physics/GamePhysics/Implementation/PhysicsAPI_Impl.cpp

453 lines
15 KiB
C++
Raw Normal View History

#include "PhysicsAPI_Impl.h"
#include "OysterPhysics3D.h"
#include "SimpleRigidBody.h"
#include <BulletWorldImporter\btBulletWorldImporter.h>
#include <codecvt>
2014-01-15 10:44:31 +01:00
using namespace ::Oyster;
using namespace ::Oyster::Physics;
using namespace ::Oyster::Math;
using namespace ::Oyster::Collision3D;
using namespace ::Utility::DynamicMemory;
2013-12-19 10:15:32 +01:00
using namespace ::Utility::Value;
API_Impl API_instance;
2014-02-12 10:23:07 +01:00
2014-02-09 21:24:09 +01:00
API & API::Instance()
{
2014-02-09 21:24:09 +01:00
return API_instance;
}
2014-02-06 21:15:28 +01:00
2014-02-09 21:24:09 +01:00
API_Impl::API_Impl()
{
this->broadphase = NULL;
this->collisionConfiguration = NULL;
this->dispatcher = NULL;
this->solver = NULL;
this->dynamicsWorld = NULL;
this->timeStep = 1.0f/120.0f;
2014-02-11 13:36:14 +01:00
this->gravityPoint = Float3(0.0f, 0.0f, 0.0f);
this->gravity = 10.0f;
2014-02-09 21:24:09 +01:00
}
2014-02-06 21:15:28 +01:00
2014-02-09 21:24:09 +01:00
API_Impl::~API_Impl()
{
delete this->dynamicsWorld;
this->dynamicsWorld = NULL;
delete this->solver;
this->solver = NULL;
delete this->dispatcher;
this->dispatcher = NULL;
delete this->collisionConfiguration;
this->collisionConfiguration = NULL;
delete this->broadphase;
this->broadphase = NULL;
2014-02-06 21:15:28 +01:00
for(unsigned int i = 0; i < this->customBodies.size(); i++)
2014-02-06 21:15:28 +01:00
{
2014-02-09 21:24:09 +01:00
delete this->customBodies[i];
this->customBodies[i] = NULL;
}
}
2014-02-03 10:45:25 +01:00
2014-02-11 13:36:14 +01:00
void API_Impl::SetGravityPoint(::Oyster::Math::Float3 gravityPoint)
{
this->gravityPoint = gravityPoint;
}
void API_Impl::SetGravity(float gravity)
{
this->gravity = gravity;
}
2014-02-09 21:24:09 +01:00
// Bullet physics
ICustomBody* API_Impl::AddCollisionSphere(float radius, ::Oyster::Math::Float4 rotation, ::Oyster::Math::Float3 position, float mass, float restitution, float staticFriction, float dynamicFriction)
2014-02-09 21:24:09 +01:00
{
SimpleRigidBody* body = new SimpleRigidBody;
2014-02-10 15:46:55 +01:00
SimpleRigidBody::State state;
2014-01-22 13:50:54 +01:00
2014-02-09 21:24:09 +01:00
// Add collision shape
btCollisionShape* collisionShape = new btSphereShape(radius);
body->SetCollisionShape(collisionShape);
2014-02-09 21:24:09 +01:00
// Add motion state
btDefaultMotionState* motionState = new btDefaultMotionState(btTransform(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w),btVector3(position.x, position.y, position.z)));
body->SetMotionState(motionState);
2014-01-22 15:29:50 +01:00
2014-02-09 21:24:09 +01:00
// Add rigid body
btVector3 fallInertia(0, 0, 0);
collisionShape->calculateLocalInertia(mass, fallInertia);
btRigidBody::btRigidBodyConstructionInfo rigidBodyCI(mass, motionState, collisionShape, fallInertia);
btRigidBody* rigidBody = new btRigidBody(rigidBodyCI);
2014-02-10 14:22:10 +01:00
rigidBody->setFriction(staticFriction);
rigidBody->setRestitution(restitution);
2014-02-09 21:24:09 +01:00
rigidBody->setUserPointer(body);
body->SetRigidBody(rigidBody);
2014-02-09 21:24:09 +01:00
// Add rigid body to world
this->dynamicsWorld->addRigidBody(rigidBody);
this->customBodies.push_back(body);
2014-02-10 15:46:55 +01:00
state.centerPos = position;
state.reach = Float3(radius, radius, radius);
state.dynamicFrictionCoeff = dynamicFriction;
state.staticFrictionCoeff = staticFriction;
2014-02-10 15:46:55 +01:00
state.quaternion = Quaternion(Float3(rotation.xyz), rotation.w);
state.mass = mass;
body->SetState(state);
2014-02-09 21:24:09 +01:00
return body;
}
ICustomBody* API_Impl::AddCollisionBox(Float3 halfSize, ::Oyster::Math::Float4 rotation, ::Oyster::Math::Float3 position, float mass, float restitution, float staticFriction, float dynamicFriction)
2013-11-28 17:59:12 +01:00
{
2014-02-09 21:24:09 +01:00
SimpleRigidBody* body = new SimpleRigidBody;
2014-02-10 15:46:55 +01:00
SimpleRigidBody::State state;
2014-02-09 21:24:09 +01:00
// Add collision shape
btCollisionShape* collisionShape = new btBoxShape(btVector3(halfSize.x, halfSize.y, halfSize.z));
body->SetCollisionShape(collisionShape);
2014-02-09 21:24:09 +01:00
// Add motion state
btDefaultMotionState* motionState = new btDefaultMotionState(btTransform(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w),btVector3(position.x, position.y, position.z)));
body->SetMotionState(motionState);
2014-02-09 21:24:09 +01:00
// Add rigid body
btVector3 fallInertia(0, 0, 0);
collisionShape->calculateLocalInertia(mass, fallInertia);
btRigidBody::btRigidBodyConstructionInfo rigidBodyCI(mass, motionState, collisionShape, fallInertia);
btRigidBody* rigidBody = new btRigidBody(rigidBodyCI);
2014-02-10 14:22:10 +01:00
rigidBody->setFriction(staticFriction);
rigidBody->setRestitution(restitution);
rigidBody->setUserPointer(body);
body->SetRigidBody(rigidBody);
// Add rigid body to world
this->dynamicsWorld->addRigidBody(rigidBody);
this->customBodies.push_back(body);
2014-02-10 15:46:55 +01:00
state.centerPos = position;
state.reach = halfSize;
state.dynamicFrictionCoeff = dynamicFriction;
state.staticFrictionCoeff = staticFriction;
2014-02-10 15:46:55 +01:00
state.quaternion = Quaternion(Float3(rotation.xyz), rotation.w);
state.mass = mass;
body->SetState(state);
return body;
}
ICustomBody* API_Impl::AddCollisionCylinder(::Oyster::Math::Float3 halfSize, ::Oyster::Math::Float4 rotation, ::Oyster::Math::Float3 position, float mass, float restitution, float staticFriction, float dynamicFriction)
{
SimpleRigidBody* body = new SimpleRigidBody;
2014-02-10 15:46:55 +01:00
SimpleRigidBody::State state;
// Add collision shape
btCollisionShape* collisionShape = new btCylinderShape(btVector3(halfSize.x, halfSize.y, halfSize.z));
body->SetCollisionShape(collisionShape);
// Add motion state
btDefaultMotionState* motionState = new btDefaultMotionState(btTransform(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w),btVector3(position.x, position.y, position.z)));
body->SetMotionState(motionState);
// Add rigid body
2014-02-09 21:24:09 +01:00
btVector3 fallInertia(0, 0, 0);
collisionShape->calculateLocalInertia(mass, fallInertia);
btRigidBody::btRigidBodyConstructionInfo rigidBodyCI(mass, motionState, collisionShape, fallInertia);
btRigidBody* rigidBody = new btRigidBody(rigidBodyCI);
2014-02-10 14:22:10 +01:00
rigidBody->setFriction(staticFriction);
rigidBody->setRestitution(restitution);
2014-02-09 21:24:09 +01:00
rigidBody->setUserPointer(body);
body->SetRigidBody(rigidBody);
2014-02-09 21:24:09 +01:00
// Add rigid body to world
this->dynamicsWorld->addRigidBody(rigidBody);
this->customBodies.push_back(body);
2014-01-29 12:22:18 +01:00
2014-02-10 15:46:55 +01:00
state.centerPos = position;
state.reach = halfSize;
state.dynamicFrictionCoeff = dynamicFriction;
state.staticFrictionCoeff = staticFriction;
2014-02-10 15:46:55 +01:00
state.quaternion = Quaternion(Float3(rotation.xyz), rotation.w);
state.mass = mass;
body->SetState(state);
2014-02-09 21:24:09 +01:00
return body;
}
ICustomBody* API_Impl::AddCharacter(::Oyster::Math::Float height, ::Oyster::Math::Float radius, ::Oyster::Math::Float4 rotation, ::Oyster::Math::Float3 position, float mass, float restitution, float staticFriction, float dynamicFriction)
{
SimpleRigidBody* body = new SimpleRigidBody;
SimpleRigidBody::State state;
// Add collision shape
btCapsuleShape* collisionShape = new btCapsuleShape(radius, height);
body->SetCollisionShape(collisionShape);
// Add motion state
btDefaultMotionState* motionState = new btDefaultMotionState(btTransform(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w),btVector3(position.x, position.y, position.z)));
body->SetMotionState(motionState);
// Add rigid body
btVector3 fallInertia(0, 0, 0);
collisionShape->calculateLocalInertia(mass, fallInertia);
btRigidBody::btRigidBodyConstructionInfo rigidBodyCI(mass, motionState, collisionShape, fallInertia);
btRigidBody* rigidBody = new btRigidBody(rigidBodyCI);
rigidBody->setFriction(staticFriction);
rigidBody->setRestitution(restitution);
rigidBody->setUserPointer(body);
rigidBody->setAngularFactor(0);
rigidBody->setSleepingThresholds(0, 0);
body->SetRigidBody(rigidBody);
// Add rigid body to world
this->dynamicsWorld->addRigidBody(rigidBody);
this->customBodies.push_back(body);
state.centerPos = position;
2014-02-14 11:52:44 +01:00
state.reach = Float3(radius, height, radius);
state.dynamicFrictionCoeff = dynamicFriction;
state.staticFrictionCoeff = staticFriction;
state.quaternion = Quaternion(Float3(rotation.xyz), rotation.w);
state.mass = mass;
body->SetState(state);
return body;
}
ICustomBody* API_Impl::AddTriangleMesh(const std::wstring fileName, ::Oyster::Math::Float4 rotation, ::Oyster::Math::Float3 position, float mass, float restitution, float staticFriction, float dynamicFriction)
{
SimpleRigidBody* body = new SimpleRigidBody;
SimpleRigidBody::State state;
2014-02-26 14:06:02 +01:00
btBulletWorldImporter bulletFile(0);
typedef std::codecvt_utf8<wchar_t> convert_typeX;
std::wstring_convert<convert_typeX, wchar_t> converterX;
2014-02-26 14:08:49 +01:00
std::string bulletPath = converterX.to_bytes(fileName);
// Add collision shape
2014-02-26 14:08:49 +01:00
bulletFile.loadFile(bulletPath.c_str());
btCollisionShape* collisionShape = bulletFile.getCollisionShapeByIndex(0);
body->SetCollisionShape(collisionShape);
// Add motion state
btDefaultMotionState* motionState = new btDefaultMotionState(btTransform(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w),btVector3(position.x, position.y, position.z)));
body->SetMotionState(motionState);
// Add rigid body
btVector3 fallInertia(0, 0, 0);
2014-02-26 14:06:02 +01:00
//collisionShape->calculateLocalInertia(mass, fallInertia);
btRigidBody::btRigidBodyConstructionInfo rigidBodyCI(0, motionState, collisionShape, fallInertia);
btRigidBody* rigidBody = new btRigidBody(rigidBodyCI);
rigidBody->setFriction(staticFriction);
rigidBody->setRestitution(restitution);
rigidBody->setUserPointer(body);
body->SetRigidBody(rigidBody);
// Add rigid body to world
this->dynamicsWorld->addRigidBody(rigidBody);
this->customBodies.push_back(body);
state.centerPos = position;
state.reach = Float3(0, 0, 0);
state.dynamicFrictionCoeff = dynamicFriction;
state.staticFrictionCoeff = staticFriction;
state.quaternion = Quaternion(Float3(rotation.xyz), rotation.w);
2014-02-26 14:06:02 +01:00
state.mass = 0;
body->SetState(state);
return body;
}
void API_Impl::SetTimeStep(float timeStep)
{
this->timeStep = timeStep;
}
2014-02-09 21:24:09 +01:00
void API_Impl::UpdateWorld()
{
2014-02-11 13:36:14 +01:00
for(unsigned int i = 0; i < this->customBodies.size(); i++ )
{
2014-02-14 11:52:44 +01:00
SimpleRigidBody* simpleBody = dynamic_cast<SimpleRigidBody*>(this->customBodies[i]);
this->customBodies[i]->SetGravity(-(this->customBodies[i]->GetState().centerPos - this->gravityPoint).GetNormalized()*this->gravity);
simpleBody->PreStep(this->dynamicsWorld);
2014-02-20 11:13:52 +01:00
if(simpleBody->GetRigidBody()->getActivationState() == ACTIVE_TAG)
{
this->customBodies[i]->CallSubscription_Move();
}
2014-02-21 11:33:57 +01:00
simpleBody->SetPreviousVelocity(simpleBody->GetLinearVelocity());
2014-02-11 13:36:14 +01:00
}
2014-02-26 14:06:02 +01:00
this->dynamicsWorld->stepSimulation(this->timeStep, 1, this->timeStep);
ICustomBody::State state;
2014-02-09 21:24:09 +01:00
for(unsigned int i = 0; i < this->customBodies.size(); i++ )
{
SimpleRigidBody* simpleBody = dynamic_cast<SimpleRigidBody*>(this->customBodies[i]);
2014-02-09 21:24:09 +01:00
btTransform trans;
2014-02-12 14:10:17 +01:00
trans = simpleBody->GetRigidBody()->getWorldTransform();
this->customBodies[i]->SetPosition(Float3(trans.getOrigin().x(), trans.getOrigin().y(), trans.getOrigin().z()));
2014-02-20 11:13:52 +01:00
this->customBodies[i]->SetRotation(Quaternion(Float3(trans.getRotation().x(), trans.getRotation().y(), trans.getRotation().z()), trans.getRotation().w()));
}
2014-02-09 21:24:09 +01:00
int numManifolds = this->dynamicsWorld->getDispatcher()->getNumManifolds();
for (int i = 0; i < numManifolds; i++)
{
2014-02-09 21:24:09 +01:00
btPersistentManifold* contactManifold = this->dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
const btCollisionObject* obA = contactManifold->getBody0();
const btCollisionObject* obB = contactManifold->getBody1();
ICustomBody* bodyA = (ICustomBody*)obA->getUserPointer();
ICustomBody* bodyB = (ICustomBody*)obB->getUserPointer();
2014-02-21 14:09:38 +01:00
int numContacts = contactManifold->getNumContacts();
for (int j=0;j<numContacts;j++)
{
btManifoldPoint& pt = contactManifold->getContactPoint(j);
if (pt.getDistance()<0.f)
{
const btVector3& ptA = pt.getPositionWorldOnA();
const btVector3& ptB = pt.getPositionWorldOnB();
const btVector3& normalOnB = pt.m_normalWorldOnB;
bodyA->CallSubscription_AfterCollisionResponse(bodyA, bodyB, 0.0f);
bodyB->CallSubscription_AfterCollisionResponse(bodyB, bodyA, 0.0f);
}
}
}
}
2014-02-09 21:24:09 +01:00
void API_Impl::Init()
{
2014-02-09 21:24:09 +01:00
this->broadphase = new btDbvtBroadphase();
this->collisionConfiguration = new btDefaultCollisionConfiguration();
this->dispatcher = new btCollisionDispatcher(this->collisionConfiguration);
this->solver = new btSequentialImpulseConstraintSolver;
this->dynamicsWorld = new btDiscreteDynamicsWorld(this->dispatcher,this->broadphase,this->solver,this->collisionConfiguration);
this->dynamicsWorld->setGravity(btVector3(0,-10,0));
}
2014-02-09 21:24:09 +01:00
bool API_Impl::IsInLimbo( const ICustomBody* objRef )
{
2014-02-09 21:24:09 +01:00
return true;
}
2014-02-09 21:24:09 +01:00
void API_Impl::MoveToLimbo( const ICustomBody* objRef )
2014-01-15 10:44:31 +01:00
{
2014-02-09 21:24:09 +01:00
2014-01-15 10:44:31 +01:00
}
2014-02-09 21:24:09 +01:00
void API_Impl::ReleaseFromLimbo( const ICustomBody* objRef )
2014-01-15 10:44:31 +01:00
{
2014-02-09 21:24:09 +01:00
2014-01-15 10:44:31 +01:00
}
2014-02-12 10:23:07 +01:00
void API_Impl::ApplyEffect(Oyster::Collision3D::ICollideable* collideable, void* args, EventAction_ApplyEffect effect)
{
2014-02-12 10:23:07 +01:00
btRigidBody* body;
btCollisionShape* shape;
btMotionState* state;
btRigidBody::btRigidBodyConstructionInfo rigidBodyCI(0, NULL, NULL);
Sphere* sphere;
Box* box;
2014-02-12 10:31:50 +01:00
Cone* cone;
2014-02-12 10:23:07 +01:00
switch(collideable->type)
{
case ICollideable::Type::Type_sphere:
sphere = dynamic_cast<Sphere*>(collideable);
// Add collision shape
shape = new btSphereShape(sphere->radius);
// Add motion state
state = new btDefaultMotionState(btTransform(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f),btVector3(sphere->center.x, sphere->center.y, sphere->center.z)));
// Add rigid body
rigidBodyCI = btRigidBody::btRigidBodyConstructionInfo(0, state, shape);
body = new btRigidBody(rigidBodyCI);
break;
case ICollideable::Type::Type_box:
box = dynamic_cast<Box*>(collideable);
// Add collision shape
shape = new btBoxShape(btVector3(box->boundingOffset.x, box->boundingOffset.y, box->boundingOffset.z));
// Add motion state
state = new btDefaultMotionState(btTransform(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f),btVector3(box->center.x, box->center.y, box->center.z)));
// Add rigid body
rigidBodyCI = btRigidBody::btRigidBodyConstructionInfo(0, state, shape);
body = new btRigidBody(rigidBodyCI);
break;
2014-02-12 10:31:50 +01:00
case ICollideable::Type::Type_cone:
cone = dynamic_cast<Cone*>(collideable);
2014-02-12 10:23:07 +01:00
// Add collision shape
shape = new btConeShapeZ(cone->radius, cone->length);
2014-02-12 10:23:07 +01:00
// Add motion state
state = new btDefaultMotionState(btTransform(btQuaternion(cone->quaternion.x, cone->quaternion.y, cone->quaternion.z, cone->quaternion.w),btVector3(cone->center.x, cone->center.y, cone->center.z)));
2014-02-12 10:23:07 +01:00
// Add rigid body
2014-02-12 10:31:50 +01:00
rigidBodyCI = btRigidBody::btRigidBodyConstructionInfo (0, state, shape);
body = new btRigidBody(rigidBodyCI);
2014-02-12 10:23:07 +01:00
2014-02-12 10:31:50 +01:00
break;
2014-02-12 10:23:07 +01:00
default:
return;
}
ContactSensorCallback callback(*body, effect, args);
this->dynamicsWorld->contactTest(body, callback);
delete state;
state = NULL;
delete shape;
shape = NULL;
delete body;
body = NULL;
}
2014-02-09 21:24:09 +01:00
namespace Oyster
{
namespace Physics
2013-11-28 17:59:12 +01:00
{
2014-02-09 21:24:09 +01:00
namespace Default
{
void EventAction_Destruction( ::Utility::DynamicMemory::UniquePointer<::Oyster::Physics::ICustomBody> proto )
{ /* Do nothing except allowing the proto uniquePointer destroy itself. */ }
2014-02-09 21:24:09 +01:00
::Oyster::Physics::ICustomBody::SubscriptMessage EventAction_BeforeCollisionResponse( const ::Oyster::Physics::ICustomBody *proto, const ::Oyster::Physics::ICustomBody *deuter )
{ /* Do nothing except returning business as usual. */
return ::Oyster::Physics::ICustomBody::SubscriptMessage_none;
}
2014-02-09 21:24:09 +01:00
void EventAction_AfterCollisionResponse( const ::Oyster::Physics::ICustomBody *proto, const ::Oyster::Physics::ICustomBody *deuter, ::Oyster::Math::Float kineticEnergyLoss )
{ /* Do nothing except returning business as usual. */ }
2014-01-22 13:50:54 +01:00
2014-02-09 21:24:09 +01:00
void EventAction_Move( const ::Oyster::Physics::ICustomBody *object )
{ /* Do nothing. */ }
}
}
}