commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
486
include/modules/physic_bullet/bullet_character_controller.cpp
Normal file
486
include/modules/physic_bullet/bullet_character_controller.cpp
Normal file
@ -0,0 +1,486 @@
|
||||
|
||||
|
||||
#include "physic_bullet/bullet_character_controller.h"
|
||||
#include "LinearMath/btIDebugDraw.h"
|
||||
#include "nstring/nstring.h"
|
||||
|
||||
using namespace GS;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::debugDraw(btIDebugDraw *idebug)
|
||||
{
|
||||
String output;
|
||||
|
||||
output << "Vertical Velocity: " << mVerticalVelocity << "\n";
|
||||
output << "OnGround: " << (mGroundContact ? "Yes" : "No") << "\n";
|
||||
output << "Ground.y: " << mGroundNormal.y() << "\n";
|
||||
output << "Step high: " << dbg_step_high << "\n";
|
||||
output << "Down sweep: " << dbg_down_sweep_hit << "\n";
|
||||
|
||||
idebug->draw3dText(mCurrentPosition, output.c_str());
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
btVector3 btCustomCharacterController::computeReflectionDirection(const btVector3 & direction, const btVector3 & normal)
|
||||
{ return direction - (btScalar(2) * direction.dot(normal)) * normal; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
btCustomCharacterController::btCustomCharacterController(btPairCachingGhostObject * ghostObject, btConvexShape * convexShape, btScalar stepHeight, btCollisionWorld * collisionWorld, int upAxis)
|
||||
{
|
||||
mUpAxis = upAxis;
|
||||
mAddedMargin = 0.02;
|
||||
mWalkDirection.setValue(0, 0, 0);
|
||||
// mUseGhostObjectSweepTest = true;
|
||||
mGhostObject = ghostObject;
|
||||
mStepHeight = stepHeight;
|
||||
mTurnAngle = 0;
|
||||
mConvexShape = mStandingConvexShape = convexShape;
|
||||
mUseWalkDirection = true;
|
||||
mVelocityTimeInterval = 0;
|
||||
mVerticalOffset = 0;
|
||||
mVerticalVelocity = 0;
|
||||
mGravity = 9.8 * 3.0;
|
||||
mFallSpeed = 9.8;
|
||||
mJumpSpeed = 10;
|
||||
// mWasOnGround = false;
|
||||
// mWasJumping = false;
|
||||
setMaxSlope(btRadians(45));
|
||||
mCollisionWorld = collisionWorld;
|
||||
// mCanStand = true;
|
||||
mCurrentPosition.setValue(0, 0, 0);
|
||||
mMass = 20;
|
||||
mGroundContact = false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::setDuckingConvexShape(btConvexShape * shape)
|
||||
{ mDuckingConvexShape = shape; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::setRBForceImpulseBasedOnCollision()
|
||||
{
|
||||
if (mWalkDirection.isZero())
|
||||
return;
|
||||
|
||||
for (int i = 0; i < mGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); ++i)
|
||||
{
|
||||
btBroadphasePair *collisionPair = &mGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
|
||||
|
||||
btRigidBody *rb = (btRigidBody*)collisionPair->m_pProxy1->m_clientObject;
|
||||
|
||||
if (mMass > rb->getInvMass())
|
||||
{
|
||||
btScalar resultMass = mMass - rb->getInvMass();
|
||||
btVector3 reflection = computeReflectionDirection(mWalkDirection * resultMass, getNormalizedVector(mWalkDirection));
|
||||
rb->applyCentralImpulse(reflection * -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::setVelocityForTimeInterval(const btVector3 & velocity, btScalar timeInterval)
|
||||
{
|
||||
mUseWalkDirection = false;
|
||||
mWalkDirection = velocity;
|
||||
mNormalizedDirection = getNormalizedVector(mWalkDirection);
|
||||
mVelocityTimeInterval = timeInterval;
|
||||
}
|
||||
|
||||
void btCustomCharacterController::warp(const btVector3 & origin)
|
||||
{
|
||||
btTransform xform;
|
||||
xform.setIdentity();
|
||||
xform.setOrigin(origin);
|
||||
mGhostObject->setWorldTransform(xform);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool btCustomCharacterController::SweepTest(const btVector3 &src, const btVector3 &dst, btScalar &hitFraction, btVector3 *normal, btVector3 *hit)
|
||||
{
|
||||
btTransform start, end;
|
||||
start.setIdentity(); end.setIdentity();
|
||||
start.setOrigin(src); end.setOrigin(dst);
|
||||
|
||||
ClosestNotMeConvexResultCallback callback(mGhostObject, getUpAxisDirection(), 0);
|
||||
callback.m_collisionFilterGroup = mGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = mGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
mGhostObject->convexSweepTest(mConvexShape, start, end, callback, mCollisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
||||
|
||||
hitFraction = callback.hasHit() ? callback.m_closestHitFraction : btScalar(1);
|
||||
if (normal)
|
||||
*normal = callback.m_hitNormalWorld;
|
||||
if (hit)
|
||||
*hit = callback.m_hitPointWorld;
|
||||
|
||||
return callback.hasHit();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool btCustomCharacterController::recoverFromPenetration(const btVector3 &step_direction)
|
||||
{
|
||||
return false;
|
||||
mCollisionWorld->getDispatcher()->dispatchAllCollisionPairs(mGhostObject->getOverlappingPairCache(), mCollisionWorld->getDispatchInfo(), mCollisionWorld->getDispatcher());
|
||||
|
||||
bool penetration = false;
|
||||
for (int i = 0; i < mGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); ++i)
|
||||
{
|
||||
btBroadphasePair *collisionPair = &mGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
|
||||
|
||||
mManifoldArray.resize(0);
|
||||
if (collisionPair->m_algorithm)
|
||||
collisionPair->m_algorithm->getAllContactManifolds(mManifoldArray);
|
||||
|
||||
for (int j = 0; j < mManifoldArray.size(); ++j)
|
||||
{
|
||||
btPersistentManifold *manifold = mManifoldArray[j];
|
||||
btScalar directionSign = manifold->getBody0() == mGhostObject ? btScalar(1) : btScalar(-1);
|
||||
|
||||
for (int p = 0; p < manifold->getNumContacts(); ++p)
|
||||
{
|
||||
const btManifoldPoint &pt = manifold->getContactPoint(p);
|
||||
|
||||
btScalar dist = pt.getDistance();
|
||||
btVector3 normal = pt.m_normalWorldOnB * directionSign;
|
||||
|
||||
if (dist < 0.0)
|
||||
{
|
||||
penetration = true;
|
||||
|
||||
if (normal.y() > 0.9)
|
||||
normal = btVector3(0, 1, 0); // prevent sliding down slopes
|
||||
|
||||
mCurrentPosition -= normal * dist * btScalar(0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return penetration;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "log/log.h"
|
||||
|
||||
enum
|
||||
{
|
||||
UpSweep,
|
||||
ForwardSweep,
|
||||
DownSweep
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool btCustomCharacterController::SweepAndSlide(btVector3 &from, btVector3 &to, int sweep)
|
||||
{
|
||||
bool hit = false;
|
||||
for (int it = 0; it < 4; ++it)
|
||||
{
|
||||
btScalar hit_fraction;
|
||||
btVector3 hit_normal;
|
||||
if (!SweepTest(from, to, hit_fraction, &hit_normal))
|
||||
return hit;
|
||||
|
||||
switch (sweep)
|
||||
{
|
||||
case ForwardSweep:
|
||||
if (hit_normal.y() < 0.75)
|
||||
{
|
||||
hit_normal.setY(0.0);
|
||||
hit_normal.normalize();
|
||||
}
|
||||
else
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
|
||||
from += (to - from) * hit_fraction;
|
||||
to -= hit_normal * (to - from).dot(hit_normal);
|
||||
|
||||
if ((to - from).length2() < btScalar(0.0001))
|
||||
break;
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void btCustomCharacterController::performStep(btScalar dt)
|
||||
{
|
||||
btScalar hit_fraction;
|
||||
btVector3 hit_normal, hit_point;
|
||||
|
||||
mStepHeight = 0.25;
|
||||
|
||||
// up sweep
|
||||
btVector3 step_height = getUpAxisDirection() * mStepHeight;
|
||||
|
||||
btVector3 wpos = mGhostObject->getWorldTransform().getOrigin();
|
||||
btVector3 tpos = wpos + step_height;
|
||||
|
||||
SweepTest(wpos, tpos, hit_fraction, &hit_normal);
|
||||
tpos = wpos + (tpos - wpos) * hit_fraction;
|
||||
|
||||
// forward sweep
|
||||
bool forward_hit = false;
|
||||
|
||||
if (mWalkDirection.length2() > 0.0)
|
||||
{
|
||||
wpos = tpos;
|
||||
tpos += mWalkDirection;
|
||||
|
||||
forward_hit = SweepAndSlide(wpos, tpos, ForwardSweep);
|
||||
}
|
||||
|
||||
// down sweep
|
||||
btVector3 g = btVector3(0, -9, 0) * dt;
|
||||
|
||||
wpos = tpos;
|
||||
tpos -= step_height;
|
||||
tpos += g;
|
||||
|
||||
bool down_hit = SweepTest(wpos, tpos, hit_fraction, &hit_normal);
|
||||
tpos = wpos + (tpos - wpos) * hit_fraction;
|
||||
|
||||
// landing on a steep slope higher than we starter, revert height change.
|
||||
if (down_hit && (hit_normal.y() < 0.75))
|
||||
{
|
||||
tpos += hit_normal * 0.2;
|
||||
wpos = tpos;
|
||||
tpos = wpos - btVector3(0, 4, 0);
|
||||
|
||||
SweepTest(wpos, tpos, hit_fraction);
|
||||
tpos = wpos + (tpos - wpos) * hit_fraction;
|
||||
}
|
||||
|
||||
|
||||
|
||||
mCurrentPosition = tpos;
|
||||
return;
|
||||
// }
|
||||
/*
|
||||
// perform high sweep to step above small obstacle
|
||||
btVector3 step_height = getUpAxisDirection() * mStepHeight;
|
||||
|
||||
wpos = mGhostObject->getWorldTransform().getOrigin() + step_height;
|
||||
tpos = wpos + mWalkDirection;
|
||||
|
||||
if (!SweepAndSlide(wpos, tpos, HighSweep))
|
||||
return; // high sweep is not cutting it either... drop its result entirely
|
||||
|
||||
// step down from the high sweep
|
||||
wpos = tpos;
|
||||
tpos -= step_height;
|
||||
|
||||
if (!SweepAndSlide(wpos, tpos, DownSweep))
|
||||
{
|
||||
mVerticalVelocity = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// else
|
||||
{
|
||||
mVerticalVelocity = btClamped(mVerticalVelocity - mGravity * dt, -mFallSpeed, mJumpSpeed);
|
||||
|
||||
wpos = tpos;
|
||||
tpos += btVector3(0, mVerticalVelocity, 0) * dt;
|
||||
|
||||
SweepAndSlide(wpos, tpos, GravitySweep);
|
||||
}
|
||||
|
||||
// commit
|
||||
mCurrentPosition = tpos;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::preStep(btCollisionWorld *collisionWorld)
|
||||
{}
|
||||
void btCustomCharacterController::playerStep(btCollisionWorld * collisionWorld, btScalar dt)
|
||||
{
|
||||
if (!mUseWalkDirection && mVelocityTimeInterval <= 0)
|
||||
return;
|
||||
|
||||
performStep(dt);
|
||||
#if 0
|
||||
mCurrentPosition = mGhostObject->getWorldTransform().getOrigin();
|
||||
|
||||
// Apply gravity.
|
||||
mVerticalVelocity = btClamped(mVerticalVelocity - mGravity * dt, -mFallSpeed, mJumpSpeed);
|
||||
|
||||
// Compute total step velocity.
|
||||
mTouchingContact = false;
|
||||
for (int n = 0; (n < 4) && recoverFromPenetration(mWalkDirection + btVector3(0, -1, 0) * mVerticalVelocity); ++n)
|
||||
mTouchingContact = true;
|
||||
|
||||
// Perform sweep tests.
|
||||
btVector3 stepHeight = getUpAxisDirection() * mStepHeight;
|
||||
btVector3 stepHigh = mCurrentPosition + stepHeight;
|
||||
|
||||
btScalar hitFraction;
|
||||
|
||||
mGroundContact = false;
|
||||
if (SweepTest(stepHigh, stepHigh + mWalkDirection, hitFraction, &mGroundNormal))
|
||||
{
|
||||
btVector3 hit = stepHigh + mWalkDirection * hitFraction;
|
||||
if (mGroundNormal.y() > 0.6) // on ground, take step
|
||||
mCurrentPosition = hit;
|
||||
}
|
||||
else
|
||||
{
|
||||
stepHigh += mWalkDirection; // take the whole walk step
|
||||
|
||||
btVector3 g = stepHeight - mVerticalVelocity * getUpAxisDirection();
|
||||
|
||||
bool down_sweep_hit = SweepTest(stepHigh, stepHigh - g, hitFraction, &mGroundNormal);
|
||||
|
||||
if (!down_sweep_hit)
|
||||
{
|
||||
mCurrentPosition += mVerticalVelocity * getUpAxisDirection(); // free-falling
|
||||
}
|
||||
else
|
||||
{
|
||||
mGroundContact = mGroundNormal.y() > 0.6;
|
||||
|
||||
btVector3 dp = stepHigh - g * hitFraction;
|
||||
|
||||
if (dp.y() > mCurrentPosition.y()) // going up a slope
|
||||
{
|
||||
if (mGroundContact)
|
||||
mCurrentPosition = dp; // ok if on ground
|
||||
}
|
||||
else
|
||||
mCurrentPosition = dp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//
|
||||
if (mGroundContact)
|
||||
mVerticalVelocity = 0.0;
|
||||
|
||||
//
|
||||
btTransform xform = mGhostObject->getWorldTransform();
|
||||
xform.setOrigin(mCurrentPosition);
|
||||
mGhostObject->setWorldTransform(xform);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::setFallSpeed(btScalar fallSpeed)
|
||||
{ mFallSpeed = fallSpeed; }
|
||||
void btCustomCharacterController::setJumpSpeed(btScalar jumpSpeed)
|
||||
{ mJumpSpeed = jumpSpeed; }
|
||||
void btCustomCharacterController::setMaxJumpHeight(btScalar maxJumpHeight)
|
||||
{ mMaxJumpHeight = maxJumpHeight; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool btCustomCharacterController::canJump() const
|
||||
{ return onGround(); }
|
||||
void btCustomCharacterController::jump()
|
||||
{
|
||||
if (!canJump())
|
||||
return;
|
||||
|
||||
mVerticalVelocity = mJumpSpeed;
|
||||
// mWasJumping = true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::duck()
|
||||
{
|
||||
mConvexShape = mDuckingConvexShape;
|
||||
mGhostObject->setCollisionShape(mDuckingConvexShape);
|
||||
|
||||
btTransform xform;
|
||||
xform.setIdentity();
|
||||
xform.setOrigin(mCurrentPosition + btVector3(0, 0.1, 0));
|
||||
mGhostObject->setWorldTransform(xform);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::stand()
|
||||
{
|
||||
mConvexShape = mStandingConvexShape;
|
||||
mGhostObject->setCollisionShape(mStandingConvexShape);
|
||||
}
|
||||
bool btCustomCharacterController::canStand()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::setGravity(const btScalar gravity)
|
||||
{ mGravity = gravity; }
|
||||
btScalar btCustomCharacterController::getGravity() const
|
||||
{ return mGravity; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::setMaxSlope(btScalar slopeRadians)
|
||||
{
|
||||
mMaxSlopeRadians = slopeRadians;
|
||||
mMaxSlopeCosine = btCos(slopeRadians);
|
||||
}
|
||||
btScalar btCustomCharacterController::getMaxSlope() const
|
||||
{ return mMaxSlopeRadians; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool btCustomCharacterController::onGround() const
|
||||
{ return mGroundContact; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::setWalkDirection(const btVector3 & walkDirection)
|
||||
{
|
||||
mUseWalkDirection = true;
|
||||
mWalkDirection = walkDirection;
|
||||
mNormalizedDirection = getNormalizedVector(mWalkDirection);
|
||||
}
|
||||
void btCustomCharacterController::setWalkDirection(const btScalar x, const btScalar y, const btScalar z)
|
||||
{
|
||||
mUseWalkDirection = true;
|
||||
mWalkDirection.setValue(x, y, z);
|
||||
mNormalizedDirection = getNormalizedVector(mWalkDirection);
|
||||
}
|
||||
btVector3 btCustomCharacterController::getWalkDirection() const
|
||||
{ return mWalkDirection; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
btVector3 btCustomCharacterController::getPosition() const
|
||||
{ return mCurrentPosition; }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::setOrientation(const btQuaternion &orientation)
|
||||
{
|
||||
btTransform xform;
|
||||
xform = mGhostObject->getWorldTransform();
|
||||
xform.setRotation(orientation);
|
||||
mGhostObject->setWorldTransform(xform);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void btCustomCharacterController::updateAction(btCollisionWorld *collisionWorld, btScalar dt)
|
||||
{
|
||||
preStep(collisionWorld);
|
||||
playerStep(collisionWorld, dt);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
176
include/modules/physic_bullet/bullet_constraint.cpp
Normal file
176
include/modules/physic_bullet/bullet_constraint.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "physic_bullet/bullet_constraint.h"
|
||||
#include "physic_bullet/bullet_item.h"
|
||||
#include "scene3d/mitem.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::S3D;
|
||||
|
||||
void BulletConstraint::setLimitHinge(float low, float high, float _softness, float _biasFactor, float _relaxationFactor)
|
||||
{
|
||||
if (!constraint)
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case PhysicConstraintDesc::TypeHinge:
|
||||
((btHingeConstraint*)constraint)->setLimit(low, high, _softness, _biasFactor, _relaxationFactor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void BulletConstraint::SetPivotA(const Matrix4 &pivot)
|
||||
{
|
||||
if (!constraint)
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case PhysicConstraintDesc::TypePoint:
|
||||
{
|
||||
Vector4 p = pivot.GetRow(3);
|
||||
if (item_a.IsValid())
|
||||
p -= ((BulletPhysicItem *)item_a.c_ptr())->GetCenter();
|
||||
|
||||
btVector3 bt_pivot(p.x, p.y, p.z);
|
||||
((btPoint2PointConstraint *)constraint)->setPivotA(bt_pivot);
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
void BulletConstraint::SetPivotB(const Matrix4 &pivot)
|
||||
{
|
||||
if (constraint)
|
||||
switch (type)
|
||||
{
|
||||
case PhysicConstraintDesc::TypePoint:
|
||||
{
|
||||
Vector4 p = pivot.GetRow(3);
|
||||
if (item_b.IsValid())
|
||||
p -= ((BulletPhysicItem *)item_b.c_ptr())->GetCenter();
|
||||
|
||||
btVector3 bt_pivot(p.x, p.y, p.z);
|
||||
((btPoint2PointConstraint *)constraint)->setPivotB(bt_pivot);
|
||||
}
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void BulletConstraint::Enable(bool b)
|
||||
{
|
||||
if (constraint)
|
||||
constraint->setEnabled(b);
|
||||
}
|
||||
bool BulletConstraint::SetupConstraint(const PhysicConstraintDesc &desc)
|
||||
{
|
||||
DeleteConstraint();
|
||||
|
||||
// Get constraint items.
|
||||
item_a = desc.item_a.IsValid() ? desc.item_a->physic_item.c_ptr() : NULL;
|
||||
item_b = desc.item_b.IsValid() ? desc.item_b->physic_item.c_ptr() : NULL;
|
||||
|
||||
BulletPhysicItem *bullet_item_a = (BulletPhysicItem *)item_a.c_ptr(),
|
||||
*bullet_item_b = (BulletPhysicItem *)item_b.c_ptr();
|
||||
|
||||
btRigidBody *rigid_body_a = bullet_item_a ? bullet_item_a->rigid_body.c_ptr() : NULL,
|
||||
*rigid_body_b = bullet_item_b ? bullet_item_b->rigid_body.c_ptr() : NULL;
|
||||
|
||||
if (!rigid_body_a && !rigid_body_b)
|
||||
return false;
|
||||
|
||||
// Create constraint.
|
||||
type = desc.type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case PhysicConstraintDesc::TypePoint:
|
||||
{
|
||||
Vector4 np_a = desc.pivot_a.GetRow(3), np_b = desc.pivot_b.GetRow(3);
|
||||
|
||||
if (bullet_item_a)
|
||||
np_a -= bullet_item_a->GetCenter();
|
||||
if (bullet_item_b)
|
||||
np_b -= bullet_item_b->GetCenter();
|
||||
|
||||
btVector3 btp_a(np_a.x, np_a.y, np_a.z), btp_b(np_b.x, np_b.y, np_b.z);
|
||||
|
||||
if (rigid_body_a && rigid_body_b)
|
||||
constraint = new btPoint2PointConstraint(*rigid_body_a, *rigid_body_b, btp_a, btp_b);
|
||||
if (rigid_body_a && !rigid_body_b)
|
||||
constraint = new btPoint2PointConstraint(*rigid_body_a, btp_a);
|
||||
|
||||
// constraint->setParam(BT_CONSTRAINT_ERP, 0.8);
|
||||
// constraint->setParam(BT_CONSTRAINT_CFM, 0);
|
||||
}
|
||||
break;
|
||||
case PhysicConstraintDesc::TypeHinge:
|
||||
{
|
||||
Vector4 np_a = desc.pivot_a.GetRow(3), np_b = desc.pivot_b.GetRow(3);
|
||||
|
||||
if (bullet_item_a)
|
||||
np_a -= bullet_item_a->GetCenter();
|
||||
if (bullet_item_b)
|
||||
np_b -= bullet_item_b->GetCenter();
|
||||
|
||||
btVector3 btp_a(np_a.x, np_a.y, np_a.z), btp_b(np_b.x, np_b.y, np_b.z);
|
||||
|
||||
if (rigid_body_a && rigid_body_b)
|
||||
constraint = new btHingeConstraint(*rigid_body_a, *rigid_body_b, btp_a, btp_b, btVector3(0,0,1), btVector3(0,0,1));
|
||||
if (rigid_body_a && !rigid_body_b)
|
||||
constraint = new btHingeConstraint(*rigid_body_a, btp_a, btVector3(0,1,0));
|
||||
// ((btHingeConstraint*)constraint)->setLimit(0, 0);
|
||||
// constraint->setParam(BT_CONSTRAINT_STOP_CFM, 0);
|
||||
// constraint->setParam(BT_CONSTRAINT_CFM, 0);
|
||||
// constraint->setParam(BT_CONSTRAINT_STOP_ERP, 0.8);
|
||||
// constraint->setParam(BT_CONSTRAINT_ERP, 0.8);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (constraint)
|
||||
world->addConstraint(constraint);
|
||||
|
||||
return true;
|
||||
}
|
||||
void BulletConstraint::DeleteConstraint()
|
||||
{
|
||||
if (constraint)
|
||||
{
|
||||
world->removeConstraint(constraint);
|
||||
_safe_delete(constraint);
|
||||
}
|
||||
|
||||
item_a = NULL;
|
||||
item_b = NULL;
|
||||
|
||||
type = PhysicConstraintDesc::TypeNone;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
BulletConstraint::BulletConstraint(btDiscreteDynamicsWorld *_world)
|
||||
{
|
||||
type = PhysicConstraintDesc::TypeNone;
|
||||
|
||||
world = _world;
|
||||
constraint = NULL;
|
||||
}
|
||||
BulletConstraint::~BulletConstraint()
|
||||
{
|
||||
DeleteConstraint();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
83
include/modules/physic_bullet/bullet_debug.cpp
Normal file
83
include/modules/physic_bullet/bullet_debug.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "physic_bullet/bullet_debug.h"
|
||||
#include "core/renderer.h"
|
||||
#include "core/renderer_toolbox.h"
|
||||
#include "core/camera.h"
|
||||
#include "gpu/gpu_renderer.h"
|
||||
|
||||
using namespace GS::S3D;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void BulletDebugDraw::Flush()
|
||||
{
|
||||
renderer.DrawLine(line_count, vtx_cache, col_cache, xray_first_pass ? GS::Core::Material::Blend_Alpha : GS::Core::Material::Blend_None, GS::Core::Material::Render_NoZWrite);
|
||||
line_count = 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
float BulletDebugDraw::GetXRayAlpha() const
|
||||
{ return xray_first_pass ? 0.2f : 1.f; }
|
||||
void BulletDebugDraw::SetXRayFirstPass(bool pass)
|
||||
{
|
||||
// FIXME: WTF!?
|
||||
((GS::GPU::Renderer &)renderer).SetDepthFunc(pass ? GS::GPU::Renderer::DepthGreater : GS::GPU::Renderer::DepthLessEqual);
|
||||
xray_first_pass = pass;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void BulletDebugDraw::drawLine(const btVector3 &from, const btVector3 &to, const btVector3 &color)
|
||||
{
|
||||
if (line_count == 2048)
|
||||
Flush();
|
||||
|
||||
vtx_cache[(line_count << 1) + 0].Set(from.x(), from.y(), from.z());
|
||||
vtx_cache[(line_count << 1) + 1].Set(to.x(), to.y(), to.z());
|
||||
col_cache[(line_count << 1) + 0].Set(color.x(), color.y(), color.z(), GetXRayAlpha());
|
||||
col_cache[(line_count << 1) + 1].Set(color.x(), color.y(), color.z(), GetXRayAlpha());
|
||||
|
||||
++line_count;
|
||||
}
|
||||
void BulletDebugDraw::drawContactPoint(const btVector3 &PointOnB, const btVector3 &/*normalOnB*/, btScalar /*distance*/, int /*lifeTime*/, const btVector3 &color)
|
||||
{
|
||||
drawLine(PointOnB - btVector3(0.25, 0, 0), PointOnB + btVector3(0.25, 0, 0), color);
|
||||
drawLine(PointOnB - btVector3(0, 0.25, 0), PointOnB + btVector3(0, 0.25, 0), color);
|
||||
drawLine(PointOnB - btVector3(0, 0, 0.25), PointOnB + btVector3(0, 0, 0.25), color);
|
||||
}
|
||||
void BulletDebugDraw::reportErrorWarning(const char *)
|
||||
{}
|
||||
void BulletDebugDraw::draw3dText(const btVector3 &p, const char *text)
|
||||
{
|
||||
if (camera && raster_font)
|
||||
{
|
||||
Matrix4 m = camera->GetMatrix();
|
||||
m.SetRow(3, Vector4(p.x(), p.y(), p.z()));
|
||||
renderer.SetWorldMatrix(m);
|
||||
|
||||
float x = 0, y = 0;
|
||||
Renderer::WriterConfig config(true, false);
|
||||
renderer.Write(*raster_font, text, x, y, config, 2.f);
|
||||
|
||||
renderer.SetWorldMatrix(Matrix4::IdentityMatrix(), &Matrix4::IdentityMatrix());
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
BulletDebugDraw::BulletDebugDraw(Renderer &r) : renderer(r)
|
||||
{
|
||||
vtx_cache.Allocate(2048 * 2);
|
||||
col_cache.Allocate(2048 * 2);
|
||||
line_count = 0;
|
||||
|
||||
camera = NULL;
|
||||
raster_font = NULL;
|
||||
|
||||
xray_first_pass = true;
|
||||
}
|
||||
821
include/modules/physic_bullet/bullet_item.cpp
Normal file
821
include/modules/physic_bullet/bullet_item.cpp
Normal file
@ -0,0 +1,821 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
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();
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
345
include/modules/physic_bullet/bullet_world.cpp
Normal file
345
include/modules/physic_bullet/bullet_world.cpp
Normal file
@ -0,0 +1,345 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "physic_bullet/bullet_world.h"
|
||||
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
|
||||
#include "physic_bullet/bullet_item.h"
|
||||
#include "physic_bullet/bullet_constraint.h"
|
||||
#include "physic_bullet/bullet_debug.h"
|
||||
#include "core/geometry.h"
|
||||
#include "metafile/nml_object.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::S3D;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
PhysicItem *BulletWorld::NewItem()
|
||||
{ return new BulletPhysicItem(world); }
|
||||
PhysicConstraint *BulletWorld::NewConstraint()
|
||||
{ return new BulletConstraint(world); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
BulletConvex *BulletWorld::LoadConvex(const char *_name)
|
||||
{
|
||||
String name(_name);
|
||||
|
||||
// Check cache.
|
||||
ListForeachPtr(BulletConvex *, convex, convex_cache)
|
||||
if (convex->name == name)
|
||||
return convex;
|
||||
|
||||
// Load geometry.
|
||||
AutoPtr <Core::Geometry> g(new Core::Geometry);
|
||||
if (!NML::LoadFromFile(*g, name))
|
||||
return NULL;
|
||||
|
||||
// Setup convex.
|
||||
BulletConvex *bullet_convex = new BulletConvex;
|
||||
if (!bullet_convex)
|
||||
__ERR__(__LOG_E__ << "Failed to allocate bullet convex.\n", NULL)
|
||||
|
||||
Array <btScalar> bt_vtx(g->vtx.GetCount() * 3);
|
||||
btScalar *p_bt_vtx = bt_vtx.c_ptr();
|
||||
|
||||
Vector4 gcenter(0, 0, 0);
|
||||
for (uint n = 0; n < g->vtx.GetCount(); ++n)
|
||||
{
|
||||
gcenter += g->vtx[n];
|
||||
*p_bt_vtx++ = g->vtx[n].x;
|
||||
*p_bt_vtx++ = g->vtx[n].y;
|
||||
*p_bt_vtx++ = g->vtx[n].z;
|
||||
}
|
||||
|
||||
bullet_convex->name = name;
|
||||
bullet_convex->center = (gcenter / (float)g->vtx.GetCount());
|
||||
bullet_convex->convex = new btConvexHullShape(bt_vtx.c_ptr(), g->vtx.GetCount(), 3 * sizeof(btScalar));
|
||||
convex_cache.Add(bullet_convex);
|
||||
|
||||
return bullet_convex;
|
||||
}
|
||||
BulletMesh *BulletWorld::LoadMesh(const char *_name, const char *_suffix)
|
||||
{
|
||||
String name(_name), suffix(_suffix);
|
||||
|
||||
// Check cache.
|
||||
ListForeachPtr(BulletMesh *, mesh, mesh_cache)
|
||||
if ((mesh->name == name) && (mesh->suffix == suffix))
|
||||
{
|
||||
__LOG_V__ << "Reusing cached Bullet btMesh for " << _name << " (suffix: " << _suffix << ").\n";
|
||||
return mesh;
|
||||
}
|
||||
|
||||
// Load bullet mesh.
|
||||
AutoPtr <Core::Geometry> g(new Core::Geometry);
|
||||
if (g.IsNull())
|
||||
return NULL;
|
||||
|
||||
g->name = name;
|
||||
if (!NML::LoadFromFile(*g, name))
|
||||
return NULL;
|
||||
|
||||
if (!g->vtx.GetCount() || !g->pol.GetCount())
|
||||
__ERR__(__LOG_E__ << "No geometry data in '" << g->name << "' to build collision shape.\n", NULL)
|
||||
|
||||
BulletMesh *bullet_mesh = new BulletMesh;
|
||||
if (!bullet_mesh)
|
||||
__ERR__(__LOG_E__ << "Failed to allocate bullet mesh.\n", NULL)
|
||||
|
||||
int triangle_count = g->GetTriangleCount();
|
||||
|
||||
bullet_mesh->bt_vtx.Allocate(g->vtx.GetCount() * 3);
|
||||
btScalar *p_bt_vtx = bullet_mesh->bt_vtx;
|
||||
bullet_mesh->bt_idx.Allocate(triangle_count * 3);
|
||||
int *p_bt_idx = bullet_mesh->bt_idx;
|
||||
|
||||
Vector4 gcenter(0, 0, 0);
|
||||
for (uint n = 0; n < g->vtx.GetCount(); ++n)
|
||||
{
|
||||
gcenter += g->vtx[n];
|
||||
*p_bt_vtx++ = g->vtx[n].x;
|
||||
*p_bt_vtx++ = g->vtx[n].y;
|
||||
*p_bt_vtx++ = g->vtx[n].z;
|
||||
}
|
||||
bullet_mesh->center = gcenter / (float)g->vtx.GetCount();
|
||||
|
||||
// Triangulate geometry on the fly, transfer material indices.
|
||||
bullet_mesh->bt_mat.Allocate(g->material_table.GetCount());
|
||||
for (uint n = 0; n < g->material_table.GetCount(); ++n)
|
||||
bullet_mesh->bt_mat[n] = g->material_table[n].name;
|
||||
|
||||
bullet_mesh->bt_id_mat.Allocate(triangle_count);
|
||||
ushort *p_bt_id_mat = bullet_mesh->bt_id_mat;
|
||||
|
||||
for (uint n = 0; n < g->pol.GetCount(); ++n)
|
||||
for (int p = 1; p < (g->pol[n].vtx_count - 1); ++p)
|
||||
{
|
||||
*p_bt_idx++ = g->pol[n].binding[0];
|
||||
*p_bt_idx++ = g->pol[n].binding[p];
|
||||
*p_bt_idx++ = g->pol[n].binding[p + 1];
|
||||
*p_bt_id_mat++ = g->pol[n].material;
|
||||
}
|
||||
|
||||
bullet_mesh->name = name;
|
||||
bullet_mesh->suffix = suffix;
|
||||
bullet_mesh->mesh_interface = new btTriangleIndexVertexArray(triangle_count, bullet_mesh->bt_idx, 3 * sizeof(int), g->vtx.GetCount(), bullet_mesh->bt_vtx, 3 * sizeof(btScalar));
|
||||
bullet_mesh->mesh = new btBvhTriangleMeshShape(bullet_mesh->mesh_interface, true);
|
||||
|
||||
mesh_cache.Add(bullet_mesh);
|
||||
|
||||
return bullet_mesh;
|
||||
}
|
||||
void BulletWorld::ClearConvexMeshCache()
|
||||
{
|
||||
convex_cache.Clear();
|
||||
mesh_cache.Clear();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool BulletWorld::HasDebugger() const
|
||||
{ return debug_draw.IsValid(); }
|
||||
void BulletWorld::CreateDebugger(Renderer *renderer)
|
||||
{
|
||||
debug_draw = renderer ? new BulletDebugDraw(*renderer) : NULL;
|
||||
if (world)
|
||||
world->setDebugDrawer(debug_draw);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static void bullet_pretick_callback(btDynamicsWorld *world, btScalar timeStep)
|
||||
{
|
||||
BulletWorld *physic_world = (BulletWorld *)world->getWorldUserInfo();
|
||||
if (physic_world->GetWorldInterface())
|
||||
physic_world->GetWorldInterface()->PhysicStep(timeStep, true);
|
||||
}
|
||||
static void bullet_posttick_callback(btDynamicsWorld *world, btScalar timeStep)
|
||||
{
|
||||
BulletWorld *physic_world = (BulletWorld *)world->getWorldUserInfo();
|
||||
if (physic_world->GetWorldInterface())
|
||||
physic_world->GetWorldInterface()->PhysicStep(timeStep, false);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void BulletWorld::DrawDebug(Renderer &, Camera *c, RasterFont *f, bool xray_first_pass)
|
||||
{
|
||||
if (BulletDebugDraw *dd = (BulletDebugDraw *)world->getDebugDrawer())
|
||||
{
|
||||
dd->camera = c;
|
||||
dd->raster_font = f;
|
||||
dd->SetDebugMode(btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawConstraints | btIDebugDraw::DBG_DrawConstraintLimits | btIDebugDraw::DBG_DrawContactPoints);
|
||||
// dd->SetDebugMode(btIDebugDraw::DBG_DrawAabb | btIDebugDraw::DBG_FastWireframe);
|
||||
dd->SetXRayFirstPass(xray_first_pass);
|
||||
|
||||
world->debugDrawWorld();
|
||||
dd->Flush();
|
||||
}
|
||||
}
|
||||
uint BulletWorld::GetCollisionPairCount()
|
||||
{ return world->getDispatcher()->getNumManifolds(); }
|
||||
bool BulletWorld::GetCollisionPair(uint n, CollisionPair &pair)
|
||||
{
|
||||
btPersistentManifold *manifold = world->getDispatcher()->getInternalManifoldPointer()[n];
|
||||
if (!manifold || !manifold->getNumContacts()) // Manifolds are valid as long as the bodies overlap in the broadphase.
|
||||
return false;
|
||||
|
||||
pair.a = (PhysicItem *)((btRigidBody *)manifold->getBody0())->getUserPointer();
|
||||
pair.b = (PhysicItem *)((btRigidBody *)manifold->getBody1())->getUserPointer();
|
||||
|
||||
pair.contact_count = 0;
|
||||
for (int i = 0; (i < manifold->getNumContacts()) && (i < 4); ++i)
|
||||
{
|
||||
btVector3 p = manifold->getContactPoint(i).getPositionWorldOnB();
|
||||
pair.contact[i].Set(p.x(), p.y(), p.z());
|
||||
btVector3 n = manifold->getContactPoint(i).m_normalWorldOnB;
|
||||
pair.normal[i].Set(n.x(), n.y(), n.z());
|
||||
|
||||
pair.contact_count++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool BulletWorld::Create()
|
||||
{
|
||||
collision_config = new btDefaultCollisionConfiguration();
|
||||
|
||||
#if __ENABLE_BULLET_MULTITHREAD__
|
||||
thread_support_collision = new Win32ThreadSupport(Win32ThreadSupport::Win32ThreadConstructionInfo("Bullet Collision", processCollisionTask, createCollisionLocalStoreMemory, __BULLET_THREAD_COUNT__));
|
||||
dispatcher = new SpuGatheringCollisionDispatcher(thread_support_collision, __BULLET_THREAD_COUNT__, collision_config);
|
||||
#else
|
||||
dispatcher = new btCollisionDispatcher(collision_config);
|
||||
#endif
|
||||
|
||||
broadphase = new btDbvtBroadphase();
|
||||
broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(pair_callback = new btGhostPairCallback);
|
||||
|
||||
solver = new btSequentialImpulseConstraintSolver;
|
||||
world = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collision_config);
|
||||
world->setInternalTickCallback(bullet_pretick_callback, (void *)this, true);
|
||||
world->setInternalTickCallback(bullet_posttick_callback, (void *)this, false);
|
||||
|
||||
// world->getSolverInfo().m_numIterations = 10;
|
||||
// world->getDispatchInfo().m_enableSPU = true;
|
||||
world->getSolverInfo().m_solverMode = SOLVER_SIMD + SOLVER_USE_WARMSTARTING;// + SOLVER_RANDMIZE_ORDER;
|
||||
// world->getSolverInfo().m_splitImpulse = 1;
|
||||
// world->getSolverInfo().m_splitImpulsePenetrationThreshold = 0.2;
|
||||
|
||||
world->setDebugDrawer(debug_draw);
|
||||
return true;
|
||||
}
|
||||
void BulletWorld::Delete()
|
||||
{
|
||||
ClearConvexMeshCache();
|
||||
|
||||
collision_config = NULL;
|
||||
dispatcher = NULL;
|
||||
broadphase = NULL;
|
||||
solver = NULL;
|
||||
world = NULL;
|
||||
#if __ENABLE_BULLET_MULTITHREAD__
|
||||
thread_support_collision = NULL;
|
||||
#endif
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void BulletWorld::Step(const GS::Time &dt)
|
||||
{
|
||||
ScopedBenchmark bench(bench_step);
|
||||
|
||||
#if 1
|
||||
substep_dt -= dt.toSec();
|
||||
|
||||
int limit = 4;
|
||||
while (substep_dt < 0)
|
||||
{
|
||||
world->stepSimulation(GetTimestep(), 0, GetTimestep());
|
||||
substep_dt += GetTimestep();
|
||||
|
||||
if (--limit <= 0)
|
||||
{
|
||||
substep_dt = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
world->stepSimulation(dt, 12, GetTimestep());
|
||||
#endif
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool BulletWorld::Raytrace(const Vector4 &s, const Vector4 &d, PhysicTrace &hit, int collision_mask, int shape_mask, float max_distance)
|
||||
{
|
||||
struct ClosestRayResultWithTriangleIndexCallback : public btCollisionWorld::ClosestRayResultCallback
|
||||
{
|
||||
ClosestRayResultWithTriangleIndexCallback(const btVector3 &rayFromWorld, const btVector3 &rayToWorld) : ClosestRayResultCallback(rayFromWorld, rayToWorld) {}
|
||||
|
||||
int m_TriangleIndex;
|
||||
int m_shapePart;
|
||||
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult &rayResult, bool normalInWorldSpace)
|
||||
{
|
||||
if (rayResult.m_localShapeInfo)
|
||||
{
|
||||
m_TriangleIndex = rayResult.m_localShapeInfo->m_triangleIndex;
|
||||
m_shapePart = rayResult.m_localShapeInfo->m_shapePart;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_TriangleIndex = -1;
|
||||
m_shapePart = -1;
|
||||
}
|
||||
return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
|
||||
}
|
||||
};
|
||||
|
||||
Vector4 e = s + d * (max_distance > 0 ? max_distance : 5000.f);
|
||||
btVector3 from(s.x, s.y, s.z), to(e.x, e.y, e.z);
|
||||
|
||||
ClosestRayResultWithTriangleIndexCallback trace(from, to);
|
||||
trace.m_collisionFilterGroup = btBroadphaseProxy::AllFilter;
|
||||
trace.m_collisionFilterMask = (short)collision_mask;
|
||||
world->rayTest(from, to, trace);
|
||||
if (!trace.hasHit())
|
||||
return false;
|
||||
|
||||
hit.p.Set(trace.m_hitPointWorld.x(), trace.m_hitPointWorld.y(), trace.m_hitPointWorld.z());
|
||||
hit.n.Set(trace.m_hitNormalWorld.x(), trace.m_hitNormalWorld.y(), trace.m_hitNormalWorld.z());
|
||||
hit.i = (PhysicItem *)trace.m_collisionObject->getUserPointer();
|
||||
|
||||
if (BulletPhysicItem *bi = (BulletPhysicItem *)hit.i)
|
||||
if ((trace.m_shapePart >= 0) && ((uint)trace.m_shapePart < bi->shapes.GetCount()))
|
||||
if (BulletMesh *mesh = bi->shapes[trace.m_shapePart].mesh.c_ptr())
|
||||
if (uint(trace.m_TriangleIndex) < mesh->bt_id_mat.GetCount())
|
||||
hit.m = mesh->bt_mat[mesh->bt_id_mat[trace.m_TriangleIndex]];
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static void *bulletAlloc(size_t s) { return MemAllocPhysics::Alloc(s, Alloc::Physics); }
|
||||
static void bulletFree(void *p) { MemAllocPhysics::Delete(p, Alloc::Physics); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
BulletWorld::BulletWorld()
|
||||
{
|
||||
btAlignedAllocSetCustom(bulletAlloc, bulletFree);
|
||||
substep_dt = 0;
|
||||
}
|
||||
BulletWorld::~BulletWorld()
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user