diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-06-09 00:08:19 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2009-06-09 00:08:19 +0400 |
commit | c8b4cf92067ffeb625aa39003baf5d8f7c3f0025 (patch) | |
tree | c6c50dbc3d90a65fca6c1ca56a93e4a57cf7e154 /source/gameengine/Physics/Bullet | |
parent | e93db433a086a3e739c0f4026cd500f0b595b0f1 (diff) | |
parent | d76a6f5231c015c35123d22e1f5c3ffcdfbf9bbd (diff) |
2.50:
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r19820:HEAD
Notes:
* Game and sequencer RNA, and sequencer header are now out of date
a bit after changes in trunk.
* I didn't know how to port these bugfixes, most likely they are
not needed anymore.
* Fix "duplicate strip" always increase the user count for ipo.
* IPO pinning on sequencer strips was lost during Undo.
Diffstat (limited to 'source/gameengine/Physics/Bullet')
9 files changed, 564 insertions, 390 deletions
diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt index ec2cdede683..02f2aa635af 100644 --- a/source/gameengine/Physics/Bullet/CMakeLists.txt +++ b/source/gameengine/Physics/Bullet/CMakeLists.txt @@ -32,6 +32,7 @@ SET(INC ../../../../extern/bullet2/src ../../../../extern/glew/include ../../../../intern/moto/include + ../../../../intern/guardedalloc ../../../kernel/gen_system ../../../../intern/string ../../../../intern/SoundSystem @@ -41,6 +42,8 @@ SET(INC ../../GameLogic ../../SceneGraph ../../../../source/blender/makesdna + ../../../../source/blender/blenlib + ../../../../source/blender/blenkernel ${PYTHON_INC} ) diff --git a/source/gameengine/Physics/Bullet/CcdGraphicController.cpp b/source/gameengine/Physics/Bullet/CcdGraphicController.cpp index caf18fd28ba..2dbbb7fa4a0 100644 --- a/source/gameengine/Physics/Bullet/CcdGraphicController.cpp +++ b/source/gameengine/Physics/Bullet/CcdGraphicController.cpp @@ -47,11 +47,24 @@ void CcdGraphicController::setLocalAabb(const btVector3& aabbMin,const btVector3 void CcdGraphicController::setLocalAabb(const MT_Point3& aabbMin,const MT_Point3& aabbMax) { - m_localAabbMin = btVector3(aabbMin[0],aabbMin[1],aabbMin[2]); - m_localAabbMax = btVector3(aabbMax[0],aabbMax[1],aabbMax[2]); + m_localAabbMin.setValue(aabbMin[0],aabbMin[1],aabbMin[2]); + m_localAabbMax.setValue(aabbMax[0],aabbMax[1],aabbMax[2]); SetGraphicTransform(); } +void CcdGraphicController::setLocalAabb(const PHY__Vector3& aabbMin,const PHY__Vector3& aabbMax) +{ + m_localAabbMin.setValue(aabbMin[0],aabbMin[1],aabbMin[2]); + m_localAabbMax.setValue(aabbMax[0],aabbMax[1],aabbMax[2]); + SetGraphicTransform(); +} + +void CcdGraphicController::setLocalAabb(const float* aabbMin,const float* aabbMax) +{ + m_localAabbMin.setValue(aabbMin[0],aabbMin[1],aabbMin[2]); + m_localAabbMax.setValue(aabbMax[0],aabbMax[1],aabbMax[2]); + SetGraphicTransform(); +} void CcdGraphicController::getAabb(btVector3& aabbMin, btVector3& aabbMax) { @@ -105,8 +118,17 @@ PHY_IGraphicController* CcdGraphicController::GetReplica(class PHY_IMotionState* replica->m_motionState = motionState; replica->m_newClientInfo = NULL; replica->m_handle = NULL; - m_phyEnv->addCcdGraphicController(replica); + // don't add the graphic controller now: work around a bug in Bullet with rescaling, + // (the scale of the controller is not yet defined). + //m_phyEnv->addCcdGraphicController(replica); return replica; } +void CcdGraphicController::Activate(bool active) +{ + if (active) + m_phyEnv->addCcdGraphicController(this); + else + m_phyEnv->removeCcdGraphicController(this); +} diff --git a/source/gameengine/Physics/Bullet/CcdGraphicController.h b/source/gameengine/Physics/Bullet/CcdGraphicController.h index 8faa0944313..b0626f902c2 100644 --- a/source/gameengine/Physics/Bullet/CcdGraphicController.h +++ b/source/gameengine/Physics/Bullet/CcdGraphicController.h @@ -38,6 +38,8 @@ public: void setLocalAabb(const btVector3& aabbMin,const btVector3& aabbMax); void setLocalAabb(const MT_Point3& aabbMin,const MT_Point3& aabbMax); + virtual void setLocalAabb(const PHY__Vector3& aabbMin,const PHY__Vector3& aabbMax); + virtual void setLocalAabb(const float aabbMin[3],const float aabbMax[3]); PHY_IMotionState* GetMotionState() { return m_motionState; } void getAabb(btVector3& aabbMin, btVector3& aabbMax); @@ -53,6 +55,10 @@ public: * Updates the Aabb based on the motion state */ virtual bool SetGraphicTransform(); + /** + * Add/remove to environment + */ + virtual void Activate(bool active); // client info for culling virtual void* getNewClientInfo() { return m_newClientInfo; } diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index 0b9da8f46d3..d22c09b4d3e 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -35,6 +35,10 @@ subject to the following restrictions: #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +extern "C"{ +#include "BKE_cdderivedmesh.h" +} + class BP_Proxy; ///todo: fill all the empty CcdPhysicsController methods, hook them up to the btRigidBody class @@ -88,16 +92,19 @@ CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci) } -btTransform CcdPhysicsController::GetTransformFromMotionState(PHY_IMotionState* motionState) +btTransform& CcdPhysicsController::GetTransformFromMotionState(PHY_IMotionState* motionState) { - btTransform trans; - float tmp[3]; - motionState->getWorldPosition(tmp[0],tmp[1],tmp[2]); - trans.setOrigin(btVector3(tmp[0],tmp[1],tmp[2])); - - btQuaternion orn; - motionState->getWorldOrientation(orn[0],orn[1],orn[2],orn[3]); - trans.setRotation(orn); + static btTransform trans; + btVector3 tmp; + motionState->getWorldPosition(tmp.m_floats[0], tmp.m_floats[1], tmp.m_floats[2]); + trans.setOrigin(tmp); + + float ori[12]; + motionState->getWorldOrientation(ori); + trans.getBasis().setFromOpenGLSubMatrix(ori); + //btQuaternion orn; + //motionState->getWorldOrientation(orn[0],orn[1],orn[2],orn[3]); + //trans.setRotation(orn); return trans; } @@ -114,18 +121,18 @@ public: } - virtual void getWorldTransform(btTransform& worldTrans ) const + void getWorldTransform(btTransform& worldTrans ) const { - float pos[3]; - float quatOrn[4]; + btVector3 pos; + float ori[12]; - m_blenderMotionState->getWorldPosition(pos[0],pos[1],pos[2]); - m_blenderMotionState->getWorldOrientation(quatOrn[0],quatOrn[1],quatOrn[2],quatOrn[3]); - worldTrans.setOrigin(btVector3(pos[0],pos[1],pos[2])); - worldTrans.setBasis(btMatrix3x3(btQuaternion(quatOrn[0],quatOrn[1],quatOrn[2],quatOrn[3]))); + m_blenderMotionState->getWorldPosition(pos.m_floats[0],pos.m_floats[1],pos.m_floats[2]); + m_blenderMotionState->getWorldOrientation(ori); + worldTrans.setOrigin(pos); + worldTrans.getBasis().setFromOpenGLSubMatrix(ori); } - virtual void setWorldTransform(const btTransform& worldTrans) + void setWorldTransform(const btTransform& worldTrans) { m_blenderMotionState->setWorldPosition(worldTrans.getOrigin().getX(),worldTrans.getOrigin().getY(),worldTrans.getOrigin().getZ()); btQuaternion rotQuat = worldTrans.getRotation(); @@ -178,12 +185,12 @@ void CcdPhysicsController::CreateRigidbody() rbci.m_restitution = m_cci.m_restitution; - int nodecount = 0; + + - int numtriangles = 1; btVector3 p(0,0,0);// = getOrigin(); - btScalar h = 1.f; + btSoftRigidDynamicsWorld* softDynaWorld = (btSoftRigidDynamicsWorld*)m_cci.m_physicsEnv->getDynamicsWorld(); @@ -289,7 +296,11 @@ void CcdPhysicsController::CreateRigidbody() } } - + if (m_cci.m_margin > 0.f) + { + psb->getCollisionShape()->setMargin(m_cci.m_margin); + psb->updateBounds(); + } m_object = psb; @@ -489,10 +500,12 @@ void CcdPhysicsController::CreateRigidbody() //convert collision flags! //special case: a near/radar sensor controller should not be defined static or it will //generate loads of static-static collision messages on the console - if ((m_cci.m_collisionFilterGroup & CcdConstructionInfo::SensorFilter) != 0) + if (m_cci.m_bSensor) { // reset the flags that have been set so far GetCollisionObject()->setCollisionFlags(0); + // sensor must never go to sleep: they need to detect continously + GetCollisionObject()->setActivationState(DISABLE_DEACTIVATION); } GetCollisionObject()->setCollisionFlags(m_object->getCollisionFlags() | m_cci.m_collisionFlags); btRigidBody* body = GetRigidBody(); @@ -506,6 +519,8 @@ void CcdPhysicsController::CreateRigidbody() { body->setAngularFactor(0.f); } + body->setContactProcessingThreshold(m_cci.m_contactProcessingThreshold); + } if (m_object && m_cci.m_do_anisotropic) { @@ -572,10 +587,22 @@ bool CcdPhysicsController::SynchronizeMotionStates(float time) btSoftBody* sb = GetSoftBody(); if (sb) { - btVector3 aabbMin,aabbMax; - sb->getAabb(aabbMin,aabbMax); - btVector3 worldPos = (aabbMax+aabbMin)*0.5f; - m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]); + if (sb->m_pose.m_bframe) + { + btVector3 worldPos = sb->m_pose.m_com; + btQuaternion worldquat; + btMatrix3x3 trs = sb->m_pose.m_rot*sb->m_pose.m_scl; + trs.getRotation(worldquat); + m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]); + m_MotionState->setWorldOrientation(worldquat[0],worldquat[1],worldquat[2],worldquat[3]); + } + else + { + btVector3 aabbMin,aabbMax; + sb->getAabb(aabbMin,aabbMax); + btVector3 worldPos = (aabbMax+aabbMin)*0.5f; + m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]); + } m_MotionState->calculateWorldTransformations(); return true; } @@ -597,12 +624,13 @@ bool CcdPhysicsController::SynchronizeMotionStates(float time) body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_min / len)); } - const btVector3& worldPos = body->getCenterOfMassPosition(); + const btTransform& xform = body->getCenterOfMassTransform(); + const btMatrix3x3& worldOri = xform.getBasis(); + const btVector3& worldPos = xform.getOrigin(); + float ori[12]; + worldOri.getOpenGLSubMatrix(ori); + m_MotionState->setWorldOrientation(ori); m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]); - - const btQuaternion& worldquat = body->getOrientation(); - m_MotionState->setWorldOrientation(worldquat[0],worldquat[1],worldquat[2],worldquat[3]); - m_MotionState->calculateWorldTransformations(); float scale[3]; @@ -639,8 +667,10 @@ bool CcdPhysicsController::SynchronizeMotionStates(float time) void CcdPhysicsController::WriteMotionStateToDynamics(bool nondynaonly) { - + btTransform& xform = CcdPhysicsController::GetTransformFromMotionState(m_MotionState); + SetCenterOfMassTransform(xform); } + void CcdPhysicsController::WriteDynamicsToMotionState() { } @@ -657,12 +687,12 @@ void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionsta if (m_shapeInfo) { m_shapeInfo->AddRef(); - m_collisionShape = m_shapeInfo->CreateBulletShape(); + m_collisionShape = m_shapeInfo->CreateBulletShape(m_cci.m_margin); if (m_collisionShape) { // new shape has no scaling, apply initial scaling - m_collisionShape->setMargin(m_cci.m_margin); + //m_collisionShape->setMargin(m_cci.m_margin); m_collisionShape->setLocalScaling(m_cci.m_scaling); if (m_cci.m_mass) @@ -670,19 +700,29 @@ void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionsta } } + // load some characterists that are not + btRigidBody* oldbody = GetRigidBody(); m_object = 0; CreateRigidbody(); - btRigidBody* body = GetRigidBody(); - if (body) { if (m_cci.m_mass) { body->setMassProps(m_cci.m_mass, m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); } - } - m_cci.m_physicsEnv->addCcdPhysicsController(this); + + if (oldbody) + { + body->setLinearFactor(oldbody->getLinearFactor()); + body->setAngularFactor(oldbody->getAngularFactor()); + if (oldbody->getActivationState() == DISABLE_DEACTIVATION) + body->setActivationState(DISABLE_DEACTIVATION); + } + } + // sensor object are added when needed + if (!m_cci.m_bSensor) + m_cci.m_physicsEnv->addCcdPhysicsController(this); /* SM_Object* dynaparent=0; @@ -759,10 +799,13 @@ void CcdPhysicsController::RelativeTranslate(float dlocX,float dlocY,float dloc m_object->activate(true); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + // kinematic object should not set the transform, it disturbs the velocity interpolation + return; } - btRigidBody* body = GetRigidBody(); + // btRigidBody* body = GetRigidBody(); // not used anymore btVector3 dloc(dlocX,dlocY,dlocZ); btTransform xform = m_object->getWorldTransform(); @@ -785,7 +828,10 @@ void CcdPhysicsController::RelativeRotate(const float rotval[9],bool local) m_object->activate(true); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + // kinematic object should not set the transform, it disturbs the velocity interpolation + return; } btMatrix3x3 drotmat( rotval[0],rotval[4],rotval[8], @@ -808,10 +854,9 @@ void CcdPhysicsController::RelativeRotate(const float rotval[9],bool local) void CcdPhysicsController::GetWorldOrientation(btMatrix3x3& mat) { - float orn[4]; - m_MotionState->getWorldOrientation(orn[0],orn[1],orn[2],orn[3]); - btQuaternion quat(orn[0],orn[1],orn[2],orn[3]); - mat.setRotation(quat); + float ori[12]; + m_MotionState->getWorldOrientation(ori); + mat.setFromOpenGLSubMatrix(ori); } void CcdPhysicsController::getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal) @@ -829,7 +874,10 @@ void CcdPhysicsController::setOrientation(float quatImag0,float quatImag1,float m_object->activate(true); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + // kinematic object should not set the transform, it disturbs the velocity interpolation + return; } // not required //m_MotionState->setWorldOrientation(quatImag0,quatImag1,quatImag2,quatReal); @@ -850,7 +898,7 @@ void CcdPhysicsController::setWorldOrientation(const btMatrix3x3& orn) if (m_object) { m_object->activate(true); - if (m_object->isStaticObject()) + if (m_object->isStaticObject() && !m_cci.m_bSensor) { m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } @@ -881,7 +929,10 @@ void CcdPhysicsController::setPosition(float posX,float posY,float posZ) m_object->activate(true); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + // kinematic object should not set the transform, it disturbs the velocity interpolation + return; } // not required, this function is only used to update the physic controller //m_MotionState->setWorldPosition(posX,posY,posZ); @@ -893,9 +944,19 @@ void CcdPhysicsController::setPosition(float posX,float posY,float posZ) // not required //m_bulletMotionState->setWorldTransform(xform); } +} - +void CcdPhysicsController::forceWorldTransform(const btMatrix3x3& mat, const btVector3& pos) +{ + if (m_object) + { + btTransform& xform = m_object->getWorldTransform(); + xform.setBasis(mat); + xform.setOrigin(pos); + } } + + void CcdPhysicsController::resolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) { } @@ -945,14 +1006,24 @@ void CcdPhysicsController::ApplyTorque(float torqueX,float torqueY,float torque m_object->activate(); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + return; } if (local) { torque = xform.getBasis()*torque; } if (body) + { + //workaround for incompatibility between 'DYNAMIC' game object, and angular factor + //a DYNAMIC object has some inconsistency: it has no angular effect due to collisions, but still has torque + const btVector3& angFac = body->getAngularFactor(); + btVector3 tmpFac(0,0,1); + body->setAngularFactor(tmpFac); body->applyTorque(torque); + body->setAngularFactor(angFac); + } } } @@ -966,27 +1037,26 @@ void CcdPhysicsController::ApplyForce(float forceX,float forceY,float forceZ,bo m_object->activate(); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + return; } - + btTransform xform = m_object->getWorldTransform(); + + if (local) + { + force = xform.getBasis()*force; + } + btRigidBody* body = GetRigidBody(); + if (body) + body->applyCentralForce(force); + btSoftBody* soft = GetSoftBody(); + if (soft) { - btTransform xform = m_object->getWorldTransform(); - - if (local) - { - force = xform.getBasis()*force; - } - btRigidBody* body = GetRigidBody(); - if (body) - body->applyCentralForce(force); - btSoftBody* soft = GetSoftBody(); - if (soft) - { - // the force is applied on each node, must reduce it in the same extend - if (soft->m_nodes.size() > 0) - force /= soft->m_nodes.size(); - soft->addForce(force); - } + // the force is applied on each node, must reduce it in the same extend + if (soft->m_nodes.size() > 0) + force /= soft->m_nodes.size(); + soft->addForce(force); } } } @@ -998,19 +1068,18 @@ void CcdPhysicsController::SetAngularVelocity(float ang_velX,float ang_velY,flo m_object->activate(true); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); - } else + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + return; + } + btTransform xform = m_object->getWorldTransform(); + if (local) { - btTransform xform = m_object->getWorldTransform(); - if (local) - { - angvel = xform.getBasis()*angvel; - } - btRigidBody* body = GetRigidBody(); - if (body) - body->setAngularVelocity(angvel); - + angvel = xform.getBasis()*angvel; } + btRigidBody* body = GetRigidBody(); + if (body) + body->setAngularVelocity(angvel); } } @@ -1023,7 +1092,8 @@ void CcdPhysicsController::SetLinearVelocity(float lin_velX,float lin_velY,floa m_object->activate(true); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); return; } @@ -1057,7 +1127,9 @@ void CcdPhysicsController::applyImpulse(float attachX,float attachY,float attac m_object->activate(); if (m_object->isStaticObject()) { - m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + if (!m_cci.m_bSensor) + m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + return; } btVector3 pos(attachX,attachY,attachZ); @@ -1184,7 +1256,7 @@ PHY_IPhysicsController* CcdPhysicsController::GetReplica() if (m_shapeInfo) { // This situation does not normally happen - cinfo.m_collisionShape = m_shapeInfo->CreateBulletShape(); + cinfo.m_collisionShape = m_shapeInfo->CreateBulletShape(0.01); } else if (m_collisionShape) { @@ -1251,28 +1323,22 @@ void DefaultMotionState::getWorldScaling(float& scaleX,float& scaleY,float& scal void DefaultMotionState::getWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal) { - quatIma0 = m_worldTransform.getRotation().x(); - quatIma1 = m_worldTransform.getRotation().y(); - quatIma2 = m_worldTransform.getRotation().z(); - quatReal = m_worldTransform.getRotation()[3]; + btQuaternion quat = m_worldTransform.getRotation(); + quatIma0 = quat.x(); + quatIma1 = quat.y(); + quatIma2 = quat.z(); + quatReal = quat[3]; } void DefaultMotionState::getWorldOrientation(float* ori) { - *ori++ = m_worldTransform.getBasis()[0].x(); - *ori++ = m_worldTransform.getBasis()[1].x(); - *ori++ = m_worldTransform.getBasis()[1].x(); - *ori++ = 0.f; - *ori++ = m_worldTransform.getBasis()[0].y(); - *ori++ = m_worldTransform.getBasis()[1].y(); - *ori++ = m_worldTransform.getBasis()[1].y(); - *ori++ = 0.f; - *ori++ = m_worldTransform.getBasis()[0].z(); - *ori++ = m_worldTransform.getBasis()[1].z(); - *ori++ = m_worldTransform.getBasis()[1].z(); - *ori++ = 0.f; + m_worldTransform.getBasis().getOpenGLSubMatrix(ori); } +void DefaultMotionState::setWorldOrientation(const float* ori) +{ + m_worldTransform.getBasis().setFromOpenGLSubMatrix(ori); +} void DefaultMotionState::setWorldPosition(float posX,float posY,float posZ) { btVector3 pos(posX,posY,posZ); @@ -1293,9 +1359,9 @@ void DefaultMotionState::calculateWorldTransformations() // Shape constructor std::map<RAS_MeshObject*, CcdShapeConstructionInfo*> CcdShapeConstructionInfo::m_meshShapeMap; -CcdShapeConstructionInfo* CcdShapeConstructionInfo::FindMesh(RAS_MeshObject* mesh, bool polytope) +CcdShapeConstructionInfo* CcdShapeConstructionInfo::FindMesh(RAS_MeshObject* mesh, struct DerivedMesh* dm, bool polytope, bool gimpact) { - if (polytope) + if (polytope || dm || gimpact) // not yet supported return NULL; @@ -1305,9 +1371,9 @@ CcdShapeConstructionInfo* CcdShapeConstructionInfo::FindMesh(RAS_MeshObject* mes return NULL; } -bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, bool polytope,bool useGimpact) +bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, bool polytope,bool useGimpact) { - int numpolys; + int numpolys, numverts; m_useGimpact = useGimpact; @@ -1316,6 +1382,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, bool polytope,bo assert(IsUnused()); m_shapeType = PHY_SHAPE_NONE; m_meshObject = NULL; + bool free_dm = false; // No mesh object or mesh has no polys if (!meshobj || meshobj->HasColliderPolygon()==false) { @@ -1325,164 +1392,182 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, bool polytope,bo return false; } - numpolys = meshobj->NumPolygons(); + if (!dm) { + free_dm = true; + dm = CDDM_from_mesh(meshobj->GetMesh(), NULL); + } + + MVert *mvert = dm->getVertArray(dm); + MFace *mface = dm->getFaceArray(dm); + numpolys = dm->getNumFaces(dm); + numverts = dm->getNumVerts(dm); + int* index = (int*)dm->getFaceDataArray(dm, CD_ORIGINDEX); m_shapeType = (polytope) ? PHY_SHAPE_POLYTOPE : PHY_SHAPE_MESH; /* Convert blender geometry into bullet mesh, need these vars for mapping */ - vector<bool> vert_tag_array(meshobj->GetMesh()->totvert, false); + vector<bool> vert_tag_array(numverts, false); unsigned int tot_bt_verts= 0; - unsigned int orig_index; - int i; if (polytope) { // Tag verts we're using for (int p2=0; p2<numpolys; p2++) { - RAS_Polygon* poly= meshobj->GetPolygon(p2); + MFace* mf = &mface[p2]; + RAS_Polygon* poly = meshobj->GetPolygon(index[p2]); // only add polygons that have the collision flag set if (poly->IsCollider()) { - for(i=0; i<poly->VertexCount(); i++) { - orig_index= poly->GetVertex(i)->getOrigIndex(); - if (vert_tag_array[orig_index]==false) - { - vert_tag_array[orig_index]= true; - tot_bt_verts++; - } - } + if (vert_tag_array[mf->v1]==false) {vert_tag_array[mf->v1]= true;tot_bt_verts++;} + if (vert_tag_array[mf->v2]==false) {vert_tag_array[mf->v2]= true;tot_bt_verts++;} + if (vert_tag_array[mf->v3]==false) {vert_tag_array[mf->v3]= true;tot_bt_verts++;} + if (mf->v4 && vert_tag_array[mf->v4]==false) {vert_tag_array[mf->v4]= true;tot_bt_verts++;} } } - m_vertexArray.resize(tot_bt_verts); + m_vertexArray.resize(tot_bt_verts*3); - btVector3 *bt= &m_vertexArray[0]; + btScalar *bt= &m_vertexArray[0]; for (int p2=0; p2<numpolys; p2++) { - RAS_Polygon* poly= meshobj->GetPolygon(p2); + MFace* mf = &mface[p2]; + RAS_Polygon* poly= meshobj->GetPolygon(index[p2]); // only add polygons that have the collisionflag set if (poly->IsCollider()) { - for(i=0; i<poly->VertexCount(); i++) { - RAS_TexVert *v= poly->GetVertex(i); - orig_index= v->getOrigIndex(); - - if (vert_tag_array[orig_index]==true) - { - const float* vtx = v->getXYZ(); - vert_tag_array[orig_index]= false; - - bt->setX(vtx[0]); bt->setY(vtx[1]); bt->setZ(vtx[2]); - bt++; - } + if (vert_tag_array[mf->v1]==true) + { + const float* vtx = mvert[mf->v1].co; + vert_tag_array[mf->v1]= false; + *bt++ = vtx[0]; + *bt++ = vtx[1]; + *bt++ = vtx[2]; + } + if (vert_tag_array[mf->v2]==true) + { + const float* vtx = mvert[mf->v2].co; + vert_tag_array[mf->v2]= false; + *bt++ = vtx[0]; + *bt++ = vtx[1]; + *bt++ = vtx[2]; + } + if (vert_tag_array[mf->v3]==true) + { + const float* vtx = mvert[mf->v3].co; + vert_tag_array[mf->v3]= false; + *bt++ = vtx[0]; + *bt++ = vtx[1]; + *bt++ = vtx[2]; + } + if (mf->v4 && vert_tag_array[mf->v4]==true) + { + const float* vtx = mvert[mf->v4].co; + vert_tag_array[mf->v4]= false; + *bt++ = vtx[0]; + *bt++ = vtx[1]; + *bt++ = vtx[2]; } } } } else { unsigned int tot_bt_tris= 0; - vector<int> vert_remap_array(meshobj->GetMesh()->totvert, 0); + vector<int> vert_remap_array(numverts, 0); // Tag verts we're using for (int p2=0; p2<numpolys; p2++) { - RAS_Polygon* poly= meshobj->GetPolygon(p2); + MFace* mf = &mface[p2]; + RAS_Polygon* poly= meshobj->GetPolygon(index[p2]); // only add polygons that have the collision flag set if (poly->IsCollider()) { - for(i=0; i<poly->VertexCount(); i++) { - orig_index= poly->GetVertex(i)->getOrigIndex(); - if (vert_tag_array[orig_index]==false) - { - vert_tag_array[orig_index]= true; - vert_remap_array[orig_index]= tot_bt_verts; - tot_bt_verts++; - } - } - - tot_bt_tris += (i==4 ? 2:1); /* a quad or a tri */ + if (vert_tag_array[mf->v1]==false) + {vert_tag_array[mf->v1]= true;vert_remap_array[mf->v1]= tot_bt_verts;tot_bt_verts++;} + if (vert_tag_array[mf->v2]==false) + {vert_tag_array[mf->v2]= true;vert_remap_array[mf->v2]= tot_bt_verts;tot_bt_verts++;} + if (vert_tag_array[mf->v3]==false) + {vert_tag_array[mf->v3]= true;vert_remap_array[mf->v3]= tot_bt_verts;tot_bt_verts++;} + if (mf->v4 && vert_tag_array[mf->v4]==false) + {vert_tag_array[mf->v4]= true;vert_remap_array[mf->v4]= tot_bt_verts;tot_bt_verts++;} + tot_bt_tris += (mf->v4 ? 2:1); /* a quad or a tri */ } } - m_vertexArray.resize(tot_bt_verts); + m_vertexArray.resize(tot_bt_verts*3); m_polygonIndexArray.resize(tot_bt_tris); m_triFaceArray.resize(tot_bt_tris*3); - btVector3 *bt= &m_vertexArray[0]; + btScalar *bt= &m_vertexArray[0]; int *poly_index_pt= &m_polygonIndexArray[0]; int *tri_pt= &m_triFaceArray[0]; - for (int p2=0; p2<numpolys; p2++) { - RAS_Polygon* poly= meshobj->GetPolygon(p2); + MFace* mf = &mface[p2]; + RAS_Polygon* poly= meshobj->GetPolygon(index[p2]); // only add polygons that have the collisionflag set if (poly->IsCollider()) { - RAS_TexVert *v1= poly->GetVertex(0); - RAS_TexVert *v2= poly->GetVertex(1); - RAS_TexVert *v3= poly->GetVertex(2); - int i1= v1->getOrigIndex(); - int i2= v2->getOrigIndex(); - int i3= v3->getOrigIndex(); - const float* vtx; + MVert *v1= &mvert[mf->v1]; + MVert *v2= &mvert[mf->v2]; + MVert *v3= &mvert[mf->v3]; // the face indicies - tri_pt[0]= vert_remap_array[i1]; - tri_pt[1]= vert_remap_array[i2]; - tri_pt[2]= vert_remap_array[i3]; + tri_pt[0]= vert_remap_array[mf->v1]; + tri_pt[1]= vert_remap_array[mf->v2]; + tri_pt[2]= vert_remap_array[mf->v3]; tri_pt= tri_pt+3; // m_polygonIndexArray - *poly_index_pt= p2; + *poly_index_pt= index[p2]; poly_index_pt++; // the vertex location - if (vert_tag_array[i1]==true) { /* *** v1 *** */ - vert_tag_array[i1]= false; - vtx = v1->getXYZ(); - bt->setX(vtx[0]); bt->setY( vtx[1]); bt->setZ(vtx[2]); - bt++; + if (vert_tag_array[mf->v1]==true) { /* *** v1 *** */ + vert_tag_array[mf->v1]= false; + *bt++ = v1->co[0]; + *bt++ = v1->co[1]; + *bt++ = v1->co[2]; } - if (vert_tag_array[i2]==true) { /* *** v2 *** */ - vert_tag_array[i2]= false; - vtx = v2->getXYZ(); - bt->setX(vtx[0]); bt->setY(vtx[1]); bt->setZ(vtx[2]); - bt++; + if (vert_tag_array[mf->v2]==true) { /* *** v2 *** */ + vert_tag_array[mf->v2]= false; + *bt++ = v2->co[0]; + *bt++ = v2->co[1]; + *bt++ = v2->co[2]; } - if (vert_tag_array[i3]==true) { /* *** v3 *** */ - vert_tag_array[i3]= false; - vtx = v3->getXYZ(); - bt->setX(vtx[0]); bt->setY(vtx[1]); bt->setZ(vtx[2]); - bt++; + if (vert_tag_array[mf->v3]==true) { /* *** v3 *** */ + vert_tag_array[mf->v3]= false; + *bt++ = v3->co[0]; + *bt++ = v3->co[1]; + *bt++ = v3->co[2]; } - if (poly->VertexCount()==4) + if (mf->v4) { - RAS_TexVert *v4= poly->GetVertex(3); - int i4= v4->getOrigIndex(); + MVert *v4= &mvert[mf->v4]; - tri_pt[0]= vert_remap_array[i1]; - tri_pt[1]= vert_remap_array[i3]; - tri_pt[2]= vert_remap_array[i4]; + tri_pt[0]= vert_remap_array[mf->v1]; + tri_pt[1]= vert_remap_array[mf->v3]; + tri_pt[2]= vert_remap_array[mf->v4]; tri_pt= tri_pt+3; // m_polygonIndexArray - *poly_index_pt= p2; + *poly_index_pt= index[p2]; poly_index_pt++; // the vertex location - if (vert_tag_array[i4]==true) { /* *** v4 *** */ - vert_tag_array[i4]= false; - vtx = v4->getXYZ(); - bt->setX(vtx[0]); bt->setY(vtx[1]); bt->setZ(vtx[2]); - bt++; + if (vert_tag_array[mf->v4]==true) { /* *** v4 *** */ + vert_tag_array[mf->v4]= false; + *bt++ = v4->co[0]; + *bt++ = v4->co[1]; + *bt++ = v4->co[2]; } } } @@ -1514,7 +1599,13 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, bool polytope,bo #endif m_meshObject = meshobj; - if (!polytope) + if (free_dm) { + dm->release(dm); + dm = NULL; + } + + // sharing only on static mesh at present, if you change that, you must also change in FindMesh + if (!polytope && !dm && !useGimpact) { // triangle shape can be shared, store the mesh object in the map m_meshShapeMap.insert(std::pair<RAS_MeshObject*,CcdShapeConstructionInfo*>(meshobj,this)); @@ -1533,15 +1624,13 @@ bool CcdShapeConstructionInfo::SetProxy(CcdShapeConstructionInfo* shapeInfo) return true; } -btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() +btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape(btScalar margin) { btCollisionShape* collisionShape = 0; - btTriangleMeshShape* concaveShape = 0; - btCompoundShape* compoundShape = 0; - CcdShapeConstructionInfo* nextShapeInfo; + btCompoundShape* compoundShape = 0; if (m_shapeType == PHY_SHAPE_PROXY && m_shapeProxy != NULL) - return m_shapeProxy->CreateBulletShape(); + return m_shapeProxy->CreateBulletShape(margin); switch (m_shapeType) { @@ -1550,22 +1639,27 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() case PHY_SHAPE_BOX: collisionShape = new btBoxShape(m_halfExtend); + collisionShape->setMargin(margin); break; case PHY_SHAPE_SPHERE: collisionShape = new btSphereShape(m_radius); + collisionShape->setMargin(margin); break; case PHY_SHAPE_CYLINDER: collisionShape = new btCylinderShapeZ(m_halfExtend); + collisionShape->setMargin(margin); break; case PHY_SHAPE_CONE: collisionShape = new btConeShapeZ(m_radius, m_height); + collisionShape->setMargin(margin); break; case PHY_SHAPE_POLYTOPE: - collisionShape = new btConvexHullShape(&m_vertexArray[0].getX(), m_vertexArray.size()); + collisionShape = new btConvexHullShape(&m_vertexArray[0], m_vertexArray.size()/3, 3*sizeof(btScalar)); + collisionShape->setMargin(margin); break; case PHY_SHAPE_MESH: @@ -1582,13 +1676,13 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() m_polygonIndexArray.size(), &m_triFaceArray[0], 3*sizeof(int), - m_vertexArray.size(), - (btScalar*) &m_vertexArray[0].x(), - sizeof(btVector3) + m_vertexArray.size()/3, + &m_vertexArray[0], + 3*sizeof(btScalar) ); btGImpactMeshShape* gimpactShape = new btGImpactMeshShape(indexVertexArrays); - + gimpactShape->setMargin(margin); collisionShape = gimpactShape; gimpactShape->updateBound(); @@ -1606,13 +1700,14 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() collisionMeshData->m_weldingThreshold = m_weldingThreshold1; bool removeDuplicateVertices=true; // m_vertexArray not in multiple of 3 anymore, use m_triFaceArray - for(int i=0; i<m_triFaceArray.size(); i+=3) { - collisionMeshData->addTriangle( - m_vertexArray[m_triFaceArray[i]], - m_vertexArray[m_triFaceArray[i+1]], - m_vertexArray[m_triFaceArray[i+2]], - removeDuplicateVertices - ); + for(unsigned int i=0; i<m_triFaceArray.size(); i+=3) { + btScalar *bt = &m_vertexArray[3*m_triFaceArray[i]]; + btVector3 v1(bt[0], bt[1], bt[2]); + bt = &m_vertexArray[3*m_triFaceArray[i+1]]; + btVector3 v2(bt[0], bt[1], bt[2]); + bt = &m_vertexArray[3*m_triFaceArray[i+2]]; + btVector3 v3(bt[0], bt[1], bt[2]); + collisionMeshData->addTriangle(v1, v2, v3, removeDuplicateVertices); } indexVertexArrays = collisionMeshData; @@ -1622,9 +1717,9 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() m_polygonIndexArray.size(), &m_triFaceArray[0], 3*sizeof(int), - m_vertexArray.size(), - (btScalar*) &m_vertexArray[0].x(), - sizeof(btVector3)); + m_vertexArray.size()/3, + &m_vertexArray[0], + 3*sizeof(btScalar)); } // this shape will be shared and not deleted until shapeInfo is deleted @@ -1632,6 +1727,7 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() m_unscaledShape->recalcLocalAabb(); } collisionShape = new btScaledBvhTriangleMeshShape(m_unscaledShape, btVector3(1.0f,1.0f,1.0f)); + collisionShape->setMargin(margin); } break; @@ -1643,7 +1739,7 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape() sit != m_shapeArray.end(); sit++) { - collisionShape = (*sit)->CreateBulletShape(); + collisionShape = (*sit)->CreateBulletShape(margin); if (collisionShape) { collisionShape->setLocalScaling((*sit)->m_childScale); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 4510bbddf65..d73759bac76 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -36,6 +36,7 @@ extern bool gDisableDeactivation; class CcdPhysicsEnvironment; class btMotionState; class RAS_MeshObject; +struct DerivedMesh; class btCollisionShape; @@ -59,7 +60,7 @@ class CcdShapeConstructionInfo public: - static CcdShapeConstructionInfo* FindMesh(RAS_MeshObject* mesh, bool polytope); + static CcdShapeConstructionInfo* FindMesh(class RAS_MeshObject* mesh, struct DerivedMesh* dm, bool polytope, bool gimpact); CcdShapeConstructionInfo() : m_shapeType(PHY_SHAPE_NONE), @@ -139,7 +140,7 @@ public: return true; } - bool SetMesh(RAS_MeshObject* mesh, bool polytope,bool useGimpact); + bool SetMesh(class RAS_MeshObject* mesh, struct DerivedMesh* dm, bool polytope,bool useGimpact); RAS_MeshObject* GetMesh(void) { return m_meshObject; @@ -151,7 +152,7 @@ public: return m_shapeProxy; } - btCollisionShape* CreateBulletShape(); + btCollisionShape* CreateBulletShape(btScalar margin); // member variables PHY_ShapeType m_shapeType; @@ -161,8 +162,8 @@ public: btTransform m_childTrans; btVector3 m_childScale; void* m_userData; - btAlignedObjectArray<btVector3> m_vertexArray; // Contains both vertex array for polytope shape and - // triangle array for concave mesh shape. + btAlignedObjectArray<btScalar> m_vertexArray; // Contains both vertex array for polytope shape and + // triangle array for concave mesh shape. Each vertex is 3 consecutive values // In this case a triangle is made of 3 consecutive points std::vector<int> m_polygonIndexArray; // Contains the array of polygon index in the // original mesh that correspond to shape triangles. @@ -173,11 +174,7 @@ public: void setVertexWeldingThreshold1(float threshold) { - m_weldingThreshold1 = threshold; - } - float getVertexWeldingThreshold1() const - { - return m_weldingThreshold1; + m_weldingThreshold1 = threshold*threshold; } protected: static std::map<RAS_MeshObject*, CcdShapeConstructionInfo*> m_meshShapeMap; @@ -225,6 +222,7 @@ struct CcdConstructionInfo m_collisionFlags(0), m_bRigid(false), m_bSoft(false), + m_bSensor(false), m_collisionFilterGroup(DefaultFilter), m_collisionFilterMask(AllFilter), m_collisionShape(0), @@ -233,7 +231,8 @@ struct CcdConstructionInfo m_physicsEnv(0), m_inertiaFactor(1.f), m_do_anisotropic(false), - m_anisotropicFriction(1.f,1.f,1.f) + m_anisotropicFriction(1.f,1.f,1.f), + m_contactProcessingThreshold(1e10) { } @@ -291,6 +290,7 @@ struct CcdConstructionInfo int m_collisionFlags; bool m_bRigid; bool m_bSoft; + bool m_bSensor; ///optional use of collision group/mask: ///only collision with object goups that match the collision mask. @@ -318,6 +318,13 @@ struct CcdConstructionInfo btScalar m_fh_distance; ///< The range above the surface where Fh is active. bool m_fh_normal; ///< Should the object slide off slopes? float m_radius;//for fh backwards compatibility + + ///m_contactProcessingThreshold allows to process contact points with positive distance + ///normally only contacts with negative distance (penetration) are solved + ///however, rigid body stacking is more stable when positive contacts are still passed into the constraint solver + ///this might sometimes lead to collisions with 'internal edges' such as a sliding character controller + ///so disable/set m_contactProcessingThreshold to zero for sliding characters etc. + float m_contactProcessingThreshold;///< Process contacts with positive distance in range [0..INF] }; @@ -329,7 +336,7 @@ class btSoftBody; ///CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution. class CcdPhysicsController : public PHY_IPhysicsController { - +protected: btCollisionObject* m_object; @@ -364,8 +371,8 @@ class CcdPhysicsController : public PHY_IPhysicsController return (--m_registerCount == 0) ? true : false; } - protected: - void setWorldOrientation(const btMatrix3x3& mat); + void setWorldOrientation(const btMatrix3x3& mat); + void forceWorldTransform(const btMatrix3x3& mat, const btVector3& pos); public: @@ -410,6 +417,7 @@ class CcdPhysicsController : public PHY_IPhysicsController virtual void WriteMotionStateToDynamics(bool nondynaonly); virtual void WriteDynamicsToMotionState(); + // controller replication virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl); @@ -508,7 +516,7 @@ class CcdPhysicsController : public PHY_IPhysicsController void SetCenterOfMassTransform(btTransform& xform); - static btTransform GetTransformFromMotionState(PHY_IMotionState* motionState); + static btTransform& GetTransformFromMotionState(PHY_IMotionState* motionState); void setAabb(const btVector3& aabbMin,const btVector3& aabbMax); @@ -566,6 +574,7 @@ class DefaultMotionState : public PHY_IMotionState virtual void setWorldPosition(float posX,float posY,float posZ); virtual void setWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal); virtual void getWorldOrientation(float* ori); + virtual void setWorldOrientation(const float* ori); virtual void calculateWorldTransformations(); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index 3e1e0294321..bc7ccacc39b 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -415,61 +415,7 @@ void CcdPhysicsEnvironment::addCcdPhysicsController(CcdPhysicsController* ctrl) obj->setActivationState(ISLAND_SLEEPING); } - - //CollisionObject(body,ctrl->GetCollisionFilterGroup(),ctrl->GetCollisionFilterMask()); - assert(obj->getBroadphaseHandle()); - - btBroadphaseInterface* scene = getBroadphase(); - - - btCollisionShape* shapeinterface = ctrl->GetCollisionShape(); - - assert(shapeinterface); - - const btTransform& t = ctrl->GetCollisionObject()->getWorldTransform(); - - - btVector3 minAabb,maxAabb; - - shapeinterface->getAabb(t,minAabb,maxAabb); - - float timeStep = 0.02f; - - - //extent it with the motion - - if (body) - { - btVector3 linMotion = body->getLinearVelocity()*timeStep; - - float maxAabbx = maxAabb.getX(); - float maxAabby = maxAabb.getY(); - float maxAabbz = maxAabb.getZ(); - float minAabbx = minAabb.getX(); - float minAabby = minAabb.getY(); - float minAabbz = minAabb.getZ(); - - if (linMotion.x() > 0.f) - maxAabbx += linMotion.x(); - else - minAabbx += linMotion.x(); - if (linMotion.y() > 0.f) - maxAabby += linMotion.y(); - else - minAabby += linMotion.y(); - if (linMotion.z() > 0.f) - maxAabbz += linMotion.z(); - else - minAabbz += linMotion.z(); - - - minAabb = btVector3(minAabbx,minAabby,minAabbz); - maxAabb = btVector3(maxAabbx,maxAabby,maxAabbz); - } - - - } @@ -480,6 +426,13 @@ void CcdPhysicsEnvironment::removeCcdPhysicsController(CcdPhysicsController* ctr btRigidBody* body = ctrl->GetRigidBody(); if (body) { + for (int i=body->getNumConstraintRefs()-1;i>=0;i--) + { + btTypedConstraint* con = body->getConstraintRef(i); + m_dynamicsWorld->removeConstraint(con); + body->removeConstraintRef(con); + //delete con; //might be kept by python KX_ConstraintWrapper + } m_dynamicsWorld->removeRigidBody(ctrl->GetRigidBody()); } else { @@ -533,6 +486,12 @@ void CcdPhysicsEnvironment::enableCcdPhysicsController(CcdPhysicsController* ctr { btCollisionObject* obj = ctrl->GetCollisionObject(); obj->setUserPointer(ctrl); + // update the position of the object from the user + if (ctrl->GetMotionState()) + { + btTransform xform = CcdPhysicsController::GetTransformFromMotionState(ctrl->GetMotionState()); + ctrl->SetCenterOfMassTransform(xform); + } m_dynamicsWorld->addCollisionObject(obj, ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask()); } @@ -573,7 +532,7 @@ void CcdPhysicsEnvironment::refreshCcdPhysicsController(CcdPhysicsController* ct void CcdPhysicsEnvironment::addCcdGraphicController(CcdGraphicController* ctrl) { - if (m_cullingTree) + if (m_cullingTree && !ctrl->getBroadphaseHandle()) { btVector3 minAabb; btVector3 maxAabb; @@ -617,7 +576,7 @@ void CcdPhysicsEnvironment::debugDrawWorld() m_dynamicsWorld->debugDrawWorld(); } -bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep) +bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep,float interval) { std::set<CcdPhysicsController*>::iterator it; int i; @@ -627,14 +586,9 @@ bool CcdPhysicsEnvironment::proceedDeltaTime(double curTime,float timeStep) (*it)->SynchronizeMotionStates(timeStep); } - processFhSprings(curTime,timeStep); - float subStep = timeStep / float(m_numTimeSubSteps); - for (i=0;i<m_numTimeSubSteps;i++) - { -// m_dynamicsWorld->stepSimulation(subStep,20,1./240.);//perform always a full simulation step - m_dynamicsWorld->stepSimulation(subStep,0);//perform always a full simulation step - } + i = m_dynamicsWorld->stepSimulation(interval,25,subStep);//perform always a full simulation step + processFhSprings(curTime,i*subStep); for (it=m_controllers.begin(); it!=m_controllers.end(); it++) { @@ -686,9 +640,11 @@ public: }; -void CcdPhysicsEnvironment::processFhSprings(double curTime,float timeStep) +void CcdPhysicsEnvironment::processFhSprings(double curTime,float interval) { std::set<CcdPhysicsController*>::iterator it; + // dynamic of Fh spring is based on a timestep of 1/60 + int numIter = (int)(interval*60.0001f); for (it=m_controllers.begin(); it!=m_controllers.end(); it++) { @@ -700,8 +656,6 @@ void CcdPhysicsEnvironment::processFhSprings(double curTime,float timeStep) //printf("has Fh or RotFh\n"); //re-implement SM_FhObject.cpp using btCollisionWorld::rayTest and info from ctrl->getConstructionInfo() //send a ray from {0.0, 0.0, 0.0} towards {0.0, 0.0, -10.0}, in local coordinates - - CcdPhysicsController* parentCtrl = ctrl->getParentCtrl(); btRigidBody* parentBody = parentCtrl?parentCtrl->GetRigidBody() : 0; btRigidBody* cl_object = parentBody ? parentBody : body; @@ -748,82 +702,78 @@ void CcdPhysicsEnvironment::processFhSprings(double curTime,float timeStep) btVector3 normal = resultCallback.m_hitNormalWorld; normal.normalize(); - - if (ctrl->getConstructionInfo().m_do_fh) + for (int i=0; i<numIter; i++) { - btVector3 lspot = cl_object->getCenterOfMassPosition() - + rayDirLocal * resultCallback.m_closestHitFraction; + if (ctrl->getConstructionInfo().m_do_fh) + { + btVector3 lspot = cl_object->getCenterOfMassPosition() + + rayDirLocal * resultCallback.m_closestHitFraction; + + + lspot -= hit_object->getCenterOfMassPosition(); + btVector3 rel_vel = cl_object->getLinearVelocity() - hit_object->getVelocityInLocalPoint(lspot); + btScalar rel_vel_ray = ray_dir.dot(rel_vel); + btScalar spring_extent = 1.0 - distance / hitObjShapeProps.m_fh_distance; + + btScalar i_spring = spring_extent * hitObjShapeProps.m_fh_spring; + btScalar i_damp = rel_vel_ray * hitObjShapeProps.m_fh_damping; + + cl_object->setLinearVelocity(cl_object->getLinearVelocity() + (-(i_spring + i_damp) * ray_dir)); + if (hitObjShapeProps.m_fh_normal) + { + cl_object->setLinearVelocity(cl_object->getLinearVelocity()+(i_spring + i_damp) *(normal - normal.dot(ray_dir) * ray_dir)); + } + btVector3 lateral = rel_vel - rel_vel_ray * ray_dir; + + + if (ctrl->getConstructionInfo().m_do_anisotropic) { + //Bullet basis contains no scaling/shear etc. + const btMatrix3x3& lcs = cl_object->getCenterOfMassTransform().getBasis(); + btVector3 loc_lateral = lateral * lcs; + const btVector3& friction_scaling = cl_object->getAnisotropicFriction(); + loc_lateral *= friction_scaling; + lateral = lcs * loc_lateral; + } - lspot -= hit_object->getCenterOfMassPosition(); - btVector3 rel_vel = cl_object->getLinearVelocity() - hit_object->getVelocityInLocalPoint(lspot); - btScalar rel_vel_ray = ray_dir.dot(rel_vel); - btScalar spring_extent = 1.0 - distance / hitObjShapeProps.m_fh_distance; - - btScalar i_spring = spring_extent * hitObjShapeProps.m_fh_spring; - btScalar i_damp = rel_vel_ray * hitObjShapeProps.m_fh_damping; - - cl_object->setLinearVelocity(cl_object->getLinearVelocity() + (-(i_spring + i_damp) * ray_dir)); - if (hitObjShapeProps.m_fh_normal) - { - cl_object->setLinearVelocity(cl_object->getLinearVelocity()+(i_spring + i_damp) *(normal - normal.dot(ray_dir) * ray_dir)); - } - - btVector3 lateral = rel_vel - rel_vel_ray * ray_dir; - - - if (ctrl->getConstructionInfo().m_do_anisotropic) { - //Bullet basis contains no scaling/shear etc. - const btMatrix3x3& lcs = cl_object->getCenterOfMassTransform().getBasis(); - btVector3 loc_lateral = lateral * lcs; - const btVector3& friction_scaling = cl_object->getAnisotropicFriction(); - loc_lateral *= friction_scaling; - lateral = lcs * loc_lateral; + btScalar rel_vel_lateral = lateral.length(); + + if (rel_vel_lateral > SIMD_EPSILON) { + btScalar friction_factor = hit_object->getFriction();//cl_object->getFriction(); + + btScalar max_friction = friction_factor * btMax(btScalar(0.0), i_spring); + + btScalar rel_mom_lateral = rel_vel_lateral / cl_object->getInvMass(); + + btVector3 friction = (rel_mom_lateral > max_friction) ? + -lateral * (max_friction / rel_vel_lateral) : + -lateral; + + cl_object->applyCentralImpulse(friction); + } } - btScalar rel_vel_lateral = lateral.length(); - if (rel_vel_lateral > SIMD_EPSILON) { - btScalar friction_factor = hit_object->getFriction();//cl_object->getFriction(); + if (ctrl->getConstructionInfo().m_do_rot_fh) { + btVector3 up2 = cl_object->getWorldTransform().getBasis().getColumn(2); - btScalar max_friction = friction_factor * btMax(btScalar(0.0), i_spring); + btVector3 t_spring = up2.cross(normal) * hitObjShapeProps.m_fh_spring; + btVector3 ang_vel = cl_object->getAngularVelocity(); - btScalar rel_mom_lateral = rel_vel_lateral / cl_object->getInvMass(); + // only rotations that tilt relative to the normal are damped + ang_vel -= ang_vel.dot(normal) * normal; - btVector3 friction = (rel_mom_lateral > max_friction) ? - -lateral * (max_friction / rel_vel_lateral) : - -lateral; + btVector3 t_damp = ang_vel * hitObjShapeProps.m_fh_damping; - cl_object->applyCentralImpulse(friction); + cl_object->setAngularVelocity(cl_object->getAngularVelocity() + (t_spring - t_damp)); } } - - - if (ctrl->getConstructionInfo().m_do_rot_fh) { - btVector3 up2 = cl_object->getWorldTransform().getBasis().getColumn(2); - - btVector3 t_spring = up2.cross(normal) * hitObjShapeProps.m_fh_spring; - btVector3 ang_vel = cl_object->getAngularVelocity(); - - // only rotations that tilt relative to the normal are damped - ang_vel -= ang_vel.dot(normal) * normal; - - btVector3 t_damp = ang_vel * hitObjShapeProps.m_fh_damping; - - cl_object->setAngularVelocity(cl_object->getAngularVelocity() + (t_spring - t_damp)); - } - } - - } - - } } - } void CcdPhysicsEnvironment::setDebugMode(int debugMode) @@ -972,7 +922,7 @@ int CcdPhysicsEnvironment::createUniversalD6Constraint( bool useReferenceFrameA = true; - genericConstraint = new btGeneric6DofConstraint( + genericConstraint = new btGeneric6DofSpringConstraint( *rb0,*rb1, frameInA,frameInB,useReferenceFrameA); genericConstraint->setLinearLowerLimit(linearMinLimits); @@ -1053,7 +1003,7 @@ struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResul virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { - CcdPhysicsController* curHit = static_cast<CcdPhysicsController*>(rayResult.m_collisionObject->getUserPointer()); + //CcdPhysicsController* curHit = static_cast<CcdPhysicsController*>(rayResult.m_collisionObject->getUserPointer()); // save shape information as ClosestRayResultCallback::AddSingleResult() does not do it if (rayResult.m_localShapeInfo) { @@ -1071,10 +1021,6 @@ struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResul PHY_IPhysicsController* CcdPhysicsEnvironment::rayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ) { - - - float minFraction = 1.f; - btVector3 rayFrom(fromX,fromY,fromZ); btVector3 rayTo(toX,toY,toZ); @@ -1224,7 +1170,7 @@ struct OcclusionBuffer { m_initialized=false; m_occlusion = false; - m_buffer == NULL; + m_buffer = NULL; m_bufferSize = 0; } // multiplication of column major matrices: m=m1*m2 @@ -1332,8 +1278,7 @@ struct OcclusionBuffer static bool project(btVector4* p,int n) { for(int i=0;i<n;++i) - { - const btScalar iw=1/p[i][3]; + { p[i][2]=1/p[i][3]; p[i][0]*=p[i][2]; p[i][1]*=p[i][2]; @@ -1651,7 +1596,7 @@ struct OcclusionBuffer 6,5,1,2, 7,6,2,3, 5,4,0,1}; - for(int i=0;i<(sizeof(d)/sizeof(d[0]));) + for(unsigned int i=0;i<(sizeof(d)/sizeof(d[0]));) { const btVector4 p[]={ x[d[i++]], x[d[i++]], @@ -1841,6 +1786,45 @@ CcdPhysicsEnvironment::~CcdPhysicsEnvironment() } +float CcdPhysicsEnvironment::getConstraintParam(int constraintId,int param) +{ + btTypedConstraint* typedConstraint = getConstraintById(constraintId); + switch (typedConstraint->getUserConstraintType()) + { + case PHY_GENERIC_6DOF_CONSTRAINT: + { + + switch (param) + { + case 0: case 1: case 2: + { + //param = 0..2 are linear constraint values + btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; + genCons->calculateTransforms(); + return genCons->getRelativePivotPosition(param); + break; + } + case 3: case 4: case 5: + { + //param = 3..5 are relative constraint (Euler) angles + btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; + genCons->calculateTransforms(); + return genCons->getAngle(param-3); + break; + } + default: + { + } + } + break; + }; + default: + { + }; + }; + return 0.f; +} + void CcdPhysicsEnvironment::setConstraintParam(int constraintId,int param,float value0,float value1) { btTypedConstraint* typedConstraint = getConstraintById(constraintId); @@ -1848,9 +1832,63 @@ void CcdPhysicsEnvironment::setConstraintParam(int constraintId,int param,float { case PHY_GENERIC_6DOF_CONSTRAINT: { - //param = 1..12, min0,max0,min1,max1...min6,max6 - btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; - genCons->setLimit(param,value0,value1); + + switch (param) + { + case 0: case 1: case 2: case 3: case 4: case 5: + { + //param = 0..5 are constraint limits, with low/high limit value + btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; + genCons->setLimit(param,value0,value1); + break; + } + case 6: case 7: case 8: + { + //param = 6,7,8 are translational motors, with value0=target velocity, value1 = max motor force + btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; + int transMotorIndex = param-6; + btTranslationalLimitMotor* transMotor = genCons->getTranslationalLimitMotor(); + transMotor->m_targetVelocity[transMotorIndex]= value0; + transMotor->m_maxMotorForce[transMotorIndex]=value1; + transMotor->m_enableMotor[transMotorIndex] = (value1>0.f); + break; + } + case 9: case 10: case 11: + { + //param = 9,10,11 are rotational motors, with value0=target velocity, value1 = max motor force + btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; + int angMotorIndex = param-9; + btRotationalLimitMotor* rotMotor = genCons->getRotationalLimitMotor(angMotorIndex); + rotMotor->m_enableMotor = (value1 > 0.f); + rotMotor->m_targetVelocity = value0; + rotMotor->m_maxMotorForce = value1; + break; + } + + case 12: case 13: case 14: case 15: case 16: case 17: + { + //param 13-17 are for motorized springs on each of the degrees of freedom + btGeneric6DofSpringConstraint* genCons = (btGeneric6DofSpringConstraint*)typedConstraint; + int springIndex = param-12; + if (value0!=0.f) + { + bool springEnabled = true; + genCons->setStiffness(springIndex,value0); + genCons->setDamping(springIndex,value1); + genCons->enableSpring(springIndex,springEnabled); + genCons->setEquilibriumPoint(springIndex); + } else + { + bool springEnabled = false; + genCons->enableSpring(springIndex,springEnabled); + } + break; + } + + default: + { + } + } break; }; default: @@ -1887,29 +1925,20 @@ void CcdPhysicsEnvironment::addSensor(PHY_IPhysicsController* ctrl) // addCcdPhysicsController(ctrl1); //} enableCcdPhysicsController(ctrl1); - - //Collision filter/mask is now set at the time of the creation of the controller - //force collision detection with everything, including static objects (might hurt performance!) - //ctrl1->GetRigidBody()->getBroadphaseHandle()->m_collisionFilterMask = btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::SensorTrigger; - //ctrl1->GetRigidBody()->getBroadphaseHandle()->m_collisionFilterGroup = btBroadphaseProxy::SensorTrigger; - //todo: make this 'sensor'! - - requestCollisionCallback(ctrl); - //printf("addSensor\n"); } -void CcdPhysicsEnvironment::removeCollisionCallback(PHY_IPhysicsController* ctrl) +bool CcdPhysicsEnvironment::removeCollisionCallback(PHY_IPhysicsController* ctrl) { CcdPhysicsController* ccdCtrl = (CcdPhysicsController*)ctrl; - if (ccdCtrl->Unregister()) - m_triggerControllers.erase(ccdCtrl); + if (!ccdCtrl->Unregister()) + return false; + m_triggerControllers.erase(ccdCtrl); + return true; } void CcdPhysicsEnvironment::removeSensor(PHY_IPhysicsController* ctrl) { - removeCollisionCallback(ctrl); - disableCcdPhysicsController((CcdPhysicsController*)ctrl); } @@ -1945,19 +1974,18 @@ void CcdPhysicsEnvironment::addTouchCallback(int response_class, PHY_ResponseCal m_triggerCallbacksUserPtrs[response_class] = user; } -void CcdPhysicsEnvironment::requestCollisionCallback(PHY_IPhysicsController* ctrl) +bool CcdPhysicsEnvironment::requestCollisionCallback(PHY_IPhysicsController* ctrl) { CcdPhysicsController* ccdCtrl = static_cast<CcdPhysicsController*>(ctrl); - if (ccdCtrl->Register()) - m_triggerControllers.insert(ccdCtrl); + if (!ccdCtrl->Register()) + return false; + m_triggerControllers.insert(ccdCtrl); + return true; } void CcdPhysicsEnvironment::CallbackTriggers() { - - CcdPhysicsController* ctrl0=0,*ctrl1=0; - if (m_triggerCallbacks[PHY_OBJECT_RESPONSE] || (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints))) { //walk over all overlapping pairs, and if one of the involved bodies is registered for trigger callback, perform callback @@ -2099,12 +2127,13 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::CreateSphereController(float radi // declare this object as Dyamic rather then static!! // The reason as it is designed to detect all type of object, including static object // It would cause static-static message to be printed on the console otherwise - cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE/* | btCollisionObject::CF_KINEMATIC_OBJECT*/; + cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE | btCollisionObject::CF_STATIC_OBJECT; DefaultMotionState* motionState = new DefaultMotionState(); cinfo.m_MotionState = motionState; // we will add later the possibility to select the filter from option cinfo.m_collisionFilterMask = CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter; cinfo.m_collisionFilterGroup = CcdConstructionInfo::SensorFilter; + cinfo.m_bSensor = true; motionState->m_worldTransform.setIdentity(); motionState->m_worldTransform.setOrigin(btVector3(position[0],position[1],position[2])); @@ -2373,7 +2402,7 @@ int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl frameInB = inv * globalFrameA; bool useReferenceFrameA = true; - genericConstraint = new btGeneric6DofConstraint( + genericConstraint = new btGeneric6DofSpringConstraint( *rb0,*rb1, frameInA,frameInB,useReferenceFrameA); @@ -2397,7 +2426,7 @@ int CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl frameInB = rb0->getCenterOfMassTransform() * frameInA; bool useReferenceFrameA = true; - genericConstraint = new btGeneric6DofConstraint( + genericConstraint = new btGeneric6DofSpringConstraint( *rb0,s_fixedObject2, frameInA,frameInB,useReferenceFrameA); } @@ -2558,13 +2587,14 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::CreateConeController(float conera cinfo.m_collisionShape = new btConeShape(coneradius,coneheight); cinfo.m_MotionState = 0; cinfo.m_physicsEnv = this; - cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE; + cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE | btCollisionObject::CF_STATIC_OBJECT; DefaultMotionState* motionState = new DefaultMotionState(); cinfo.m_MotionState = motionState; // we will add later the possibility to select the filter from option cinfo.m_collisionFilterMask = CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter; cinfo.m_collisionFilterGroup = CcdConstructionInfo::SensorFilter; + cinfo.m_bSensor = true; motionState->m_worldTransform.setIdentity(); // motionState->m_worldTransform.setOrigin(btVector3(position[0],position[1],position[2])); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h index f861621ae37..bc5491e00cc 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h @@ -114,7 +114,7 @@ protected: virtual void beginFrame(); virtual void endFrame() {}; /// Perform an integration step of duration 'timeStep'. - virtual bool proceedDeltaTime(double curTime,float timeStep); + virtual bool proceedDeltaTime(double curTime,float timeStep,float interval); virtual void debugDrawWorld(); // virtual bool proceedDeltaTimeOneStep(float timeStep); @@ -149,7 +149,10 @@ protected: const btVector3& angularMaxLimits,int flags ); + virtual void setConstraintParam(int constraintId,int param,float value,float value1); + + virtual float getConstraintParam(int constraintId,int param); virtual void removeConstraint(int constraintid); @@ -179,8 +182,8 @@ protected: virtual void addSensor(PHY_IPhysicsController* ctrl); virtual void removeSensor(PHY_IPhysicsController* ctrl); virtual void addTouchCallback(int response_class, PHY_ResponseCallback callback, void *user); - virtual void requestCollisionCallback(PHY_IPhysicsController* ctrl); - virtual void removeCollisionCallback(PHY_IPhysicsController* ctrl); + virtual bool requestCollisionCallback(PHY_IPhysicsController* ctrl); + virtual bool removeCollisionCallback(PHY_IPhysicsController* ctrl); //These two methods are used *solely* to create controllers for Near/Radar sensor! Don't use for anything else virtual PHY_IPhysicsController* CreateSphereController(float radius,const PHY__Vector3& position); virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight); diff --git a/source/gameengine/Physics/Bullet/Makefile b/source/gameengine/Physics/Bullet/Makefile index 48e537bb6a3..19b17de275a 100644 --- a/source/gameengine/Physics/Bullet/Makefile +++ b/source/gameengine/Physics/Bullet/Makefile @@ -51,4 +51,6 @@ CPPFLAGS += -I../../Expressions CPPFLAGS += -I../../GameLogic CPPFLAGS += -I../../SceneGraph CPPFLAGS += -I../../../../source/blender/makesdna +CPPFLAGS += -I../../../../source/blender/blenkernel +CPPFLAGS += -I../../../../source/blender/blenlib diff --git a/source/gameengine/Physics/Bullet/SConscript b/source/gameengine/Physics/Bullet/SConscript index ab2c68ddfd5..ed53e8112cd 100644 --- a/source/gameengine/Physics/Bullet/SConscript +++ b/source/gameengine/Physics/Bullet/SConscript @@ -14,7 +14,10 @@ incs += ' #source/gameengine/Expressions' incs += ' #source/gameengine/GameLogic' incs += ' #source/gameengine/SceneGraph' incs += ' #source/blender/makesdna' +incs += ' #source/blender/blenkernel' +incs += ' #source/blender/blenlib' incs += ' #intern/SoundSystem' +incs += ' #intern/guardedalloc' incs += ' ' + env['BF_BULLET_INC'] incs += ' ' + env['BF_PYTHON_INC'] |