822 lines
24 KiB
C++
822 lines
24 KiB
C++
/* -----------------------------------------------------------------------------
|
|
GSFramework
|
|
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
#include "physic_bullet/bullet_item.h"
|
|
#include "physic_bullet/bullet_world.h"
|
|
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
|
|
#include "physic_bullet/bullet_character_controller.h"
|
|
#include "physic/physic_item_desc.h"
|
|
#include "core/item.h"
|
|
#include "core/terrain.h"
|
|
#include "scene3d/mitem.h"
|
|
#include "math/matrix4.h"
|
|
#include "log/log.h"
|
|
|
|
using namespace GS;
|
|
using namespace GS::S3D;
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
static Vector4 btTonVector(const btVector3 &v)
|
|
{ return Vector4(v.x(), v.y(), v.z()); }
|
|
static btVector3 nTobtVector(const Vector4 &v)
|
|
{ return btVector3(v.x, v.y, v.z); }
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void BulletMotionState::setWorldTransform(const btTransform &comt)
|
|
{
|
|
btTransform wt = comt;
|
|
const Vector4 &com = item->GetCenter();
|
|
wt.setOrigin(wt.getOrigin() - wt.getBasis() * btVector3(com.x, com.y, com.z));
|
|
item->TransformToMatrix4(wt, bullet_matrix);
|
|
bullet_matrix = bullet_matrix * Matrix4::ScaleMatrix(item->GetScale());
|
|
}
|
|
void BulletMotionState::getWorldTransform(btTransform &wt) const
|
|
{
|
|
item->TransformFromMatrix4(engine_matrix, wt);
|
|
const Vector4 &com = item->GetCenter();
|
|
wt.setOrigin(wt.getOrigin() + wt.getBasis() * btVector3(com.x, com.y, com.z));
|
|
}
|
|
BulletMotionState::BulletMotionState(BulletPhysicItem *_item) : item(_item)
|
|
{
|
|
MItem *mitem = (MItem *)_item->GetUserPointer();
|
|
bullet_matrix = mitem->GetBaseItem()->GetMatrix();
|
|
engine_matrix = bullet_matrix;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
uint BulletPhysicItem::GetSelfMask() const
|
|
{
|
|
btBroadphaseProxy *handle = NULL;
|
|
if (rigid_body)
|
|
handle = rigid_body->getBroadphaseHandle();
|
|
if (ghost_object)
|
|
handle = ghost_object->getBroadphaseHandle();
|
|
|
|
return handle ? handle->m_collisionFilterGroup : 0;
|
|
}
|
|
void BulletPhysicItem::SetSelfMask(uint m)
|
|
{
|
|
self_mask = m;
|
|
|
|
btBroadphaseProxy *handle = NULL;
|
|
if (rigid_body)
|
|
handle = rigid_body->getBroadphaseHandle();
|
|
if (ghost_object)
|
|
handle = ghost_object->getBroadphaseHandle();
|
|
|
|
if (handle)
|
|
{
|
|
handle->m_collisionFilterGroup = (short)m;
|
|
|
|
// Refresh pair cache.
|
|
btworld->getBroadphase()->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(handle, btworld->getDispatcher());
|
|
}
|
|
}
|
|
uint BulletPhysicItem::GetCollisionMask() const
|
|
{
|
|
btBroadphaseProxy *handle = NULL;
|
|
if (rigid_body)
|
|
handle = rigid_body->getBroadphaseHandle();
|
|
if (ghost_object)
|
|
handle = ghost_object->getBroadphaseHandle();
|
|
|
|
return handle ? handle->m_collisionFilterMask : 0;
|
|
}
|
|
void BulletPhysicItem::SetCollisionMask(uint m)
|
|
{
|
|
collision_mask = m;
|
|
|
|
btBroadphaseProxy *handle = NULL;
|
|
if (rigid_body)
|
|
handle = rigid_body->getBroadphaseHandle();
|
|
if (ghost_object)
|
|
handle = ghost_object->getBroadphaseHandle();
|
|
|
|
if (handle)
|
|
{
|
|
handle->m_collisionFilterMask = (short)m;
|
|
|
|
// Refresh pair cache.
|
|
btworld->getBroadphase()->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(handle, btworld->getDispatcher());
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void BulletPhysicItem::SetLinearDamping(float k)
|
|
{
|
|
if (rigid_body)
|
|
rigid_body->setDamping(1.f - k, rigid_body->getAngularDamping());
|
|
}
|
|
float BulletPhysicItem::GetLinearDamping() const
|
|
{
|
|
return rigid_body ? 1.f - rigid_body->getLinearDamping() : 0;
|
|
}
|
|
void BulletPhysicItem::SetAngularDamping(float k)
|
|
{
|
|
if (rigid_body)
|
|
rigid_body->setDamping(rigid_body->getLinearDamping(), 1.f - k);
|
|
}
|
|
float BulletPhysicItem::GetAngularDamping() const
|
|
{
|
|
return rigid_body ? 1.f - rigid_body->getAngularDamping() : 0;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void BulletPhysicItem::SetLinearFactor(const Vector4 &k)
|
|
{
|
|
if (rigid_body)
|
|
rigid_body->setLinearFactor(btVector3(k.x, k.y, k.z));
|
|
}
|
|
void BulletPhysicItem::SetAngularFactor(const Vector4 &k)
|
|
{
|
|
if (rigid_body)
|
|
rigid_body->setAngularFactor(btVector3(k.x, k.y, k.z));
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void BulletPhysicItem::TransformFromMatrix4(const Matrix4 &m, btTransform &transform)
|
|
{
|
|
btScalar scalar[15];
|
|
scalar[0] = m.m[0][0]; scalar[1] = m.m[1][0]; scalar[2] = m.m[2][0]; scalar[3] = 1;
|
|
scalar[4] = m.m[0][1]; scalar[5] = m.m[1][1]; scalar[6] = m.m[2][1]; scalar[7] = 1;
|
|
scalar[8] = m.m[0][2]; scalar[9] = m.m[1][2]; scalar[10] = m.m[2][2]; scalar[11] = 1;
|
|
scalar[12] = m.m[0][3]; scalar[13] = m.m[1][3]; scalar[14] = m.m[2][3];
|
|
transform.setFromOpenGLMatrix(scalar);
|
|
}
|
|
void BulletPhysicItem::TransformToMatrix4(const btTransform &transform, Matrix4 &m)
|
|
{
|
|
btScalar scalar[16];
|
|
transform.getOpenGLMatrix(scalar);
|
|
m.m[0][0] = scalar[0]; m.m[1][0] = scalar[1]; m.m[2][0] = scalar[2]; m.m[3][0] = 0;
|
|
m.m[0][1] = scalar[4]; m.m[1][1] = scalar[5]; m.m[2][1] = scalar[6]; m.m[3][1] = 0;
|
|
m.m[0][2] = scalar[8]; m.m[1][2] = scalar[9]; m.m[2][2] = scalar[10]; m.m[3][2] = 0;
|
|
m.m[0][3] = scalar[12]; m.m[1][3] = scalar[13]; m.m[2][3] = scalar[14]; m.m[3][3] = scalar[15];
|
|
}
|
|
void BulletPhysicItem::GetGraphicMatrix(Matrix4 &m)
|
|
{
|
|
if (ghost_object)
|
|
{
|
|
btTransform wt = ghost_object->getWorldTransform();
|
|
wt.setOrigin(wt.getOrigin() - wt.getBasis() * btVector3(center.x, center.y, center.z));
|
|
TransformToMatrix4(wt, m);
|
|
}
|
|
else
|
|
if (motion_state)
|
|
m = motion_state->GetGraphicMatrix();
|
|
}
|
|
void BulletPhysicItem::SetEngineMatrix(const Matrix4 &m)
|
|
{
|
|
if (motion_state)
|
|
motion_state->SetEngineMatrix(m);
|
|
}
|
|
void BulletPhysicItem::GetMatrix(Matrix4 &m)
|
|
{
|
|
if (ghost_object)
|
|
TransformToMatrix4(ghost_object->getWorldTransform(), m);
|
|
else
|
|
if (rigid_body)
|
|
TransformToMatrix4(rigid_body->getWorldTransform(), m);
|
|
}
|
|
void BulletPhysicItem::SetMatrix(const Matrix4 &m)
|
|
{
|
|
Vector4 p;
|
|
Matrix3 m3;
|
|
m.Decompose(&p, 0, &m3);
|
|
Matrix4 m4(Matrix4::FromMatrix3(m3));
|
|
m4.SetRow(3, p);
|
|
|
|
btTransform wt;
|
|
TransformFromMatrix4(m4, wt);
|
|
wt.setOrigin(wt.getOrigin() + wt.getBasis() * btVector3(center.x, center.y, center.z));
|
|
|
|
if (ghost_object)
|
|
ghost_object->setWorldTransform(wt);
|
|
else
|
|
if (rigid_body)
|
|
rigid_body->setWorldTransform(wt);
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void BulletPhysicItem::SetSleeping(bool sleep)
|
|
{
|
|
if (!rigid_body)
|
|
return;
|
|
|
|
if (sleep)
|
|
rigid_body->setActivationState(WANTS_DEACTIVATION);
|
|
else rigid_body->activate();
|
|
}
|
|
bool BulletPhysicItem::IsSleeping() const
|
|
{ return rigid_body ? rigid_body->wantsSleeping() : false; }
|
|
void BulletPhysicItem::SetActive(bool active)
|
|
{
|
|
if (!rigid_body)
|
|
return;
|
|
|
|
if (active)
|
|
{
|
|
/*
|
|
Note the activation state MUST be changed from
|
|
DISABLE_SIMULATION or activate() will silently fail.
|
|
*/
|
|
rigid_body->getBroadphaseHandle()->m_collisionFilterGroup = self_mask;
|
|
rigid_body->getBroadphaseHandle()->m_collisionFilterMask = collision_mask;
|
|
rigid_body->forceActivationState(ACTIVE_TAG);
|
|
rigid_body->activate();
|
|
}
|
|
else
|
|
{
|
|
rigid_body->setActivationState(DISABLE_SIMULATION);
|
|
rigid_body->getBroadphaseHandle()->m_collisionFilterGroup = 0;
|
|
rigid_body->getBroadphaseHandle()->m_collisionFilterMask = 0;
|
|
}
|
|
}
|
|
bool BulletPhysicItem::GetActive() const
|
|
{ return rigid_body ? rigid_body->isActive() : false; }
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void BulletPhysicItem::VehicleSetForce(float F, uint i)
|
|
{
|
|
if (vehicle && (i < (uint)vehicle->getNumWheels()))
|
|
vehicle->applyEngineForce(F, i);
|
|
}
|
|
void BulletPhysicItem::VehicleSetBrake(float F, uint i)
|
|
{
|
|
if (vehicle && (i < (uint)vehicle->getNumWheels()))
|
|
vehicle->setBrake(F, i);
|
|
}
|
|
void BulletPhysicItem::VehicleSetSteering(float v, uint i)
|
|
{
|
|
if (vehicle && (i < (uint)vehicle->getNumWheels()))
|
|
vehicle->setSteeringValue(v, i);
|
|
}
|
|
void BulletPhysicItem::VehicleSetFriction(float f, uint i)
|
|
{
|
|
if (vehicle && (i < (uint)vehicle->getNumWheels()))
|
|
vehicle->getWheelInfo(i).m_frictionSlip = f;
|
|
}
|
|
Matrix4 BulletPhysicItem::VehicleGetWheelMatrix(uint i)
|
|
{
|
|
Matrix4 m(Matrix4::IdentityMatrix());
|
|
if (vehicle && (i < (uint)vehicle->getNumWheels()))
|
|
{
|
|
vehicle->updateWheelTransform(i, true);
|
|
TransformToMatrix4(vehicle->getWheelInfo(i).m_worldTransform, m);
|
|
}
|
|
return m;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void BulletPhysicItem::CharacterSetRotationMatrix(const Matrix3 &m)
|
|
{
|
|
if (ghost_object)
|
|
{
|
|
btMatrix3x3 basis
|
|
(
|
|
m.m[0][0], m.m[0][1], m.m[0][2],
|
|
m.m[1][0], m.m[1][1], m.m[1][2],
|
|
m.m[2][0], m.m[2][1], m.m[2][2]
|
|
);
|
|
ghost_object->getWorldTransform().setBasis(basis);
|
|
}
|
|
}
|
|
void BulletPhysicItem::CharacterSetVelocity(const Vector4 &v)
|
|
{
|
|
if (character_controller)
|
|
character_controller->setWalkDirection(nTobtVector(v));
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void BulletPhysicItem::SetScale(const Vector4 &_scale)
|
|
{
|
|
scale = _scale;
|
|
if (compound)
|
|
compound->setLocalScaling(nTobtVector(scale));
|
|
}
|
|
Vector4 BulletPhysicItem::GetScale() const
|
|
{ return scale; }
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void BulletPhysicItem::ResetBody()
|
|
{
|
|
if (rigid_body)
|
|
{
|
|
rigid_body->setLinearVelocity(btVector3(0, 0, 0));
|
|
rigid_body->setAngularVelocity(btVector3(0, 0, 0));
|
|
rigid_body->clearForces();
|
|
}
|
|
}
|
|
void BulletPhysicItem::ForceUpdateMassShapePhysic(const PhysicItemDesc &desc, PhysicWorld *world)
|
|
{
|
|
float total_mass = 0;
|
|
if (!desc.shape_list.GetCount())
|
|
return;
|
|
|
|
Array <btScalar> mass_array;
|
|
mass_array.Allocate(desc.shape_list.GetCount());
|
|
center.Set(0, 0, 0);
|
|
btScalar *pmass_array = mass_array.c_ptr();
|
|
|
|
ListForeachPtr(PhysicShape *, shape, desc.shape_list)
|
|
{
|
|
Vector4 shape_center = shape->position;
|
|
center += shape_center * shape->mass;
|
|
total_mass += shape->mass;
|
|
*pmass_array++ = shape->mass;
|
|
}
|
|
center /= total_mass;
|
|
btTransform principal;
|
|
btVector3 body_inertia(0, 0, 0);
|
|
compound->calculatePrincipalAxisTransform(mass_array, principal, body_inertia);
|
|
|
|
rigid_body->setMassProps(total_mass, body_inertia);
|
|
rigid_body->updateInertiaTensor();
|
|
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
float BulletPhysicItem::SetupCollisionShapes(const PhysicItemDesc &desc, Array <btScalar> &mass_array, PhysicWorld *world)
|
|
{
|
|
float total_mass = 0;
|
|
if (!desc.shape_list.GetCount())
|
|
return total_mass;
|
|
|
|
mass_array.Allocate(desc.shape_list.GetCount());
|
|
btScalar *pmass_array = mass_array.c_ptr();
|
|
|
|
// WTF man... can't Bullet handle COM offset by itself?
|
|
shapes.Allocate(desc.shape_list.GetCount());
|
|
|
|
center.Set(0, 0, 0);
|
|
|
|
uint n = 0;
|
|
ListForeachPtr(PhysicShape *, shape, desc.shape_list)
|
|
{
|
|
btCollisionShape *btshape = NULL;
|
|
Vector4 shape_center = shape->position;
|
|
|
|
switch (shape->GetType())
|
|
{
|
|
case PhysicShape::TypeNone:
|
|
break;
|
|
|
|
case PhysicShape::TypeHeightmap:
|
|
if (float *ph = shape->GetHeightmap())
|
|
{
|
|
float min, max;
|
|
min = max = ph[0];
|
|
for (int v = 0; v < shape->GetHeight(); ++v)
|
|
for (int u = 0; u < shape->GetWidth(); ++u)
|
|
{
|
|
if (ph[0] > max)
|
|
max = ph[0];
|
|
if (ph[0] < min)
|
|
min = ph[0];
|
|
ph++;
|
|
}
|
|
|
|
btshape = new btHeightfieldTerrainShape(shape->GetWidth(), shape->GetHeight(), (void *)shape->GetHeightmap(), 1.f, min, max, 1, PHY_FLOAT, false);
|
|
}
|
|
break;
|
|
|
|
case PhysicShape::TypeSphere:
|
|
btshape = new btSphereShape(shape->dimensions.x);
|
|
break;
|
|
|
|
case PhysicShape::TypeBox:
|
|
{
|
|
const Vector4 &d = shape->dimensions;
|
|
btshape = new btBoxShape(btVector3(d.x * 0.5f, d.y * 0.5f, d.z * 0.5f));
|
|
}
|
|
break;
|
|
|
|
case PhysicShape::TypeCapsule:
|
|
{
|
|
const Vector4 &d = shape->dimensions;
|
|
btshape = new btCapsuleShapeZ(d.x * 0.5f, d.z);
|
|
}
|
|
break;
|
|
|
|
case PhysicShape::TypeCylinder:
|
|
{
|
|
const Vector4 &d = shape->dimensions;
|
|
btshape = new btCylinderShapeZ(btVector3(d.x * 0.5f, d.y * 0.5f, d.z * 0.5f));
|
|
}
|
|
break;
|
|
|
|
case PhysicShape::TypeCone:
|
|
{
|
|
const Vector4 &d = shape->dimensions;
|
|
btshape = new btConeShapeZ(d.x * 0.5f, d.z * 0.5f);
|
|
}
|
|
break;
|
|
|
|
case PhysicShape::TypeConvex:
|
|
if (BulletConvex *convex = ((BulletWorld *)world)->LoadConvex(shape->path))
|
|
{
|
|
shapes[n].convex = convex;
|
|
|
|
shape_center = convex->center * shape->GetMatrix();
|
|
btshape = convex->convex;
|
|
}
|
|
break;
|
|
|
|
case PhysicShape::TypeMesh:
|
|
if (desc.physic_mode == PhysicItemDesc::Mode_Static)
|
|
{
|
|
/*
|
|
[EJ] 06/03/13 - Bullet SILENTLY rescales the cached mesh
|
|
vertices to comply with the item scale. In order to support
|
|
multiple scales on the same mesh the path is suffixed with
|
|
the item scale.
|
|
*/
|
|
String suffix = String::Format("%.02f_%.02f_%.02f", scale.x, scale.y, scale.z);
|
|
|
|
if (BulletMesh *mesh = ((BulletWorld *)world)->LoadMesh(shape->path, suffix))
|
|
{
|
|
shapes[n].mesh = mesh;
|
|
|
|
shape_center = mesh->center * shape->GetMatrix();
|
|
btshape = mesh->mesh;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
shapes[n].shape = btshape;
|
|
|
|
center += shape_center * shape->mass;
|
|
total_mass += shape->mass;
|
|
*pmass_array++ = shape->mass;
|
|
|
|
++n;
|
|
}
|
|
|
|
center /= total_mass;
|
|
if (desc.physic_mode == PhysicItemDesc::Mode_Vehicle)
|
|
center.Set(0, 0, 0);
|
|
|
|
n = 0;
|
|
ListForeachPtr(PhysicShape *, shape, desc.shape_list)
|
|
{
|
|
if (btCollisionShape *btshape = shapes[n].shape)
|
|
{
|
|
Vector4 shape_offset(0, 0, 0);
|
|
|
|
if (shape->GetType() == PhysicShape::TypeHeightmap)
|
|
{
|
|
float *ph = shape->GetHeightmap();
|
|
|
|
float min, max;
|
|
min = max = ph[0];
|
|
|
|
for (int v = 0; v < shape->GetHeight(); ++v)
|
|
for (int u = 0; u < shape->GetWidth(); ++u)
|
|
{
|
|
if (ph[0] > max) max = ph[0];
|
|
if (ph[0] < min) min = ph[0];
|
|
ph++;
|
|
}
|
|
|
|
btshape->setLocalScaling(btVector3(1, 1, 1));
|
|
|
|
// Damn... what a mess.
|
|
float hy = (max - min) * -0.5f;
|
|
shape_offset.Set(0, min - hy, 0);
|
|
}
|
|
|
|
Matrix4 m = Matrix4::TransformationMatrix(shape->position + shape_offset - center, shape->rotation, shape->scale);
|
|
btTransform transform;
|
|
TransformFromMatrix4(m, transform);
|
|
|
|
compound->addChildShape(transform, btshape);
|
|
}
|
|
++n;
|
|
}
|
|
return total_mass;
|
|
}
|
|
bool BulletPhysicItem::SetupCharacterController(const PhysicItemDesc &desc)
|
|
{
|
|
ghost_object = new btPairCachingGhostObject();
|
|
ghost_object->setUserPointer((PhysicItem *)this);
|
|
|
|
#if 0
|
|
convex_shape = new btCylinderShape(btVector3(desc.character.radius, desc.character.height * 0.5f, desc.character.radius));
|
|
center.Set(0, desc.character.height * 0.5f, 0);
|
|
#else
|
|
float height = Types::Max(desc.character.height - desc.character.radius * 2.f, 0.f);
|
|
convex_shape = new btCapsuleShape(desc.character.radius, height); // Height is the distance between the center of the two spheres whose convex hull is a capsule.
|
|
center.Set(0, (height + desc.character.radius * 2.f) * 0.5f, 0);
|
|
#endif
|
|
|
|
ghost_object->setCollisionShape(convex_shape);
|
|
ghost_object->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);
|
|
|
|
#if 1
|
|
character_controller = new btKinematicCharacterController(ghost_object, convex_shape, desc.character.max_step);
|
|
#else
|
|
btCustomCharacterController *cc = new btCustomCharacterController(ghost_object, convex_shape, desc.character.max_step, btworld->getCollisionWorld());
|
|
character_controller = cc;
|
|
#endif
|
|
return true;
|
|
}
|
|
bool BulletPhysicItem::SetupKinematicDynamicBody(const PhysicItemDesc &desc, PhysicWorld *world)
|
|
{
|
|
// Setup collision shapes.
|
|
Array <btScalar> mass_array;
|
|
|
|
compound = new btCompoundShape;
|
|
float total_mass = SetupCollisionShapes(desc, mass_array, world);
|
|
|
|
if (!compound->getNumChildShapes())
|
|
return true;
|
|
|
|
// Initialize physic mode.
|
|
compound->setLocalScaling(nTobtVector(scale));
|
|
btVector3 body_inertia(0, 0, 0);
|
|
|
|
switch (desc.physic_mode)
|
|
{
|
|
case PhysicItemDesc::Mode_None:
|
|
break;
|
|
|
|
case PhysicItemDesc::Mode_Dynamic:
|
|
case PhysicItemDesc::Mode_Vehicle:
|
|
if (compound->getNumChildShapes())
|
|
{
|
|
btTransform principal;
|
|
compound->calculatePrincipalAxisTransform(mass_array, principal, body_inertia);
|
|
}
|
|
else
|
|
{
|
|
total_mass = 1;
|
|
body_inertia.setValue(1, 1, 1);
|
|
}
|
|
break;
|
|
|
|
case PhysicItemDesc::Mode_Static:
|
|
case PhysicItemDesc::Mode_Kinematic:
|
|
total_mass = 0;
|
|
break;
|
|
}
|
|
|
|
// Allocate motion state.
|
|
motion_state = new BulletMotionState(this);
|
|
|
|
// Create rigid body.
|
|
rigid_body = new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(total_mass, motion_state, compound, body_inertia));
|
|
rigid_body->setUserPointer((PhysicItem *)this);
|
|
|
|
// Vehicle specialization.
|
|
if (desc.physic_mode == PhysicItemDesc::Mode_Vehicle)
|
|
{
|
|
rigid_body->setActivationState(DISABLE_DEACTIVATION);
|
|
|
|
vehicle_raycaster = new btDefaultVehicleRaycaster(btworld);
|
|
vehicle = new btRaycastVehicle(btRaycastVehicle::btVehicleTuning(), rigid_body, vehicle_raycaster);
|
|
vehicle->setCoordinateSystem(0, 1, 2);
|
|
|
|
// Add wheels.
|
|
ListForeachPtr(PhysicWheel *, wheel, desc.vehicle.wheel_list)
|
|
{
|
|
btRaycastVehicle::btVehicleTuning tuning;
|
|
|
|
tuning.m_suspensionStiffness = wheel->stiffness;
|
|
tuning.m_suspensionDamping = wheel->damping;
|
|
tuning.m_suspensionCompression = wheel->damping;
|
|
tuning.m_frictionSlip = wheel->friction;
|
|
tuning.m_maxSuspensionTravelCm = wheel->max_compression * 10.f; // m to cm.
|
|
|
|
Vector4 o = wheel->ref_matrix.GetRow(3),
|
|
u = wheel->ref_matrix.GetRow(1).Reversed(),
|
|
l = wheel->ref_matrix.GetRow(0).Reversed();
|
|
|
|
vehicle->addWheel(btVector3(o.x, o.y, o.z), btVector3(u.x, u.y, u.z), btVector3(l.x, l.y, l.z), wheel->rest_length, wheel->radius > 0.01f ? wheel->radius : 0.01f, tuning, false);
|
|
}
|
|
}
|
|
|
|
// Set defaults.
|
|
SetLinearFactor(desc.linear_factor);
|
|
SetAngularFactor(desc.angular_factor);
|
|
SetLinearDamping(desc.linear_damping);
|
|
SetAngularDamping(desc.angular_damping);
|
|
|
|
if (desc.shape_list.GetCount())
|
|
{
|
|
PhysicShape *shape = desc.shape_list.GetRoot()->Object();
|
|
rigid_body->setFriction(shape->static_friction);
|
|
rigid_body->setRestitution(shape->restitution);
|
|
}
|
|
|
|
if (desc.physic_mode == PhysicItemDesc::Mode_Kinematic)
|
|
{
|
|
rigid_body->setCollisionFlags(rigid_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
|
|
rigid_body->setActivationState(DISABLE_DEACTIVATION);
|
|
}
|
|
return true;
|
|
}
|
|
bool BulletPhysicItem::SetupBody(const PhysicItemDesc &desc, PhysicWorld *world)
|
|
{
|
|
// EJ 11/10
|
|
//
|
|
// - Bullet constraint holds strong/unmanaged reference to Bullet rigid bodies.
|
|
// - A Bullet rigid body is not meant to be radically modified once created.
|
|
|
|
// BulletWorld *world = (PhysicWorld *)world;
|
|
|
|
if (rigid_body || ghost_object)
|
|
return true;
|
|
|
|
DeleteBody();
|
|
|
|
switch (desc.physic_mode)
|
|
{
|
|
case PhysicItemDesc::Mode_None:
|
|
return true;
|
|
|
|
case PhysicItemDesc::Mode_Character:
|
|
if (!SetupCharacterController(desc))
|
|
return false;
|
|
|
|
btworld->addCollisionObject(ghost_object, btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter);
|
|
btworld->addAction(character_controller);
|
|
break;
|
|
|
|
default:
|
|
if (!SetupKinematicDynamicBody(desc, world))
|
|
return false;
|
|
|
|
if (rigid_body)
|
|
{
|
|
btworld->addRigidBody(rigid_body);
|
|
const Vector4 &g(world->GetGravity());
|
|
rigid_body->setGravity(btVector3(g.x, g.y, g.z));
|
|
}
|
|
if (vehicle)
|
|
btworld->addVehicle(vehicle);
|
|
break;
|
|
}
|
|
|
|
SetCollisionMask(desc.collision_mask);
|
|
SetSelfMask(desc.self_mask);
|
|
return true;
|
|
}
|
|
void BulletPhysicItem::DeleteBody()
|
|
{
|
|
// Destroy all shapes.
|
|
if (compound)
|
|
while (compound->getNumChildShapes())
|
|
compound->removeChildShapeByIndex(0);
|
|
|
|
// The collision shape for mesh/convex are cached and should not be deleted here!
|
|
for (uint n = 0; n < shapes.GetCount(); ++n)
|
|
if (shapes[n].convex.IsValid() || shapes[n].mesh.IsValid())
|
|
shapes[n].shape.Detach();
|
|
|
|
shapes.Free();
|
|
|
|
// Destroy rigid body.
|
|
if (rigid_body)
|
|
btworld->removeRigidBody(rigid_body);
|
|
rigid_body = NULL;
|
|
|
|
if (vehicle)
|
|
btworld->removeVehicle(vehicle);
|
|
vehicle = NULL;
|
|
vehicle_raycaster = NULL;
|
|
|
|
if (ghost_object)
|
|
btworld->removeCollisionObject(ghost_object);
|
|
ghost_object = NULL;
|
|
|
|
if (character_controller)
|
|
btworld->removeAction(character_controller);
|
|
character_controller = NULL;
|
|
|
|
compound = NULL;
|
|
motion_state = NULL;
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
void BulletPhysicItem::SetGravity(const Vector4 &g)
|
|
{
|
|
if (rigid_body)
|
|
rigid_body->setGravity(btVector3(g.x, g.y, g.z));
|
|
}
|
|
Vector4 BulletPhysicItem::GetGravity() const
|
|
{
|
|
if (!rigid_body)
|
|
return Vector4(0, 0, 0);
|
|
btVector3 g = rigid_body->getGravity();
|
|
return Vector4(g.x(), g.y(), g.z());
|
|
}
|
|
void BulletPhysicItem::ApplyImpulse(const Vector4 &I, const Vector4 *p)
|
|
{
|
|
if (!rigid_body)
|
|
return;
|
|
|
|
SetSleeping(false);
|
|
|
|
if (p && (I.Len() > 0.0001))
|
|
{
|
|
btVector3 l(p->x, p->y, p->z);
|
|
btVector3 J(I.x, I.y, I.z);
|
|
btScalar k = rigid_body->computeImpulseDenominator(l, J.normalized());
|
|
rigid_body->applyImpulse(J / k, l - rigid_body->getCenterOfMassPosition());
|
|
}
|
|
else
|
|
{
|
|
btVector3 J(I.x, I.y, I.z);
|
|
rigid_body->applyCentralImpulse(J / rigid_body->getInvMass());
|
|
}
|
|
}
|
|
void BulletPhysicItem::ApplyForce(const Vector4 &F, const Vector4 *p)
|
|
{
|
|
if (!rigid_body)
|
|
return;
|
|
|
|
SetSleeping(false);
|
|
if (p)
|
|
rigid_body->applyForce(btVector3(F.x, F.y, F.z), btVector3(p->x, p->y, p->z) - rigid_body->getCenterOfMassPosition());
|
|
else rigid_body->applyCentralForce(btVector3(F.x, F.y, F.z));
|
|
}
|
|
void BulletPhysicItem::ApplyTorque(const Vector4 &T)
|
|
{
|
|
if (rigid_body)
|
|
rigid_body->applyTorque(rigid_body->getCenterOfMassTransform().getBasis() * btVector3(T.x, T.y, T.z));
|
|
}
|
|
void BulletPhysicItem::SetAngularVelocity(const Vector4 &w)
|
|
{
|
|
if (rigid_body)
|
|
rigid_body->setAngularVelocity(btVector3(w.x, w.y, w.z));
|
|
}
|
|
Vector4 BulletPhysicItem::GetAngularVelocity() const
|
|
{
|
|
if (!rigid_body)
|
|
return Vector4(0, 0, 0);
|
|
const btVector3 &v = rigid_body->getAngularVelocity();
|
|
return Vector4(v.x(), v.y(), v.z());
|
|
}
|
|
void BulletPhysicItem::SetLinearVelocity(const Vector4 &v)
|
|
{
|
|
if (rigid_body)
|
|
rigid_body->setLinearVelocity(btVector3(v.x, v.y, v.z));
|
|
}
|
|
Vector4 BulletPhysicItem::GetLinearVelocity() const
|
|
{
|
|
if (!rigid_body)
|
|
return Vector4(0, 0, 0);
|
|
const btVector3 &v = rigid_body->getLinearVelocity();
|
|
return Vector4(v.x(), v.y(), v.z());
|
|
}
|
|
Vector4 BulletPhysicItem::GetLocalPointVelocity(const Vector4 &p) const
|
|
{
|
|
if (!rigid_body)
|
|
return Vector4(0, 0, 0);
|
|
btVector3 v = rigid_body->getVelocityInLocalPoint(rigid_body->getCenterOfMassTransform().getBasis() * btVector3(p.x, p.y, p.z));
|
|
return Vector4(v.x(), v.y(), v.z());
|
|
}
|
|
Vector4 BulletPhysicItem::GetWorldPointVelocity(const Vector4 &wp) const
|
|
{
|
|
if (!rigid_body)
|
|
return Vector4(0, 0, 0);
|
|
btVector3 v = rigid_body->getVelocityInLocalPoint(btVector3(wp.x, wp.y, wp.z) - rigid_body->getCenterOfMassPosition());
|
|
return Vector4(v.x(), v.y(), v.z());
|
|
}
|
|
Vector4 BulletPhysicItem::GetCenterOfMass() const
|
|
{
|
|
if (!rigid_body)
|
|
return Vector4(0, 0, 0);
|
|
btVector3 p = rigid_body->getCenterOfMassPosition();
|
|
return Vector4(p.x(), p.y(), p.z());
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
BulletPhysicItem::BulletPhysicItem(btDiscreteDynamicsWorld *w)
|
|
{
|
|
btworld = w;
|
|
|
|
center.Set(0, 0, 0);
|
|
scale.Set(1, 1, 1);
|
|
}
|
|
BulletPhysicItem::~BulletPhysicItem()
|
|
{
|
|
DeleteBody();
|
|
}
|
|
//----------------------------------------------------------------------------------
|