commit x64 compilation from lulu cause the other branch dont seems to compile properly at home

This commit is contained in:
2026-07-17 16:08:20 +02:00
parent c0f3eeb00d
commit 0efa4ee6f7
625 changed files with 117283 additions and 4426 deletions

View 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);
}
//------------------------------------------------------------------------------

View 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();
}
//------------------------------------------------------------------------------

View 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;
}

View 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();
}
//----------------------------------------------------------------------------------

View 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();
}
//------------------------------------------------------------------------------