diff options
Diffstat (limited to 'source/gameengine/Physics')
11 files changed, 989 insertions, 624 deletions
diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt index fbaa7bb59ba..e52dc1ba052 100644 --- a/source/gameengine/Physics/Bullet/CMakeLists.txt +++ b/source/gameengine/Physics/Bullet/CMakeLists.txt @@ -40,6 +40,7 @@ set(INC ../../../blender/makesdna ../../../../intern/container ../../../../intern/guardedalloc + ../../../../intern/glew-mx ../../../../intern/string ) @@ -66,4 +67,6 @@ if(WITH_BULLET) add_definitions(-DWITH_BULLET) endif() +add_definitions(${GL_DEFINITIONS}) + blender_add_lib(ge_phys_bullet "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index 72c3b13e301..dbaa925db08 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -39,7 +39,6 @@ subject to the following restrictions: #include "LinearMath/btConvexHull.h" #include "BulletCollision/Gimpact/btGImpactShape.h" - #include "BulletSoftBody/btSoftRigidDynamicsWorld.h" #include "DNA_mesh_types.h" @@ -65,7 +64,6 @@ extern bool gDisableDeactivation; float gLinearSleepingTreshold; float gAngularSleepingTreshold; - BlenderBulletCharacterController::BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight) : btKinematicCharacterController(ghost,shape,stepHeight,2), m_motionState(motionState), @@ -118,6 +116,18 @@ const btVector3& BlenderBulletCharacterController::getWalkDirection() return m_walkDirection; } +bool CleanPairCallback::processOverlap(btBroadphasePair &pair) +{ + if ((pair.m_pProxy0 == m_cleanProxy) || (pair.m_pProxy1 == m_cleanProxy)) { + m_pairCache->cleanOverlappingPair(pair, m_dispatcher); + CcdPhysicsController *ctrl0 = (CcdPhysicsController*)(((btCollisionObject*)pair.m_pProxy0->m_clientObject)->getUserPointer()); + CcdPhysicsController *ctrl1 = (CcdPhysicsController*)(((btCollisionObject*)pair.m_pProxy1->m_clientObject)->getUserPointer()); + ctrl0->GetCollisionObject()->activate(false); + ctrl1->GetCollisionObject()->activate(false); + } + return false; +} + CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci) :m_cci(ci) { @@ -148,11 +158,34 @@ CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci) m_savedCollisionFilterGroup = 0; m_savedCollisionFilterMask = 0; m_savedMass = 0.0; + m_savedDyna = false; m_suspended = false; CreateRigidbody(); } +void CcdPhysicsController::addCcdConstraintRef(btTypedConstraint* c) +{ + int index = m_ccdConstraintRefs.findLinearSearch(c); + if (index == m_ccdConstraintRefs.size()) + m_ccdConstraintRefs.push_back(c); +} + +void CcdPhysicsController::removeCcdConstraintRef(btTypedConstraint* c) +{ + m_ccdConstraintRefs.remove(c); +} + +btTypedConstraint* CcdPhysicsController::getCcdConstraintRef(int index) +{ + return m_ccdConstraintRefs[index]; +} + +int CcdPhysicsController::getNumCcdConstraintRefs() const +{ + return m_ccdConstraintRefs.size(); +} + btTransform& CcdPhysicsController::GetTransformFromMotionState(PHY_IMotionState* motionState) { static btTransform trans; @@ -207,6 +240,11 @@ btRigidBody* CcdPhysicsController::GetRigidBody() { return btRigidBody::upcast(m_object); } +const btRigidBody* CcdPhysicsController::GetRigidBody() const +{ + return btRigidBody::upcast(m_object); +} + btCollisionObject* CcdPhysicsController::GetCollisionObject() { return m_object; @@ -560,20 +598,13 @@ void CcdPhysicsController::CreateRigidbody() static void DeleteBulletShape(btCollisionShape* shape, bool free) { - if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE) - { - // shapes based on meshes use an interface that contains the vertices. - btTriangleMeshShape* meshShape = static_cast<btTriangleMeshShape*>(shape); - btStridingMeshInterface* meshInterface = meshShape->getMeshInterface(); - if (meshInterface) - delete meshInterface; - } - else if (shape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE) - { - btGImpactMeshShape* meshShape = static_cast<btGImpactMeshShape*>(shape); - btStridingMeshInterface* meshInterface = meshShape->getMeshInterface(); - if (meshInterface) - delete meshInterface; + if (shape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) { + /* If we use Bullet scaled shape (btScaledBvhTriangleMeshShape) we have to + * free the child of the unscaled shape (btTriangleMeshShape) here. + */ + btTriangleMeshShape *meshShape = ((btScaledBvhTriangleMeshShape *)shape)->getChildShape(); + if (meshShape) + delete meshShape; } if (free) { delete shape; @@ -606,48 +637,41 @@ bool CcdPhysicsController::DeleteControllerShape( ) bool CcdPhysicsController::ReplaceControllerShape(btCollisionShape *newShape) { - - /* Note, deleting the previous collision shape must be done already */ - /* if (m_collisionShape) DeleteControllerShape(); */ + if (m_collisionShape) + DeleteControllerShape(); + + // If newShape is NULL it means to create a new Bullet shape. + if (!newShape) + newShape = m_shapeInfo->CreateBulletShape(m_cci.m_margin, m_cci.m_bGimpact, !m_cci.m_bSoft); m_object->setCollisionShape(newShape); - m_collisionShape= newShape; - m_cci.m_collisionShape= newShape; - - if (GetSoftBody()) { + m_collisionShape = newShape; + m_cci.m_collisionShape = newShape; + + btSoftBody *softBody = GetSoftBody(); + if (softBody) { + btSoftRigidDynamicsWorld *world = GetPhysicsEnvironment()->GetDynamicsWorld(); + // remove the old softBody + world->removeSoftBody(softBody); + // soft body must be recreated - m_cci.m_physicsEnv->RemoveCcdPhysicsController(this); delete m_object; m_object = NULL; // force complete reinitialization m_softbodyMappingDone = false; m_prototypeTransformInitialized = false; m_softBodyTransformInitialized = false; + CreateSoftbody(); assert(m_object); - // reinsert the new body - m_cci.m_physicsEnv->AddCcdPhysicsController(this); - } - - /* Copied from CcdPhysicsEnvironment::addCcdPhysicsController() */ - - /* without this, an object can rest on the old physics mesh - * and not move to account for the physics mesh, even with 'nosleep' */ - btSoftRigidDynamicsWorld* dw= GetPhysicsEnvironment()->GetDynamicsWorld(); - btCollisionObjectArray &obarr= dw->getCollisionObjectArray(); - btCollisionObject *ob; - btBroadphaseProxy* proxy; - - for (int i= 0; i < obarr.size(); i++) { - ob= obarr[i]; - if (ob->getCollisionShape() == newShape) { - proxy = ob->getBroadphaseHandle(); - - if (proxy) - dw->getPairCache()->cleanProxyFromPairs(proxy,dw->getDispatcher()); - } + + btSoftBody *newSoftBody = GetSoftBody(); + // set the user + newSoftBody->setUserPointer(this); + // add the new softbody + world->addSoftBody(newSoftBody); } - + return true; } @@ -673,6 +697,35 @@ CcdPhysicsController::~CcdPhysicsController() } } +void CcdPhysicsController::SimulationTick(float timestep) +{ + btRigidBody *body = GetRigidBody(); + if (!body || body->isStaticObject()) + return; + + // Clamp linear velocity + if (m_cci.m_clamp_vel_max > 0.0f || m_cci.m_clamp_vel_min > 0.0f) { + const btVector3 &linvel = body->getLinearVelocity(); + btScalar len = linvel.length(); + + if (m_cci.m_clamp_vel_max > 0.0f && len > m_cci.m_clamp_vel_max) + body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_max / len)); + else if (m_cci.m_clamp_vel_min > 0.0f && !btFuzzyZero(len) && len < m_cci.m_clamp_vel_min) + body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_min / len)); + } + + // Clamp angular velocity + if (m_cci.m_clamp_angvel_max > 0.0f || m_cci.m_clamp_angvel_min > 0.0f) { + const btVector3 &angvel = body->getAngularVelocity(); + btScalar len = angvel.length(); + + if (m_cci.m_clamp_angvel_max > 0.0f && len > m_cci.m_clamp_angvel_max) + body->setAngularVelocity(angvel * (m_cci.m_clamp_angvel_max / len)); + else if (m_cci.m_clamp_angvel_min > 0.0f && !btFuzzyZero(len) && len < m_cci.m_clamp_angvel_min) + body->setAngularVelocity(angvel * (m_cci.m_clamp_angvel_min / len)); + } +} + /** * SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') @@ -708,19 +761,6 @@ bool CcdPhysicsController::SynchronizeMotionStates(float time) if (body && !body->isStaticObject()) { - - if ((m_cci.m_clamp_vel_max>0.0) || (m_cci.m_clamp_vel_min>0.0)) - { - const btVector3& linvel = body->getLinearVelocity(); - float len= linvel.length(); - - if ((m_cci.m_clamp_vel_max>0.0) && (len > m_cci.m_clamp_vel_max)) - body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_max / len)); - - else if ((m_cci.m_clamp_vel_min>0.0) && btFuzzyZero(len)==0 && (len < m_cci.m_clamp_vel_min)) - body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_min / len)); - } - const btTransform& xform = body->getCenterOfMassTransform(); const btMatrix3x3& worldOri = xform.getBasis(); const btVector3& worldPos = xform.getOrigin(); @@ -780,6 +820,9 @@ void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionsta m_registerCount = 0; m_collisionShape = NULL; + // Clear all old constraints. + m_ccdConstraintRefs.clear(); + // always create a new shape to avoid scaling bug if (m_shapeInfo) { @@ -822,36 +865,6 @@ void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionsta m_cci.m_physicsEnv->AddCcdPhysicsController(this); -/* SM_Object* dynaparent=0; - SumoPhysicsController* sumoparentctrl = (SumoPhysicsController* )parentctrl; - - if (sumoparentctrl) - { - dynaparent = sumoparentctrl->GetSumoObject(); - } - - SM_Object* orgsumoobject = m_sumoObj; - - - m_sumoObj = new SM_Object( - orgsumoobject->getShapeHandle(), - orgsumoobject->getMaterialProps(), - orgsumoobject->getShapeProps(), - dynaparent); - - m_sumoObj->setRigidBody(orgsumoobject->isRigidBody()); - - m_sumoObj->setMargin(orgsumoobject->getMargin()); - m_sumoObj->setPosition(orgsumoobject->getPosition()); - m_sumoObj->setOrientation(orgsumoobject->getOrientation()); - //if it is a dyna, register for a callback - m_sumoObj->registerCallback(*this); - - m_sumoScene->add(* (m_sumoObj)); - */ - - - } void CcdPhysicsController::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env) @@ -899,12 +912,6 @@ void CcdPhysicsController::SetCenterOfMassTransform(btTransform& xform) { m_object->setInterpolationWorldTransform(xform); } - if (body) - { - body->setInterpolationLinearVelocity(body->getLinearVelocity()); - body->setInterpolationAngularVelocity(body->getAngularVelocity()); - body->updateInertiaTensor(); - } m_object->setWorldTransform(xform); } } @@ -1054,15 +1061,35 @@ void CcdPhysicsController::ResolveCombinedVelocities(float linvelX,float linvel { } +void CcdPhysicsController::RefreshCollisions() +{ + // the object is in an inactive layer so it's useless to update it and can cause problems + if (!GetPhysicsEnvironment()->IsActiveCcdPhysicsController(this)) + return; + + btSoftRigidDynamicsWorld *dw = GetPhysicsEnvironment()->GetDynamicsWorld(); + btBroadphaseProxy *proxy = m_object->getBroadphaseHandle(); + btDispatcher *dispatcher = dw->getDispatcher(); + btOverlappingPairCache *pairCache = dw->getPairCache(); + + CleanPairCallback cleanPairs(proxy, pairCache, dispatcher); + pairCache->processAllOverlappingPairs(&cleanPairs, dispatcher); + + // Forcibly recreate the physics object + btBroadphaseProxy* handle = m_object->getBroadphaseHandle(); + GetPhysicsEnvironment()->UpdateCcdPhysicsController(this, GetMass(), m_object->getCollisionFlags(), handle->m_collisionFilterGroup, handle->m_collisionFilterMask); +} + void CcdPhysicsController::SuspendDynamics(bool ghost) { btRigidBody *body = GetRigidBody(); - if (body && !m_suspended && !GetConstructionInfo().m_bSensor) + if (body && !m_suspended && !GetConstructionInfo().m_bSensor && GetPhysicsEnvironment()->IsActiveCcdPhysicsController(this)) { btBroadphaseProxy* handle = body->getBroadphaseHandle(); m_savedCollisionFlags = body->getCollisionFlags(); m_savedMass = GetMass(); + m_savedDyna = m_cci.m_bDyna; m_savedCollisionFilterGroup = handle->m_collisionFilterGroup; m_savedCollisionFilterMask = handle->m_collisionFilterMask; m_suspended = true; @@ -1071,13 +1098,14 @@ void CcdPhysicsController::SuspendDynamics(bool ghost) btCollisionObject::CF_STATIC_OBJECT|((ghost)?btCollisionObject::CF_NO_CONTACT_RESPONSE:(m_savedCollisionFlags&btCollisionObject::CF_NO_CONTACT_RESPONSE)), btBroadphaseProxy::StaticFilter, btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter); + m_cci.m_bDyna = false; } } void CcdPhysicsController::RestoreDynamics() { btRigidBody *body = GetRigidBody(); - if (body && m_suspended) + if (body && m_suspended && GetPhysicsEnvironment()->IsActiveCcdPhysicsController(this)) { // before make sure any position change that was done in this logic frame are accounted for SetTransform(); @@ -1087,6 +1115,7 @@ void CcdPhysicsController::RestoreDynamics() m_savedCollisionFilterGroup, m_savedCollisionFilterMask); body->activate(); + m_cci.m_bDyna = m_savedDyna; m_suspended = false; } } @@ -1354,6 +1383,42 @@ void CcdPhysicsController::Jump() void CcdPhysicsController::SetActive(bool active) { } + +float CcdPhysicsController::GetLinearDamping() const +{ + const btRigidBody* body = GetRigidBody(); + if (body) + return body->getLinearDamping(); + return 0; +} + +float CcdPhysicsController::GetAngularDamping() const +{ + const btRigidBody* body = GetRigidBody(); + if (body) + return body->getAngularDamping(); + return 0; +} + +void CcdPhysicsController::SetLinearDamping(float damping) +{ + SetDamping(damping, GetAngularDamping()); +} + +void CcdPhysicsController::SetAngularDamping(float damping) +{ + SetDamping(GetLinearDamping(), damping); +} + +void CcdPhysicsController::SetDamping(float linear, float angular) +{ + btRigidBody* body = GetRigidBody(); + if (!body) return; + + body->setDamping(linear, angular); +} + + // reading out information from physics MT_Vector3 CcdPhysicsController::GetLinearVelocity() { @@ -1479,8 +1544,7 @@ void CcdPhysicsController::AddCompoundChild(PHY_IPhysicsController* child) const btCollisionShape* childShape = childBody->getCollisionShape(); if (!rootShape || !childShape || - rootShape->getShapeType() != COMPOUND_SHAPE_PROXYTYPE || - childShape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) + rootShape->getShapeType() != COMPOUND_SHAPE_PROXYTYPE) return; btCompoundShape* compoundShape = (btCompoundShape*)rootShape; // compute relative transformation between parent and child @@ -1530,7 +1594,7 @@ void CcdPhysicsController::AddCompoundChild(PHY_IPhysicsController* child) // must update the broadphase cache, GetPhysicsEnvironment()->RefreshCcdPhysicsController(this); // remove the children - GetPhysicsEnvironment()->DisableCcdPhysicsController(childCtrl); + GetPhysicsEnvironment()->RemoveCcdPhysicsController(childCtrl); } /* Reverse function of the above, it will remove a shape from a compound shape @@ -1586,7 +1650,7 @@ void CcdPhysicsController::RemoveCompoundChild(PHY_IPhysicsController* child) // must update the broadphase cache, GetPhysicsEnvironment()->RefreshCcdPhysicsController(this); // reactivate the children - GetPhysicsEnvironment()->EnableCcdPhysicsController(childCtrl); + GetPhysicsEnvironment()->AddCcdPhysicsController(childCtrl); } PHY_IPhysicsController* CcdPhysicsController::GetReplica() @@ -1646,33 +1710,50 @@ PHY_IPhysicsController* CcdPhysicsController::GetReplicaForSensors() * 2) from_gameobj - creates the phys mesh from the DerivedMesh where possible, else the RAS_MeshObject * 3) this - update the phys mesh from DerivedMesh or RAS_MeshObject * - * Most of the logic behind this is in shapeInfo->UpdateMesh(...) + * Most of the logic behind this is in m_shapeInfo->UpdateMesh(...) */ bool CcdPhysicsController::ReinstancePhysicsShape(KX_GameObject *from_gameobj, RAS_MeshObject *from_meshobj) { - CcdShapeConstructionInfo *shapeInfo; - - shapeInfo = this->GetShapeInfo(); - - if (shapeInfo->m_shapeType != PHY_SHAPE_MESH/* || spc->GetSoftBody()*/) + if (m_shapeInfo->m_shapeType != PHY_SHAPE_MESH) return false; - this->DeleteControllerShape(); - - if (from_gameobj==NULL && from_meshobj==NULL) - from_gameobj = KX_GameObject::GetClientObject((KX_ClientObjectInfo*)this->GetNewClientInfo()); + if (!from_gameobj && !from_meshobj) + from_gameobj = KX_GameObject::GetClientObject((KX_ClientObjectInfo*)GetNewClientInfo()); /* updates the arrays used for making the new bullet mesh */ - shapeInfo->UpdateMesh(from_gameobj, from_meshobj); + m_shapeInfo->UpdateMesh(from_gameobj, from_meshobj); /* create the new bullet mesh */ - CcdConstructionInfo& cci = this->GetConstructionInfo(); - btCollisionShape* bm= shapeInfo->CreateBulletShape(cci.m_margin, cci.m_bGimpact, !cci.m_bSoft); + GetPhysicsEnvironment()->UpdateCcdPhysicsControllerShape(m_shapeInfo); - this->ReplaceControllerShape(bm); return true; } +void CcdPhysicsController::ReplicateConstraints(KX_GameObject *replica, std::vector<KX_GameObject*> constobj) +{ + if (replica->GetConstraints().size() == 0 || !replica->GetPhysicsController()) + return; + + PHY_IPhysicsEnvironment *physEnv = GetPhysicsEnvironment(); + + vector<bRigidBodyJointConstraint*> constraints = replica->GetConstraints(); + vector<bRigidBodyJointConstraint*>::iterator consit; + + /* Object could have some constraints, iterate over all of theme to ensure that every constraint is recreated. */ + for (consit = constraints.begin(); consit != constraints.end(); ++consit) { + /* Try to find the constraint targets in the list of group objects. */ + bRigidBodyJointConstraint *dat = (*consit); + vector<KX_GameObject*>::iterator memit; + for (memit = constobj.begin(); memit != constobj.end(); ++memit) { + KX_GameObject *member = (*memit); + /* If the group member is the actual target for the constraint. */ + if (dat->tar->id.name + 2 == member->GetName() && member->GetPhysicsController()) + physEnv->SetupObjectConstraints(replica, member, dat); + } + } + +} + /////////////////////////////////////////////////////////// ///A small utility class, DefaultMotionState /// @@ -1754,7 +1835,7 @@ CcdShapeConstructionInfo* CcdShapeConstructionInfo::FindMesh(RAS_MeshObject* mes return NULL; } -bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, bool polytope) +bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject *meshobj, DerivedMesh *dm, bool polytope) { int numpolys, numverts; @@ -1766,7 +1847,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, bool free_dm = false; // No mesh object or mesh has no polys - if (!meshobj || meshobj->HasColliderPolygon()==false) { + if (!meshobj || !meshobj->HasColliderPolygon()) { m_vertexArray.clear(); m_polygonIndexArray.clear(); m_triFaceArray.clear(); @@ -1789,80 +1870,83 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, /* double lookup */ const int *index_mf_to_mpoly = (const int *)dm->getTessFaceDataArray(dm, CD_ORIGINDEX); const int *index_mp_to_orig = (const int *)dm->getPolyDataArray(dm, CD_ORIGINDEX); - if (index_mf_to_mpoly == NULL) { + if (!index_mf_to_mpoly) { index_mp_to_orig = NULL; } 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(numverts, false); - unsigned int tot_bt_verts= 0; + std::vector<bool> vert_tag_array(numverts, false); + unsigned int tot_bt_verts = 0; - if (polytope) - { + if (polytope) { // Tag verts we're using - for (int p2=0; p2<numpolys; p2++) - { - MFace* mf = &mface[p2]; + for (int p2 = 0; p2 < numpolys; p2++) { + MFace *mf = &mface[p2]; const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2; - RAS_Polygon* poly = meshobj->GetPolygon(origi); + RAS_Polygon *poly = meshobj->GetPolygon(origi); // only add polygons that have the collision flag set - if (poly->IsCollider()) - { - 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++;} + if (poly->IsCollider()) { + if (!vert_tag_array[mf->v1]) { + vert_tag_array[mf->v1] = true; + tot_bt_verts++; + } + if (!vert_tag_array[mf->v2]) { + vert_tag_array[mf->v2] = true; + tot_bt_verts++; + } + if (!vert_tag_array[mf->v3]) { + vert_tag_array[mf->v3] = true; + tot_bt_verts++; + } + if (mf->v4 && !vert_tag_array[mf->v4]) { + vert_tag_array[mf->v4] = true; + tot_bt_verts++; + } } } - + /* Can happen with ngons */ if (!tot_bt_verts) { goto cleanup_empty_mesh; } - m_vertexArray.resize(tot_bt_verts*3); + m_vertexArray.resize(tot_bt_verts * 3); - btScalar *bt= &m_vertexArray[0]; + btScalar *bt = &m_vertexArray[0]; - for (int p2=0; p2<numpolys; p2++) - { - MFace* mf = &mface[p2]; + for (int p2 = 0; p2 < numpolys; p2++) { + MFace *mf = &mface[p2]; const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2; - RAS_Polygon* poly= meshobj->GetPolygon(origi); + RAS_Polygon *poly = meshobj->GetPolygon(origi); // only add polygons that have the collisionflag set - if (poly->IsCollider()) - { - if (vert_tag_array[mf->v1]==true) - { - const float* vtx = mvert[mf->v1].co; + if (poly->IsCollider()) { + if (vert_tag_array[mf->v1]) { + 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; + if (vert_tag_array[mf->v2]) { + 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; + if (vert_tag_array[mf->v3]) { + 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; + if (mf->v4 && vert_tag_array[mf->v4]) { + const float *vtx = mvert[mf->v4].co; vert_tag_array[mf->v4] = false; *bt++ = vtx[0]; *bt++ = vtx[1]; @@ -1872,28 +1956,38 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, } } else { - unsigned int tot_bt_tris= 0; - vector<int> vert_remap_array(numverts, 0); - + unsigned int tot_bt_tris = 0; + std::vector<int> vert_remap_array(numverts, 0); + // Tag verts we're using - for (int p2=0; p2<numpolys; p2++) - { - MFace* mf = &mface[p2]; + for (int p2 = 0; p2 < numpolys; p2++) { + MFace *mf = &mface[p2]; const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2; - RAS_Polygon* poly= meshobj->GetPolygon(origi); + RAS_Polygon *poly = meshobj->GetPolygon(origi); // only add polygons that have the collision flag set - if (poly->IsCollider()) - { - 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 */ + if (poly->IsCollider()) { + if (!vert_tag_array[mf->v1]) { + vert_tag_array[mf->v1] = true; + vert_remap_array[mf->v1] = tot_bt_verts; + tot_bt_verts++; + } + if (!vert_tag_array[mf->v2]) { + vert_tag_array[mf->v2] = true; + vert_remap_array[mf->v2] = tot_bt_verts; + tot_bt_verts++; + } + if (!vert_tag_array[mf->v3]) { + 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]) { + 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 */ } } @@ -1902,43 +1996,39 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, goto cleanup_empty_mesh; } - m_vertexArray.resize(tot_bt_verts*3); + m_vertexArray.resize(tot_bt_verts * 3); m_polygonIndexArray.resize(tot_bt_tris); - m_triFaceArray.resize(tot_bt_tris*3); - btScalar *bt= &m_vertexArray[0]; - int *poly_index_pt= &m_polygonIndexArray[0]; - int *tri_pt= &m_triFaceArray[0]; + m_triFaceArray.resize(tot_bt_tris * 3); + btScalar *bt = &m_vertexArray[0]; + int *poly_index_pt = &m_polygonIndexArray[0]; + int *tri_pt = &m_triFaceArray[0]; UVco *uv_pt = NULL; - if (tface) - { - m_triFaceUVcoArray.resize(tot_bt_tris*3); + if (tface) { + m_triFaceUVcoArray.resize(tot_bt_tris * 3); uv_pt = &m_triFaceUVcoArray[0]; - } - else + } + else m_triFaceUVcoArray.clear(); - for (int p2=0; p2<numpolys; p2++) - { - MFace* mf = &mface[p2]; - MTFace* tf = (tface) ? &tface[p2] : NULL; + for (int p2 = 0; p2 < numpolys; p2++) { + MFace *mf = &mface[p2]; + MTFace *tf = (tface) ? &tface[p2] : NULL; const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2; - RAS_Polygon* poly= meshobj->GetPolygon(origi); + RAS_Polygon *poly = meshobj->GetPolygon(origi); // only add polygons that have the collisionflag set - if (poly->IsCollider()) - { - MVert *v1= &mvert[mf->v1]; - MVert *v2= &mvert[mf->v2]; - MVert *v3= &mvert[mf->v3]; + if (poly->IsCollider()) { + MVert *v1 = &mvert[mf->v1]; + MVert *v2 = &mvert[mf->v2]; + MVert *v3 = &mvert[mf->v3]; // the face indices 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; - if (tf) - { + tri_pt = tri_pt + 3; + if (tf) { uv_pt[0].uv[0] = tf->uv[0][0]; uv_pt[0].uv[1] = tf->uv[0][1]; uv_pt[1].uv[0] = tf->uv[1][0]; @@ -1953,19 +2043,19 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, poly_index_pt++; // the vertex location - if (vert_tag_array[mf->v1]==true) { /* *** v1 *** */ + if (vert_tag_array[mf->v1]) { /* *** v1 *** */ vert_tag_array[mf->v1] = false; *bt++ = v1->co[0]; *bt++ = v1->co[1]; *bt++ = v1->co[2]; } - if (vert_tag_array[mf->v2]==true) { /* *** v2 *** */ + if (vert_tag_array[mf->v2]) { /* *** v2 *** */ vert_tag_array[mf->v2] = false; *bt++ = v2->co[0]; *bt++ = v2->co[1]; *bt++ = v2->co[2]; } - if (vert_tag_array[mf->v3]==true) { /* *** v3 *** */ + if (vert_tag_array[mf->v3]) { /* *** v3 *** */ vert_tag_array[mf->v3] = false; *bt++ = v3->co[0]; *bt++ = v3->co[1]; @@ -1974,12 +2064,12 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, if (mf->v4) { - MVert *v4= &mvert[mf->v4]; + MVert *v4 = &mvert[mf->v4]; 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; + tri_pt = tri_pt + 3; if (tf) { uv_pt[0].uv[0] = tf->uv[0][0]; @@ -1996,7 +2086,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, poly_index_pt++; // the vertex location - if (vert_tag_array[mf->v4] == true) { /* *** v4 *** */ + if (vert_tag_array[mf->v4]) { /* *** v4 *** */ vert_tag_array[mf->v4] = false; *bt++ = v4->co[0]; *bt++ = v4->co[1]; @@ -2010,27 +2100,27 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, /* If this ever gets confusing, print out an OBJ file for debugging */ #if 0 printf("# vert count %d\n", m_vertexArray.size()); - for (i=0; i<m_vertexArray.size(); i+=1) { + for (i = 0; i < m_vertexArray.size(); i += 1) { printf("v %.6f %.6f %.6f\n", m_vertexArray[i].x(), m_vertexArray[i].y(), m_vertexArray[i].z()); } printf("# face count %d\n", m_triFaceArray.size()); - for (i=0; i<m_triFaceArray.size(); i+=3) { - printf("f %d %d %d\n", m_triFaceArray[i]+1, m_triFaceArray[i+1]+1, m_triFaceArray[i+2]+1); + for (i = 0; i < m_triFaceArray.size(); i += 3) { + printf("f %d %d %d\n", m_triFaceArray[i] + 1, m_triFaceArray[i + 1] + 1, m_triFaceArray[i + 2] + 1); } #endif } #if 0 - if (validpolys==false) + if (validpolys == false) { // should not happen m_shapeType = PHY_SHAPE_NONE; return false; } #endif - + m_meshObject = meshobj; if (free_dm) { dm->release(dm); @@ -2038,10 +2128,9 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm, } // sharing only on static mesh at present, if you change that, you must also change in FindMesh - if (!polytope && !dm) - { + if (!polytope && !dm) { // triangle shape can be shared, store the mesh object in the map - m_meshShapeMap.insert(std::pair<RAS_MeshObject*,CcdShapeConstructionInfo*>(meshobj,this)); + m_meshShapeMap.insert(std::pair<RAS_MeshObject *, CcdShapeConstructionInfo *>(meshobj, this)); } return true; @@ -2064,51 +2153,50 @@ cleanup_empty_mesh: /* Updates the arrays used by CreateBulletShape(), * take care that recalcLocalAabb() runs after CreateBulletShape is called. * */ -bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RAS_MeshObject* meshobj) +bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject *gameobj, class RAS_MeshObject *meshobj) { int numpolys; int numverts; - unsigned int tot_bt_tris= 0; - unsigned int tot_bt_verts= 0; + unsigned int tot_bt_tris = 0; + unsigned int tot_bt_verts = 0; int i, j; int v_orig; /* Use for looping over verts in a face as a try or 2 tris */ - const int quad_verts[7]= {0,1,2, 0,2,3, -1}; - const int tri_verts[4]= {0,1,2, -1}; + const int quad_verts[7] = {0, 1, 2, 0, 2, 3, -1}; + const int tri_verts[4] = {0, 1, 2, -1}; const int *fv_pt; - if (gameobj==NULL && meshobj==NULL) + if (!gameobj && !meshobj) return false; - + if (m_shapeType != PHY_SHAPE_MESH) return false; - RAS_Deformer *deformer= gameobj ? gameobj->GetDeformer():NULL; - DerivedMesh* dm = NULL; + RAS_Deformer *deformer = gameobj ? gameobj->GetDeformer() : NULL; + DerivedMesh *dm = NULL; if (deformer) dm = deformer->GetPhysicsMesh(); - + /* get the mesh from the object if not defined */ - if (meshobj==NULL) { - + if (!meshobj) { /* modifier mesh */ if (dm) - meshobj= deformer->GetRasMesh(); - + meshobj = deformer->GetRasMesh(); + /* game object first mesh */ - if (meshobj==NULL) { + if (!meshobj) { if (gameobj->GetMeshCount() > 0) { - meshobj= gameobj->GetMesh(0); + meshobj = gameobj->GetMesh(0); } } } - - if (dm && deformer->GetRasMesh() == meshobj) - { /* + + if (dm && deformer->GetRasMesh() == meshobj) { + /* * Derived Mesh Update * * */ @@ -2120,41 +2208,38 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA /* double lookup */ const int *index_mf_to_mpoly = (const int *)dm->getTessFaceDataArray(dm, CD_ORIGINDEX); - const int *index_mp_to_orig = (const int *)dm->getPolyDataArray(dm, CD_ORIGINDEX); - if (index_mf_to_mpoly == NULL) { + const int *index_mp_to_orig = (const int *)dm->getPolyDataArray(dm, CD_ORIGINDEX); + if (!index_mf_to_mpoly) { index_mp_to_orig = NULL; } MFace *mf; MVert *mv; - int flen; - - if (CustomData_has_layer(&dm->faceData, CD_MTFACE)) - { + if (CustomData_has_layer(&dm->faceData, CD_MTFACE)) { MTFace *tface = (MTFace *)dm->getTessFaceDataArray(dm, CD_MTFACE); MTFace *tf; - vector<bool> vert_tag_array(numverts, false); - vector<int> vert_remap_array(numverts, 0); + std::vector<bool> vert_tag_array(numverts, false); + std::vector<int> vert_remap_array(numverts, 0); + + for (mf = mface, tf = tface, i = 0; i < numpolys; mf++, tf++, i++) { + if (tf->mode & TF_DYNAMIC) { + int flen; - for (mf= mface, tf= tface, i=0; i < numpolys; mf++, tf++, i++) { - if (tf->mode & TF_DYNAMIC) - { if (mf->v4) { - tot_bt_tris+= 2; - flen= 4; - } else { + tot_bt_tris += 2; + flen = 4; + } + else { tot_bt_tris++; - flen= 3; + flen = 3; } - for (j=0; j<flen; j++) - { + for (j = 0; j < flen; j++) { v_orig = (*(&mf->v1 + j)); - if (vert_tag_array[v_orig]==false) - { + if (!vert_tag_array[v_orig]) { vert_tag_array[v_orig] = true; vert_remap_array[v_orig] = tot_bt_verts; tot_bt_verts++; @@ -2163,42 +2248,38 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA } } - m_vertexArray.resize(tot_bt_verts*3); - btScalar *bt= &m_vertexArray[0]; + m_vertexArray.resize(tot_bt_verts * 3); + btScalar *bt = &m_vertexArray[0]; - m_triFaceArray.resize(tot_bt_tris*3); - int *tri_pt= &m_triFaceArray[0]; + m_triFaceArray.resize(tot_bt_tris * 3); + int *tri_pt = &m_triFaceArray[0]; - m_triFaceUVcoArray.resize(tot_bt_tris*3); - UVco *uv_pt= &m_triFaceUVcoArray[0]; + m_triFaceUVcoArray.resize(tot_bt_tris * 3); + UVco *uv_pt = &m_triFaceUVcoArray[0]; m_polygonIndexArray.resize(tot_bt_tris); - int *poly_index_pt= &m_polygonIndexArray[0]; + int *poly_index_pt = &m_polygonIndexArray[0]; - for (mf= mface, tf= tface, i=0; i < numpolys; mf++, tf++, i++) - { - if (tf->mode & TF_DYNAMIC) - { + for (mf = mface, tf = tface, i = 0; i < numpolys; mf++, tf++, i++) { + if (tf->mode & TF_DYNAMIC) { int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, i) : i; if (mf->v4) { - fv_pt= quad_verts; + fv_pt = quad_verts; *poly_index_pt++ = origi; *poly_index_pt++ = origi; - flen= 4; - } else { - fv_pt= tri_verts; + } + else { + fv_pt = tri_verts; *poly_index_pt++ = origi; - flen= 3; } - for (; *fv_pt > -1; fv_pt++) - { + for (; *fv_pt > -1; fv_pt++) { v_orig = (*(&mf->v1 + (*fv_pt))); if (vert_tag_array[v_orig]) { - mv= mvert + v_orig; + mv = mvert + v_orig; *bt++ = mv->co[0]; *bt++ = mv->co[1]; *bt++ = mv->co[2]; @@ -2216,37 +2297,37 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA else { /* no need for a vertex mapping. simple/fast */ - tot_bt_verts= numverts; + tot_bt_verts = numverts; - for (mf= mface, i=0; i < numpolys; mf++, i++) { - tot_bt_tris += (mf->v4 ? 2:1); + for (mf = mface, i = 0; i < numpolys; mf++, i++) { + tot_bt_tris += (mf->v4 ? 2 : 1); } - m_vertexArray.resize(tot_bt_verts*3); - btScalar *bt= &m_vertexArray[0]; + m_vertexArray.resize(tot_bt_verts * 3); + btScalar *bt = &m_vertexArray[0]; - m_triFaceArray.resize(tot_bt_tris*3); - int *tri_pt= &m_triFaceArray[0]; + m_triFaceArray.resize(tot_bt_tris * 3); + int *tri_pt = &m_triFaceArray[0]; m_polygonIndexArray.resize(tot_bt_tris); - int *poly_index_pt= &m_polygonIndexArray[0]; + int *poly_index_pt = &m_polygonIndexArray[0]; m_triFaceUVcoArray.clear(); - for (mv= mvert, i=0; i < numverts; mv++, i++) { + for (mv = mvert, i = 0; i < numverts; mv++, i++) { *bt++ = mv->co[0]; *bt++ = mv->co[1]; *bt++ = mv->co[2]; } - for (mf= mface, i=0; i < numpolys; mf++, i++) { + for (mf = mface, i = 0; i < numpolys; mf++, i++) { int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, i) : i; if (mf->v4) { - fv_pt= quad_verts; + fv_pt = quad_verts; *poly_index_pt++ = origi; *poly_index_pt++ = origi; } else { - fv_pt= tri_verts; + fv_pt = tri_verts; *poly_index_pt++ = origi; } @@ -2255,51 +2336,46 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA } } } - else { /* - * RAS Mesh Update - * - * */ - + else { /* + * RAS Mesh Update + * + * */ /* Note!, gameobj can be NULL here */ /* transverts are only used for deformed RAS_Meshes, the RAS_TexVert data * is too hard to get at, see below for details */ - float (*transverts)[3] = NULL; - int transverts_tot= 0; /* with deformed meshes - should always be greater then the max orginal index, or we get crashes */ + float(*transverts)[3] = NULL; + int transverts_tot = 0; /* with deformed meshes - should always be greater than the max orginal index, or we get crashes */ if (deformer) { /* map locations from the deformed array * * Could call deformer->Update(); but rely on redraw updating. * */ - transverts= deformer->GetTransVerts(&transverts_tot); + transverts = deformer->GetTransVerts(&transverts_tot); } // Tag verts we're using - numpolys= meshobj->NumPolygons(); - numverts= meshobj->m_sharedvertex_map.size(); + numpolys = meshobj->NumPolygons(); + numverts = meshobj->m_sharedvertex_map.size(); const float *xyz; - vector<bool> vert_tag_array(numverts, false); - vector<int> vert_remap_array(numverts, 0); + std::vector<bool> vert_tag_array(numverts, false); + std::vector<int> vert_remap_array(numverts, 0); - for (int p=0; p<numpolys; p++) - { - RAS_Polygon* poly= meshobj->GetPolygon(p); - if (poly->IsCollider()) - { - for (i=0; i < poly->VertexCount(); i++) - { - v_orig= poly->GetVertex(i)->getOrigIndex(); - if (vert_tag_array[v_orig]==false) - { + for (int p = 0; p < numpolys; p++) { + RAS_Polygon *poly = meshobj->GetPolygon(p); + if (poly->IsCollider()) { + for (i = 0; i < poly->VertexCount(); i++) { + v_orig = poly->GetVertex(i)->getOrigIndex(); + if (!vert_tag_array[v_orig]) { vert_tag_array[v_orig] = true; vert_remap_array[v_orig] = tot_bt_verts; tot_bt_verts++; } } - tot_bt_tris += (poly->VertexCount()==4 ? 2:1); + tot_bt_tris += (poly->VertexCount() == 4 ? 2 : 1); } } @@ -2307,32 +2383,29 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA if (tot_bt_tris == 0 || tot_bt_verts == 0) return false; - m_vertexArray.resize(tot_bt_verts*3); - btScalar *bt= &m_vertexArray[0]; + m_vertexArray.resize(tot_bt_verts * 3); + btScalar *bt = &m_vertexArray[0]; - m_triFaceArray.resize(tot_bt_tris*3); - int *tri_pt= &m_triFaceArray[0]; + m_triFaceArray.resize(tot_bt_tris * 3); + int *tri_pt = &m_triFaceArray[0]; /* cant be used for anything useful in this case, since we don't rely on the original mesh * will just be an array like pythons range(tot_bt_tris) */ m_polygonIndexArray.resize(tot_bt_tris); - for (int p=0; p<numpolys; p++) - { - RAS_Polygon* poly= meshobj->GetPolygon(p); + int p = 0; + int t = 0; + while (t < tot_bt_tris) { + RAS_Polygon *poly = meshobj->GetPolygon(p); - if (poly->IsCollider()) - { + if (poly->IsCollider()) { /* quad or tri loop */ - fv_pt= (poly->VertexCount()==3 ? tri_verts:quad_verts); - - for (; *fv_pt > -1; fv_pt++) - { - v_orig= poly->GetVertex(*fv_pt)->getOrigIndex(); + fv_pt = (poly->VertexCount() == 3 ? tri_verts : quad_verts); - if (vert_tag_array[v_orig]) - { + for (; *fv_pt > -1; fv_pt++) { + v_orig = poly->GetVertex(*fv_pt)->getOrigIndex(); + if (vert_tag_array[v_orig]) { if (transverts) { /* deformed mesh, using RAS_TexVert locations would be too troublesome * because they are use the gameob as a hash in the material slot */ @@ -2342,55 +2415,60 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA } else { /* static mesh python may have modified */ - xyz= meshobj->GetVertexLocation( v_orig ); + xyz = meshobj->GetVertexLocation(v_orig); *bt++ = xyz[0]; *bt++ = xyz[1]; *bt++ = xyz[2]; } - vert_tag_array[v_orig] = false; } - *tri_pt++ = vert_remap_array[v_orig]; } } - - m_polygonIndexArray[p] = p; /* dumb counting */ + // first triangle + m_polygonIndexArray[t] = p; + + // if the poly is a quad we transform it in two triangles + if (poly->VertexCount() == 4) { + t++; + // second triangle + m_polygonIndexArray[t] = p; + } + t++; + p++; } } - + #if 0 /* needs #include <cstdio> */ printf("# vert count %d\n", m_vertexArray.size()); - for (int i=0; i<m_vertexArray.size(); i+=3) { - printf("v %.6f %.6f %.6f\n", m_vertexArray[i], m_vertexArray[i+1], m_vertexArray[i+2]); + for (int i = 0; i < m_vertexArray.size(); i += 3) { + printf("v %.6f %.6f %.6f\n", m_vertexArray[i], m_vertexArray[i + 1], m_vertexArray[i + 2]); } printf("# face count %d\n", m_triFaceArray.size()); - for (int i=0; i<m_triFaceArray.size(); i+=3) { - printf("f %d %d %d\n", m_triFaceArray[i]+1, m_triFaceArray[i+1]+1, m_triFaceArray[i+2]+1); + for (int i = 0; i < m_triFaceArray.size(); i += 3) { + printf("f %d %d %d\n", m_triFaceArray[i] + 1, m_triFaceArray[i + 1] + 1, m_triFaceArray[i + 2] + 1); } #endif - /* force recreation of the m_unscaledShape. + /* force recreation of the m_triangleIndexVertexArray. * If this has multiple users we cant delete */ - if (m_unscaledShape) { - // don't free now so it can re-allocate under the same location and not break pointers. - // DeleteBulletShape(m_unscaledShape); - m_forceReInstance= true; + if (m_triangleIndexVertexArray) { + m_forceReInstance = true; } // Make sure to also replace the mesh in the shape map! Otherwise we leave dangling references when we free. // Note, this whole business could cause issues with shared meshes. If we update one mesh, do we replace // them all? - std::map<RAS_MeshObject*,CcdShapeConstructionInfo*>::iterator mit = m_meshShapeMap.find(m_meshObject); + std::map<RAS_MeshObject *, CcdShapeConstructionInfo *>::iterator mit = m_meshShapeMap.find(m_meshObject); if (mit != m_meshShapeMap.end()) { m_meshShapeMap.erase(mit); m_meshShapeMap[meshobj] = this; } - m_meshObject= meshobj; - + m_meshObject = meshobj; + if (dm) { dm->needsFree = 1; dm->release(dm); @@ -2398,8 +2476,6 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA return true; } - - bool CcdShapeConstructionInfo::SetProxy(CcdShapeConstructionInfo* shapeInfo) { if (shapeInfo == NULL) @@ -2462,74 +2538,61 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape(btScalar margin, b // 9 multiplications/additions and one function call for each triangle that passes the mid phase filtering // One possible optimization is to use directly the btBvhTriangleMeshShape when the scale is 1,1,1 // and btScaledBvhTriangleMeshShape otherwise. - if (useGimpact) - { - btTriangleIndexVertexArray* indexVertexArrays = new btTriangleIndexVertexArray( + if (useGimpact) { + if (!m_triangleIndexVertexArray || m_forceReInstance) { + if (m_triangleIndexVertexArray) + delete m_triangleIndexVertexArray; + + m_triangleIndexVertexArray = new btTriangleIndexVertexArray( m_polygonIndexArray.size(), - &m_triFaceArray[0], - 3*sizeof(int), - m_vertexArray.size()/3, + m_triFaceArray.data(), + 3 * sizeof(int), + m_vertexArray.size() / 3, &m_vertexArray[0], - 3*sizeof(btScalar) - ); - btGImpactMeshShape* gimpactShape = new btGImpactMeshShape(indexVertexArrays); - gimpactShape->setMargin(margin); - gimpactShape->updateBound(); - collisionShape = gimpactShape; - - - } else - { - if (!m_unscaledShape || m_forceReInstance) - { - - btTriangleIndexVertexArray* indexVertexArrays = 0; + 3 * sizeof(btScalar)); + m_forceReInstance = false; + } + btGImpactMeshShape *gimpactShape = new btGImpactMeshShape(m_triangleIndexVertexArray); + gimpactShape->setMargin(margin); + gimpactShape->updateBound(); + collisionShape = gimpactShape; + } + else { + if (!m_triangleIndexVertexArray || m_forceReInstance) { ///enable welding, only for the objects that need it (such as soft bodies) - if (0.f != m_weldingThreshold1) - { - btTriangleMesh* collisionMeshData = new btTriangleMesh(true,false); + if (0.0f != m_weldingThreshold1) { + btTriangleMesh *collisionMeshData = new btTriangleMesh(true, false); collisionMeshData->m_weldingThreshold = m_weldingThreshold1; - bool removeDuplicateVertices=true; + bool removeDuplicateVertices = true; // m_vertexArray not in multiple of 3 anymore, use m_triFaceArray - for (unsigned int i=0; i<m_triFaceArray.size(); i+=3) { - btScalar *bt = &m_vertexArray[3*m_triFaceArray[i]]; + 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]]; + bt = &m_vertexArray[3 * m_triFaceArray[i + 1]]; btVector3 v2(bt[0], bt[1], bt[2]); - bt = &m_vertexArray[3*m_triFaceArray[i+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; - - } else - { - indexVertexArrays = new btTriangleIndexVertexArray( + m_triangleIndexVertexArray = collisionMeshData; + } + else { + m_triangleIndexVertexArray = new btTriangleIndexVertexArray( m_polygonIndexArray.size(), - &m_triFaceArray[0], - 3*sizeof(int), - m_vertexArray.size()/3, + m_triFaceArray.data(), + 3 * sizeof(int), + m_vertexArray.size() / 3, &m_vertexArray[0], - 3*sizeof(btScalar)); + 3 * sizeof(btScalar)); } - - // this shape will be shared and not deleted until shapeInfo is deleted - - // for UpdateMesh, reuse the last memory location so instancing wont crash. - if (m_unscaledShape) { - DeleteBulletShape(m_unscaledShape, false); - m_unscaledShape->~btBvhTriangleMeshShape(); - m_unscaledShape = new(m_unscaledShape) btBvhTriangleMeshShape( indexVertexArrays, true, useBvh ); - } else { - m_unscaledShape = new btBvhTriangleMeshShape( indexVertexArrays, true, useBvh ); - } - m_forceReInstance= false; - } else if (useBvh && m_unscaledShape->getOptimizedBvh() == NULL) { - // the existing unscaledShape was not build with Bvh, do it now - m_unscaledShape->buildOptimizedBvh(); + + m_forceReInstance = false; } - collisionShape = new btScaledBvhTriangleMeshShape(m_unscaledShape, btVector3(1.0f,1.0f,1.0f)); + + btBvhTriangleMeshShape *unscaledShape = new btBvhTriangleMeshShape(m_triangleIndexVertexArray, true, useBvh); + unscaledShape->setMargin(margin); + collisionShape = new btScaledBvhTriangleMeshShape(unscaledShape, btVector3(1.0f, 1.0f, 1.0f)); collisionShape->setMargin(margin); } break; @@ -2571,10 +2634,9 @@ CcdShapeConstructionInfo::~CcdShapeConstructionInfo() (*sit)->Release(); } m_shapeArray.clear(); - if (m_unscaledShape) - { - DeleteBulletShape(m_unscaledShape, true); - } + + if (m_triangleIndexVertexArray) + delete m_triangleIndexVertexArray; m_vertexArray.clear(); if (m_shapeType == PHY_SHAPE_MESH && m_meshObject != NULL) { diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 4d0d96e07c6..c49ae8d20e1 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -79,7 +79,7 @@ public: m_userData(NULL), m_refCount(1), m_meshObject(NULL), - m_unscaledShape(NULL), + m_triangleIndexVertexArray(NULL), m_forceReInstance(false), m_weldingThreshold1(0.f), m_shapeProxy(NULL) @@ -110,10 +110,11 @@ public: void AddShape(CcdShapeConstructionInfo* shapeInfo); - btTriangleMeshShape* GetMeshShape(void) + btStridingMeshInterface *GetMeshInterface() { - return (m_unscaledShape); + return m_triangleIndexVertexArray; } + CcdShapeConstructionInfo* GetChildShape(int i) { if (i < 0 || i >= (int)m_shapeArray.size()) @@ -195,8 +196,8 @@ protected: int m_refCount; // this class is shared between replicas // keep track of users so that we can release it RAS_MeshObject* m_meshObject; // Keep a pointer to the original mesh - btBvhTriangleMeshShape* m_unscaledShape;// holds the shared unscale BVH mesh shape, - // the actual shape is of type btScaledBvhTriangleMeshShape + // The list of vertexes and indexes for the triangle mesh, shared between Bullet shape. + btTriangleIndexVertexArray *m_triangleIndexVertexArray; std::vector<CcdShapeConstructionInfo*> m_shapeArray; // for compound shapes bool m_forceReInstance; //use gimpact for concave dynamic/moving collision detection float m_weldingThreshold1; //welding closeby vertices together can improve softbody stability etc. @@ -235,6 +236,8 @@ struct CcdConstructionInfo m_mass(0.f), m_clamp_vel_min(-1.f), m_clamp_vel_max(-1.f), + m_clamp_angvel_min(0.0f), + m_clamp_angvel_max(0.0f), m_restitution(0.1f), m_friction(0.5f), m_linearDamping(0.1f), @@ -301,6 +304,8 @@ struct CcdConstructionInfo btScalar m_mass; btScalar m_clamp_vel_min; btScalar m_clamp_vel_max; + btScalar m_clamp_angvel_min; // Minimum angular velocity, in radians/sec. + btScalar m_clamp_angvel_max; // Maximum angular velocity, in radians/sec. btScalar m_restitution; btScalar m_friction; btScalar m_linearDamping; @@ -447,6 +452,23 @@ public: #endif }; +class CleanPairCallback : public btOverlapCallback +{ + btBroadphaseProxy *m_cleanProxy; + btOverlappingPairCache *m_pairCache; + btDispatcher *m_dispatcher; + +public: + CleanPairCallback(btBroadphaseProxy *cleanProxy, btOverlappingPairCache *pairCache, btDispatcher *dispatcher) + :m_cleanProxy(cleanProxy), + m_pairCache(pairCache), + m_dispatcher(dispatcher) + { + } + + virtual bool processOverlap(btBroadphasePair &pair); +}; + ///CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution. class CcdPhysicsController : public PHY_IPhysicsController { @@ -461,6 +483,7 @@ protected: class CcdShapeConstructionInfo* m_shapeInfo; btCollisionShape* m_bulletChildShape; + btAlignedObjectArray<btTypedConstraint*> m_ccdConstraintRefs; // keep track of typed constraints referencing this rigid body friend class CcdPhysicsEnvironment; // needed when updating the controller //some book keeping for replication @@ -480,6 +503,7 @@ protected: short m_savedCollisionFilterGroup; short m_savedCollisionFilterMask; MT_Scalar m_savedMass; + bool m_savedDyna; bool m_suspended; @@ -496,6 +520,16 @@ protected: return (--m_registerCount == 0) ? true : false; } + bool Registered() const + { + return (m_registerCount != 0); + } + + void addCcdConstraintRef(btTypedConstraint* c); + void removeCcdConstraintRef(btTypedConstraint* c); + btTypedConstraint* getCcdConstraintRef(int index); + int getNumCcdConstraintRefs() const; + void SetWorldOrientation(const btMatrix3x3& mat); void ForceWorldTransform(const btMatrix3x3& mat, const btVector3& pos); @@ -506,7 +540,15 @@ protected: CcdPhysicsController (const CcdConstructionInfo& ci); + /** + * Delete the current Bullet shape used in the rigid body. + */ bool DeleteControllerShape(); + + /** + * Delete the old Bullet shape and set the new Bullet shape : newShape + * \param newShape The new Bullet shape to set, if is NULL we create a new Bullet shape + */ bool ReplaceControllerShape(btCollisionShape *newShape); virtual ~CcdPhysicsController(); @@ -522,6 +564,7 @@ protected: btRigidBody* GetRigidBody(); + const btRigidBody* GetRigidBody() const; btCollisionObject* GetCollisionObject(); btSoftBody* GetSoftBody(); btKinematicCharacterController* GetCharacterController(); @@ -540,6 +583,13 @@ protected: * SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') */ virtual bool SynchronizeMotionStates(float time); + + /** + * Called for every physics simulation step. Use this method for + * things like limiting linear and angular velocity. + */ + void SimulationTick(float timestep); + /** * WriteMotionStateToDynamics ynchronizes dynas, kinematic and deformable entities (and do 'late binding') */ @@ -573,6 +623,12 @@ protected: virtual void Jump(); virtual void SetActive(bool active); + virtual float GetLinearDamping() const; + virtual float GetAngularDamping() const; + virtual void SetLinearDamping(float damping); + virtual void SetAngularDamping(float damping); + virtual void SetDamping(float linear, float angular); + // reading out information from physics virtual MT_Vector3 GetLinearVelocity(); virtual MT_Vector3 GetAngularVelocity(); @@ -584,7 +640,7 @@ protected: virtual void ResolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ); - + virtual void RefreshCollisions(); virtual void SuspendDynamics(bool ghost); virtual void RestoreDynamics(); @@ -612,8 +668,12 @@ protected: virtual void CalcXform() {} virtual void SetMargin(float margin) { - if (m_collisionShape) - m_collisionShape->setMargin(btScalar(margin)); + if (m_collisionShape) { + m_collisionShape->setMargin(margin); + // if the shape use a unscaled shape we have also to set the correct margin in it + if (m_collisionShape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) + ((btScaledBvhTriangleMeshShape *)m_collisionShape)->getChildShape()->setMargin(margin); + } } virtual float GetMargin() const { @@ -652,6 +712,23 @@ protected: return m_cci.m_clamp_vel_max; } + virtual void SetAngularVelocityMin(float val) + { + m_cci.m_clamp_angvel_min = val; + } + virtual float GetAngularVelocityMin() const + { + return m_cci.m_clamp_angvel_min; + } + virtual void SetAngularVelocityMax(float val) + { + m_cci.m_clamp_angvel_max = val; + } + virtual float GetAngularVelocityMax() const + { + return m_cci.m_clamp_angvel_max; + } + bool WantsSleeping(); void UpdateDeactivation(float timeStep); @@ -698,6 +775,11 @@ protected: return GetConstructionInfo().m_bDyna; } + virtual bool IsSuspended() const + { + return m_suspended; + } + virtual bool IsCompound() { return GetConstructionInfo().m_shapeInfo->m_shapeType == PHY_SHAPE_COMPOUND; @@ -705,6 +787,9 @@ protected: virtual bool ReinstancePhysicsShape(KX_GameObject *from_gameobj, RAS_MeshObject* from_meshobj); + /* Method to replicate rigid body joint contraints for group instances. */ + virtual void ReplicateConstraints(KX_GameObject *gameobj, std::vector<KX_GameObject*> constobj); + #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("GE:CcdPhysicsController") #endif diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index e17d4402556..eec579158cc 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -174,26 +174,27 @@ public: virtual void GetWheelPosition(int wheelIndex,float& posX,float& posY,float& posZ) const { - btTransform trans = m_vehicle->getWheelTransformWS(wheelIndex); - posX = trans.getOrigin().x(); - posY = trans.getOrigin().y(); - posZ = trans.getOrigin().z(); + if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) + { + btVector3 origin = m_vehicle->getWheelTransformWS(wheelIndex).getOrigin(); + + posX = origin.x(); + posY = origin.y(); + posZ = origin.z(); + } } + virtual void GetWheelOrientationQuaternion(int wheelIndex,float& quatX,float& quatY,float& quatZ,float& quatW) const { - btTransform trans = m_vehicle->getWheelTransformWS(wheelIndex); - btQuaternion quat = trans.getRotation(); - btMatrix3x3 orn2(quat); - - quatX = trans.getRotation().x(); - quatY = trans.getRotation().y(); - quatZ = trans.getRotation().z(); - quatW = trans.getRotation()[3]; - - - //printf("test"); - + if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) + { + btQuaternion quat = m_vehicle->getWheelTransformWS(wheelIndex).getRotation(); + quatX = quat.x(); + quatY = quat.y(); + quatZ = quat.z(); + quatW = quat.w(); + } } virtual float GetWheelRotation(int wheelIndex) const @@ -205,8 +206,8 @@ public: btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex); rotation = info.m_rotation; } - return rotation; + return rotation; } @@ -223,12 +224,16 @@ public: virtual void SetSteeringValue(float steering,int wheelIndex) { - m_vehicle->setSteeringValue(steering,wheelIndex); + if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) { + m_vehicle->setSteeringValue(steering,wheelIndex); + } } virtual void ApplyEngineForce(float force,int wheelIndex) { - m_vehicle->applyEngineForce(force,wheelIndex); + if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) { + m_vehicle->applyEngineForce(force,wheelIndex); + } } virtual void ApplyBraking(float braking,int wheelIndex) @@ -405,6 +410,10 @@ m_ccdMode(0), m_solverType(-1), m_profileTimings(0), m_enableSatCollisionDetection(false), +m_deactivationTime(2.0f), +m_linearDeactivationThreshold(0.8f), +m_angularDeactivationThreshold(1.0f), +m_contactBreakingThreshold(0.02f), m_solver(NULL), m_ownPairCache(NULL), m_filterCallback(NULL), @@ -447,6 +456,7 @@ m_scalingPropagated(false) SetSolverType(1);//issues with quickstep and memory allocations // m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,m_broadphase,m_solver,m_collisionConfiguration); m_dynamicsWorld = new btSoftRigidDynamicsWorld(dispatcher,m_broadphase,m_solver,m_collisionConfiguration); + m_dynamicsWorld->setInternalTickCallback(&CcdPhysicsEnvironment::StaticSimulationSubtickCallback, this); //m_dynamicsWorld->getSolverInfo().m_linearSlop = 0.01f; //m_dynamicsWorld->getSolverInfo().m_solverMode= SOLVER_USE_WARMSTARTING + SOLVER_USE_2_FRICTION_DIRECTIONS + SOLVER_RANDMIZE_ORDER + SOLVER_USE_FRICTION_WARMSTARTING; @@ -456,15 +466,20 @@ m_scalingPropagated(false) void CcdPhysicsEnvironment::AddCcdPhysicsController(CcdPhysicsController* ctrl) { + // the controller is already added we do nothing + if (!m_controllers.insert(ctrl).second) { + return; + } + btRigidBody* body = ctrl->GetRigidBody(); btCollisionObject* obj = ctrl->GetCollisionObject(); //this m_userPointer is just used for triggers, see CallbackTriggers obj->setUserPointer(ctrl); - if (body) - body->setGravity( m_gravity ); - - m_controllers.insert(ctrl); + if (body) { + body->setGravity(m_gravity); + body->setSleepingThresholds(m_linearDeactivationThreshold, m_angularDeactivationThreshold); + } if (body) { @@ -496,20 +511,49 @@ void CcdPhysicsEnvironment::AddCcdPhysicsController(CcdPhysicsController* ctrl) assert(obj->getBroadphaseHandle()); } - +void CcdPhysicsEnvironment::RemoveConstraint(btTypedConstraint *con) +{ + btRigidBody rbA = con->getRigidBodyA(); + btRigidBody rbB = con->getRigidBodyB(); + rbA.activate(); + rbB.activate(); + m_dynamicsWorld->removeConstraint(con); + + if (rbA.getUserPointer()) { + ((CcdPhysicsController *)rbA.getUserPointer())->removeCcdConstraintRef(con); + } + + if (rbB.getUserPointer()) { + ((CcdPhysicsController *)rbB.getUserPointer())->removeCcdConstraintRef(con); + } + + /* Since we remove the constraint in the onwer and the target, we can delete it, + * KX_ConstraintWrapper keep the constraint id not the pointer, so no problems. */ + delete con; +} bool CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController* ctrl) { + // if the physics controller is already removed we do nothing + if (!m_controllers.erase(ctrl)) { + return false; + } + //also remove constraint btRigidBody* body = ctrl->GetRigidBody(); if (body) { - for (int i=body->getNumConstraintRefs()-1;i>=0;i--) + btBroadphaseProxy *proxy = ctrl->GetCollisionObject()->getBroadphaseHandle(); + btDispatcher *dispatcher = m_dynamicsWorld->getDispatcher(); + btOverlappingPairCache *pairCache = m_dynamicsWorld->getPairCache(); + + CleanPairCallback cleanPairs(proxy, pairCache, dispatcher); + pairCache->processAllOverlappingPairs(&cleanPairs, dispatcher); + + for (int i = ctrl->getNumCcdConstraintRefs() - 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 + btTypedConstraint* con = ctrl->getCcdConstraintRef(i); + RemoveConstraint(con); } m_dynamicsWorld->removeRigidBody(ctrl->GetRigidBody()); @@ -524,7 +568,7 @@ bool CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController* ctr } if (vehicle_constraint > 0) - RemoveConstraint(vehicle_constraint); + RemoveConstraintById(vehicle_constraint); } else { //if a softbody @@ -541,13 +585,8 @@ bool CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController* ctr } } } - if (ctrl->m_registerCount != 0) - printf("Warning: removing controller with non-zero m_registerCount: %d\n", ctrl->m_registerCount); - //remove it from the triggers - m_triggerControllers.erase(ctrl); - - return (m_controllers.erase(ctrl) != 0); + return true; } void CcdPhysicsEnvironment::UpdateCcdPhysicsController(CcdPhysicsController* ctrl, btScalar newMass, int newCollisionFlags, short int newCollisionGroup, short int newCollisionMask) @@ -555,6 +594,7 @@ void CcdPhysicsEnvironment::UpdateCcdPhysicsController(CcdPhysicsController* ctr // this function is used when the collisionning group of a controller is changed // remove and add the collistioning object btRigidBody* body = ctrl->GetRigidBody(); + btSoftBody *softBody = ctrl->GetSoftBody(); btCollisionObject* obj = ctrl->GetCollisionObject(); if (obj) { @@ -568,6 +608,9 @@ void CcdPhysicsEnvironment::UpdateCcdPhysicsController(CcdPhysicsController* ctr body->setMassProps(newMass, inertia); m_dynamicsWorld->addRigidBody(body, newCollisionGroup, newCollisionMask); } + else if (softBody) { + m_dynamicsWorld->addSoftBody(softBody); + } else { m_dynamicsWorld->addCollisionObject(obj, newCollisionGroup, newCollisionMask); } @@ -579,43 +622,6 @@ void CcdPhysicsEnvironment::UpdateCcdPhysicsController(CcdPhysicsController* ctr ctrl->m_cci.m_collisionFlags = newCollisionFlags; } -void CcdPhysicsEnvironment::EnableCcdPhysicsController(CcdPhysicsController* ctrl) -{ - if (m_controllers.insert(ctrl).second) - { - 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()); - } -} - -void CcdPhysicsEnvironment::DisableCcdPhysicsController(CcdPhysicsController* ctrl) -{ - if (m_controllers.erase(ctrl)) - { - btRigidBody* body = ctrl->GetRigidBody(); - if (body) - { - m_dynamicsWorld->removeRigidBody(body); - } else - { - if (ctrl->GetSoftBody()) - { - } else - { - m_dynamicsWorld->removeCollisionObject(ctrl->GetCollisionObject()); - } - } - } -} - void CcdPhysicsEnvironment::RefreshCcdPhysicsController(CcdPhysicsController* ctrl) { btCollisionObject* obj = ctrl->GetCollisionObject(); @@ -629,6 +635,11 @@ void CcdPhysicsEnvironment::RefreshCcdPhysicsController(CcdPhysicsController* ct } } +bool CcdPhysicsEnvironment::IsActiveCcdPhysicsController(CcdPhysicsController *ctrl) +{ + return (m_controllers.find(ctrl) != m_controllers.end()); +} + void CcdPhysicsEnvironment::AddCcdGraphicController(CcdGraphicController* ctrl) { if (m_cullingTree && !ctrl->GetBroadphaseHandle()) @@ -664,6 +675,19 @@ void CcdPhysicsEnvironment::RemoveCcdGraphicController(CcdGraphicController* ctr } } +void CcdPhysicsEnvironment::UpdateCcdPhysicsControllerShape(CcdShapeConstructionInfo *shapeInfo) +{ + for (std::set<CcdPhysicsController *>::iterator it = m_controllers.begin(); it != m_controllers.end(); ++it) { + CcdPhysicsController *ctrl = *it; + + if (ctrl->GetShapeInfo() != shapeInfo) + continue; + + ctrl->ReplaceControllerShape(NULL); + RefreshCcdPhysicsController(ctrl); + } +} + void CcdPhysicsEnvironment::BeginFrame() { @@ -675,11 +699,31 @@ void CcdPhysicsEnvironment::DebugDrawWorld() m_dynamicsWorld->debugDrawWorld(); } +void CcdPhysicsEnvironment::StaticSimulationSubtickCallback(btDynamicsWorld *world, btScalar timeStep) +{ + // Get the pointer to the CcdPhysicsEnvironment associated with this Bullet world. + CcdPhysicsEnvironment *this_ = static_cast<CcdPhysicsEnvironment*>(world->getWorldUserInfo()); + this_->SimulationSubtickCallback(timeStep); +} + +void CcdPhysicsEnvironment::SimulationSubtickCallback(btScalar timeStep) +{ + std::set<CcdPhysicsController*>::iterator it; + + for (it = m_controllers.begin(); it != m_controllers.end(); it++) { + (*it)->SimulationTick(timeStep); + } +} + bool CcdPhysicsEnvironment::ProceedDeltaTime(double curTime,float timeStep,float interval) { std::set<CcdPhysicsController*>::iterator it; int i; + // Update Bullet global variables. + gDeactivationTime = m_deactivationTime; + gContactBreakingThreshold = m_contactBreakingThreshold; + for (it=m_controllers.begin(); it!=m_controllers.end(); it++) { (*it)->SynchronizeMotionStates(timeStep); @@ -745,8 +789,8 @@ public: 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); + // Add epsilon to the tick rate for numerical stability + int numIter = (int)(interval*(KX_KetsjiEngine::GetTicRate() + 0.001f)); for (it=m_controllers.begin(); it!=m_controllers.end(); it++) { @@ -899,21 +943,32 @@ void CcdPhysicsEnvironment::SetNumIterations(int numIter) } void CcdPhysicsEnvironment::SetDeactivationTime(float dTime) { - gDeactivationTime = dTime; + m_deactivationTime = dTime; } void CcdPhysicsEnvironment::SetDeactivationLinearTreshold(float linTresh) { - gLinearSleepingTreshold = linTresh; + m_linearDeactivationThreshold = linTresh; + + // Update from all controllers. + for (std::set<CcdPhysicsController*>::iterator it = m_controllers.begin(); it != m_controllers.end(); it++) { + if ((*it)->GetRigidBody()) + (*it)->GetRigidBody()->setSleepingThresholds(m_linearDeactivationThreshold, m_angularDeactivationThreshold); + } } void CcdPhysicsEnvironment::SetDeactivationAngularTreshold(float angTresh) { - gAngularSleepingTreshold = angTresh; + m_angularDeactivationThreshold = angTresh; + + // Update from all controllers. + for (std::set<CcdPhysicsController*>::iterator it = m_controllers.begin(); it != m_controllers.end(); it++) { + if ((*it)->GetRigidBody()) + (*it)->GetRigidBody()->setSleepingThresholds(m_linearDeactivationThreshold, m_angularDeactivationThreshold); + } } void CcdPhysicsEnvironment::SetContactBreakingTreshold(float contactBreakingTreshold) { - gContactBreakingThreshold = contactBreakingTreshold; - + m_contactBreakingThreshold = contactBreakingTreshold; } @@ -1059,11 +1114,12 @@ int CcdPhysicsEnvironment::CreateUniversalD6Constraint( return 0; } - - -void CcdPhysicsEnvironment::RemoveConstraint(int constraintId) +void CcdPhysicsEnvironment::RemoveConstraintById(int constraintId) { - + // For soft body constraints + if (constraintId == 0) + return; + int i; int numConstraints = m_dynamicsWorld->getNumConstraints(); for (i=0;i<numConstraints;i++) @@ -1071,9 +1127,7 @@ void CcdPhysicsEnvironment::RemoveConstraint(int constraintId) btTypedConstraint* constraint = m_dynamicsWorld->getConstraint(i); if (constraint->getUserConstraintId() == constraintId) { - constraint->getRigidBodyA().activate(); - constraint->getRigidBodyB().activate(); - m_dynamicsWorld->removeConstraint(constraint); + RemoveConstraint(constraint); break; } } @@ -1149,17 +1203,8 @@ static bool GetHitTriangle(btCollisionShape* shape, CcdShapeConstructionInfo* sh int indexstride; int numfaces; PHY_ScalarType indicestype; - btStridingMeshInterface* meshInterface = NULL; - btTriangleMeshShape* triangleShape = shapeInfo->GetMeshShape(); + btStridingMeshInterface* meshInterface = shapeInfo->GetMeshInterface(); - if (triangleShape) - meshInterface = triangleShape->getMeshInterface(); - else - { - // other possibility is gImpact - if (shape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE) - meshInterface = (static_cast<btGImpactMeshShape*>(shape))->getMeshInterface(); - } if (!meshInterface) return false; @@ -2016,6 +2061,9 @@ CcdPhysicsEnvironment::~CcdPhysicsEnvironment() float CcdPhysicsEnvironment::GetConstraintParam(int constraintId,int param) { btTypedConstraint* typedConstraint = GetConstraintById(constraintId); + if (!typedConstraint) + return 0.0f; + switch (typedConstraint->getUserConstraintType()) { case PHY_GENERIC_6DOF_CONSTRAINT: @@ -2055,6 +2103,9 @@ float CcdPhysicsEnvironment::GetConstraintParam(int constraintId,int param) void CcdPhysicsEnvironment::SetConstraintParam(int constraintId,int param,float value0,float value1) { btTypedConstraint* typedConstraint = GetConstraintById(constraintId); + if (!typedConstraint) + return; + switch (typedConstraint->getUserConstraintType()) { case PHY_GENERIC_6DOF_CONSTRAINT: @@ -2164,6 +2215,9 @@ void CcdPhysicsEnvironment::SetConstraintParam(int constraintId,int param,float btTypedConstraint* CcdPhysicsEnvironment::GetConstraintById(int constraintId) { + // For soft body constraints + if (constraintId == 0) + return NULL; int numConstraints = m_dynamicsWorld->getNumConstraints(); int i; @@ -2181,30 +2235,20 @@ btTypedConstraint* CcdPhysicsEnvironment::GetConstraintById(int constraintId) void CcdPhysicsEnvironment::AddSensor(PHY_IPhysicsController* ctrl) { - CcdPhysicsController* ctrl1 = (CcdPhysicsController* )ctrl; - // addSensor() is a "light" function for bullet because it is used - // dynamically when the sensor is activated. Use enableCcdPhysicsController() instead - //if (m_controllers.insert(ctrl1).second) - //{ - // addCcdPhysicsController(ctrl1); - //} - EnableCcdPhysicsController(ctrl1); + AddCcdPhysicsController(ctrl1); } bool CcdPhysicsEnvironment::RemoveCollisionCallback(PHY_IPhysicsController* ctrl) { CcdPhysicsController* ccdCtrl = (CcdPhysicsController*)ctrl; - if (!ccdCtrl->Unregister()) - return false; - m_triggerControllers.erase(ccdCtrl); - return true; + return ccdCtrl->Unregister(); } void CcdPhysicsEnvironment::RemoveSensor(PHY_IPhysicsController* ctrl) { - DisableCcdPhysicsController((CcdPhysicsController*)ctrl); + RemoveCcdPhysicsController((CcdPhysicsController*)ctrl); } void CcdPhysicsEnvironment::AddTouchCallback(int response_class, PHY_ResponseCallback callback, void *user) @@ -2242,73 +2286,83 @@ void CcdPhysicsEnvironment::AddTouchCallback(int response_class, PHY_ResponseCal bool CcdPhysicsEnvironment::RequestCollisionCallback(PHY_IPhysicsController* ctrl) { CcdPhysicsController* ccdCtrl = static_cast<CcdPhysicsController*>(ctrl); - - if (!ccdCtrl->Register()) - return false; - m_triggerControllers.insert(ccdCtrl); - return true; + return ccdCtrl->Register(); } void CcdPhysicsEnvironment::CallbackTriggers() { - 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 - btDispatcher* dispatcher = m_dynamicsWorld->getDispatcher(); - int numManifolds = dispatcher->getNumManifolds(); - for (int i=0;i<numManifolds;i++) - { - btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i); - int numContacts = manifold->getNumContacts(); - if (numContacts) - { - const btRigidBody* rb0 = static_cast<const btRigidBody*>(manifold->getBody0()); - const btRigidBody* rb1 = static_cast<const btRigidBody*>(manifold->getBody1()); - if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints)) - { - for (int j=0;j<numContacts;j++) - { - btVector3 color(1,0,0); - const btManifoldPoint& cp = manifold->getContactPoint(j); - if (m_debugDrawer) - m_debugDrawer->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),color); - } - } - const btRigidBody* obj0 = rb0; - const btRigidBody* obj1 = rb1; + bool draw_contact_points = m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints); - //m_internalOwner is set in 'addPhysicsController' - CcdPhysicsController* ctrl0 = static_cast<CcdPhysicsController*>(obj0->getUserPointer()); - CcdPhysicsController* ctrl1 = static_cast<CcdPhysicsController*>(obj1->getUserPointer()); + if (!m_triggerCallbacks[PHY_OBJECT_RESPONSE] && !draw_contact_points) + return; - std::set<CcdPhysicsController*>::const_iterator i = m_triggerControllers.find(ctrl0); - if (i == m_triggerControllers.end()) - { - i = m_triggerControllers.find(ctrl1); - } + //walk over all overlapping pairs, and if one of the involved bodies is registered for trigger callback, perform callback + btDispatcher* dispatcher = m_dynamicsWorld->getDispatcher(); + int numManifolds = dispatcher->getNumManifolds(); + for (int i=0;i<numManifolds;i++) + { + bool colliding_ctrl0 = true; + btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i); + int numContacts = manifold->getNumContacts(); + if (!numContacts) continue; - if (!(i == m_triggerControllers.end())) - { - m_triggerCallbacks[PHY_OBJECT_RESPONSE](m_triggerCallbacksUserPtrs[PHY_OBJECT_RESPONSE], - ctrl0,ctrl1,0); - } - // Bullet does not refresh the manifold contact point for object without contact response - // may need to remove this when a newer Bullet version is integrated - if (!dispatcher->needsResponse(rb0, rb1)) - { - // Refresh algorithm fails sometimes when there is penetration - // (usuall the case with ghost and sensor objects) - // Let's just clear the manifold, in any case, it is recomputed on each frame. - manifold->clearManifold(); //refreshContactPoints(rb0->getCenterOfMassTransform(),rb1->getCenterOfMassTransform()); - } + const btRigidBody* rb0 = static_cast<const btRigidBody*>(manifold->getBody0()); + const btRigidBody* rb1 = static_cast<const btRigidBody*>(manifold->getBody1()); + if (draw_contact_points) + { + for (int j=0;j<numContacts;j++) + { + btVector3 color(1,1,0); + const btManifoldPoint& cp = manifold->getContactPoint(j); + m_debugDrawer->drawContactPoint(cp.m_positionWorldOnB, + cp.m_normalWorldOnB, + cp.getDistance(), + cp.getLifeTime(), + color); } } + //m_internalOwner is set in 'addPhysicsController' + CcdPhysicsController* ctrl0 = static_cast<CcdPhysicsController*>(rb0->getUserPointer()); + CcdPhysicsController* ctrl1 = static_cast<CcdPhysicsController*>(rb1->getUserPointer()); + bool usecallback = false; + // Test if one of the controller is registered and use collision callback. + if (ctrl0->Registered()) + usecallback = true; + else if (ctrl1->Registered()) { + colliding_ctrl0 = false; + usecallback = true; + } - } + if (usecallback) { + static PHY_CollData coll_data; + const btManifoldPoint &cp = manifold->getContactPoint(0); + + /* Make sure that "point1" is always on the object we report on, and + * "point2" on the other object. Also ensure the normal is oriented + * correctly. */ + btVector3 point1 = colliding_ctrl0 ? cp.m_positionWorldOnA : cp.m_positionWorldOnB; + btVector3 point2 = colliding_ctrl0 ? cp.m_positionWorldOnB : cp.m_positionWorldOnA; + btVector3 normal = colliding_ctrl0 ? -cp.m_normalWorldOnB : cp.m_normalWorldOnB; + coll_data.m_point1 = MT_Vector3(point1.m_floats); + coll_data.m_point2 = MT_Vector3(point2.m_floats); + coll_data.m_normal = MT_Vector3(normal.m_floats); + m_triggerCallbacks[PHY_OBJECT_RESPONSE](m_triggerCallbacksUserPtrs[PHY_OBJECT_RESPONSE], + ctrl0, ctrl1, &coll_data); + } + // Bullet does not refresh the manifold contact point for object without contact response + // may need to remove this when a newer Bullet version is integrated + if (!dispatcher->needsResponse(rb0, rb1)) + { + // Refresh algorithm fails sometimes when there is penetration + // (usuall the case with ghost and sensor objects) + // Let's just clear the manifold, in any case, it is recomputed on each frame. + manifold->clearManifold(); //refreshContactPoints(rb0->getCenterOfMassTransform(),rb1->getCenterOfMassTransform()); + } + } } // This call back is called before a pair is added in the cache @@ -2624,7 +2678,6 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl if (!rb0) return 0; - btVector3 pivotInB = rb1 ? rb1->getCenterOfMassTransform().inverse()(rb0->getCenterOfMassTransform()(pivotInA)) : rb0->getCenterOfMassTransform() * pivotInA; btVector3 axisInA(axisX,axisY,axisZ); @@ -2636,6 +2689,8 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl { case PHY_POINT2POINT_CONSTRAINT: { + // If either of the controllers is missing, we can't do anything. + if (!c0 || !c1) return 0; btPoint2PointConstraint* p2p = 0; @@ -2649,6 +2704,8 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl pivotInA); } + c0->addCcdConstraintRef(p2p); + c1->addCcdConstraintRef(p2p); m_dynamicsWorld->addConstraint(p2p,disableCollisionBetweenLinkedBodies); // m_constraints.push_back(p2p); @@ -2662,6 +2719,9 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl case PHY_GENERIC_6DOF_CONSTRAINT: { + // If either of the controllers is missing, we can't do anything. + if (!c0 || !c1) return 0; + btGeneric6DofConstraint* genericConstraint = 0; if (rb1) @@ -2715,10 +2775,12 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl *rb0,s_fixedObject2, frameInA,frameInB,useReferenceFrameA); } - + if (genericConstraint) { //m_constraints.push_back(genericConstraint); + c0->addCcdConstraintRef(genericConstraint); + c1->addCcdConstraintRef(genericConstraint); m_dynamicsWorld->addConstraint(genericConstraint,disableCollisionBetweenLinkedBodies); genericConstraint->setUserConstraintId(gConstraintUid++); genericConstraint->setUserConstraintType(type); @@ -2730,6 +2792,9 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl } case PHY_CONE_TWIST_CONSTRAINT: { + // If either of the controllers is missing, we can't do anything. + if (!c0 || !c1) return 0; + btConeTwistConstraint* coneTwistContraint = 0; @@ -2781,10 +2846,12 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl *rb0,s_fixedObject2, frameInA,frameInB); } - + if (coneTwistContraint) { //m_constraints.push_back(genericConstraint); + c0->addCcdConstraintRef(coneTwistContraint); + c1->addCcdConstraintRef(coneTwistContraint); m_dynamicsWorld->addConstraint(coneTwistContraint,disableCollisionBetweenLinkedBodies); coneTwistContraint->setUserConstraintId(gConstraintUid++); coneTwistContraint->setUserConstraintType(type); @@ -2802,6 +2869,9 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl case PHY_LINEHINGE_CONSTRAINT: { + // If either of the controllers is missing, we can't do anything. + if (!c0 || !c1) return 0; + btHingeConstraint* hinge = 0; if (rb1) @@ -2858,6 +2928,8 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl hinge->setAngularOnly(angularOnly); //m_constraints.push_back(hinge); + c0->addCcdConstraintRef(hinge); + c1->addCcdConstraintRef(hinge); m_dynamicsWorld->addConstraint(hinge,disableCollisionBetweenLinkedBodies); hinge->setUserConstraintId(gConstraintUid++); hinge->setUserConstraintType(type); @@ -2926,6 +2998,10 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::CreateConeController(float conera float CcdPhysicsEnvironment::getAppliedImpulse(int constraintid) { + // For soft body constraints + if (constraintid == 0) + return 0.0f; + int i; int numConstraints = m_dynamicsWorld->getNumConstraints(); for (i=0;i<numConstraints;i++) @@ -2999,7 +3075,8 @@ struct BlenderDebugDraw : public btIDebugDraw virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,float distance,int lifeTime,const btVector3& color) { - //not yet + drawLine(PointOnB, PointOnB + normalOnB, color); + drawSphere(PointOnB, 0.1, color); } virtual void setDebugMode(int debugMode) @@ -3036,7 +3113,7 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject { Object* blenderobject = gameobj->GetBlenderObject(); - bool isbulletdyna = (blenderobject->gameflag & OB_DYNAMIC) != 0;; + bool isbulletdyna = (blenderobject->gameflag & OB_DYNAMIC) != 0; bool isbulletsensor = (blenderobject->gameflag & OB_SENSOR) != 0; bool isbulletchar = (blenderobject->gameflag & OB_CHARACTER) != 0; bool isbulletsoftbody = (blenderobject->gameflag & OB_SOFT_BODY) != 0; @@ -3056,9 +3133,7 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject { KX_BlenderSceneConverter *converter = (KX_BlenderSceneConverter*)KX_GetActiveEngine()->GetSceneConverter(); parent = converter->FindGameObject(blenderparent); - isbulletdyna = false; isbulletsoftbody = false; - shapeprops->m_mass = 0.f; } if (!isbulletdyna) @@ -3082,6 +3157,8 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject ci.m_mass = isbulletdyna ? shapeprops->m_mass : 0.f; ci.m_clamp_vel_min = shapeprops->m_clamp_vel_min; ci.m_clamp_vel_max = shapeprops->m_clamp_vel_max; + ci.m_clamp_angvel_min = shapeprops->m_clamp_angvel_min; + ci.m_clamp_angvel_max = shapeprops->m_clamp_angvel_max; ci.m_stepHeight = isbulletchar ? shapeprops->m_step_height : 0.f; ci.m_jumpSpeed = isbulletchar ? shapeprops->m_jump_speed : 0.f; ci.m_fallSpeed = isbulletchar ? shapeprops->m_fall_speed : 0.f; @@ -3339,46 +3416,50 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject //take relative transform into account! CcdPhysicsController* parentCtrl = (CcdPhysicsController*)parent->GetPhysicsController(); assert(parentCtrl); - CcdShapeConstructionInfo* parentShapeInfo = parentCtrl->GetShapeInfo(); - btRigidBody* rigidbody = parentCtrl->GetRigidBody(); - btCollisionShape* colShape = rigidbody->getCollisionShape(); - assert(colShape->isCompound()); - btCompoundShape* compoundShape = (btCompoundShape*)colShape; - - // compute the local transform from parent, this may include several node in the chain - SG_Node* gameNode = gameobj->GetSGNode(); - SG_Node* parentNode = parent->GetSGNode(); - // relative transform - MT_Vector3 parentScale = parentNode->GetWorldScaling(); - parentScale[0] = MT_Scalar(1.0)/parentScale[0]; - parentScale[1] = MT_Scalar(1.0)/parentScale[1]; - parentScale[2] = MT_Scalar(1.0)/parentScale[2]; - MT_Vector3 relativeScale = gameNode->GetWorldScaling() * parentScale; - MT_Matrix3x3 parentInvRot = parentNode->GetWorldOrientation().transposed(); - MT_Vector3 relativePos = parentInvRot*((gameNode->GetWorldPosition()-parentNode->GetWorldPosition())*parentScale); - MT_Matrix3x3 relativeRot = parentInvRot*gameNode->GetWorldOrientation(); - - shapeInfo->m_childScale.setValue(relativeScale[0],relativeScale[1],relativeScale[2]); - bm->setLocalScaling(shapeInfo->m_childScale); - shapeInfo->m_childTrans.getOrigin().setValue(relativePos[0],relativePos[1],relativePos[2]); - float rot[12]; - relativeRot.getValue(rot); - shapeInfo->m_childTrans.getBasis().setFromOpenGLSubMatrix(rot); - - parentShapeInfo->AddShape(shapeInfo); - compoundShape->addChildShape(shapeInfo->m_childTrans,bm); - //do some recalc? - //recalc inertia for rigidbody - if (!rigidbody->isStaticOrKinematicObject()) - { - btVector3 localInertia; - float mass = 1.f/rigidbody->getInvMass(); - compoundShape->calculateLocalInertia(mass,localInertia); - rigidbody->setMassProps(mass,localInertia); + + // only makes compound shape if parent has a physics controller (i.e not an empty, etc) + if (parentCtrl) { + CcdShapeConstructionInfo* parentShapeInfo = parentCtrl->GetShapeInfo(); + btRigidBody* rigidbody = parentCtrl->GetRigidBody(); + btCollisionShape* colShape = rigidbody->getCollisionShape(); + assert(colShape->isCompound()); + btCompoundShape* compoundShape = (btCompoundShape*)colShape; + + // compute the local transform from parent, this may include several node in the chain + SG_Node* gameNode = gameobj->GetSGNode(); + SG_Node* parentNode = parent->GetSGNode(); + // relative transform + MT_Vector3 parentScale = parentNode->GetWorldScaling(); + parentScale[0] = MT_Scalar(1.0)/parentScale[0]; + parentScale[1] = MT_Scalar(1.0)/parentScale[1]; + parentScale[2] = MT_Scalar(1.0)/parentScale[2]; + MT_Vector3 relativeScale = gameNode->GetWorldScaling() * parentScale; + MT_Matrix3x3 parentInvRot = parentNode->GetWorldOrientation().transposed(); + MT_Vector3 relativePos = parentInvRot*((gameNode->GetWorldPosition()-parentNode->GetWorldPosition())*parentScale); + MT_Matrix3x3 relativeRot = parentInvRot*gameNode->GetWorldOrientation(); + + shapeInfo->m_childScale.setValue(relativeScale[0],relativeScale[1],relativeScale[2]); + bm->setLocalScaling(shapeInfo->m_childScale); + shapeInfo->m_childTrans.getOrigin().setValue(relativePos[0],relativePos[1],relativePos[2]); + float rot[12]; + relativeRot.getValue(rot); + shapeInfo->m_childTrans.getBasis().setFromOpenGLSubMatrix(rot); + + parentShapeInfo->AddShape(shapeInfo); + compoundShape->addChildShape(shapeInfo->m_childTrans,bm); + //do some recalc? + //recalc inertia for rigidbody + if (!rigidbody->isStaticOrKinematicObject()) + { + btVector3 localInertia; + float mass = 1.f/rigidbody->getInvMass(); + compoundShape->calculateLocalInertia(mass,localInertia); + rigidbody->setMassProps(mass,localInertia); + } + shapeInfo->Release(); + // delete motionstate as it's not used + delete motionstate; } - shapeInfo->Release(); - // delete motionstate as it's not used - delete motionstate; return; } @@ -3482,20 +3563,23 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject if (isbulletdyna) gameobj->SetRecordAnimation(true); + physicscontroller->SetNewClientInfo(gameobj->getClientInfo()); + // don't add automatically sensor object, they are added when a collision sensor is registered if (!isbulletsensor && (blenderobject->lay & activeLayerBitInfo) != 0) { this->AddCcdPhysicsController( physicscontroller); } - physicscontroller->SetNewClientInfo(gameobj->getClientInfo()); + { btRigidBody* rbody = physicscontroller->GetRigidBody(); if (rbody) { + rbody->setLinearFactor(ci.m_linearFactor); + if (isbulletrigidbody) { - rbody->setLinearFactor(ci.m_linearFactor); rbody->setAngularFactor(ci.m_angularFactor); } @@ -3506,6 +3590,9 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject } } + if (parent) + physicscontroller->SuspendDynamics(false); + CcdPhysicsController* parentCtrl = parent ? (CcdPhysicsController*)parent->GetPhysicsController() : 0; physicscontroller->SetParentCtrl(parentCtrl); @@ -3556,3 +3643,79 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject } #endif } + + +void CcdPhysicsEnvironment::SetupObjectConstraints(KX_GameObject *obj_src, KX_GameObject *obj_dest, + bRigidBodyJointConstraint *dat) +{ + PHY_IPhysicsController *phy_src = obj_src->GetPhysicsController(); + PHY_IPhysicsController *phy_dest = obj_dest->GetPhysicsController(); + PHY_IPhysicsEnvironment *phys_env = obj_src->GetScene()->GetPhysicsEnvironment(); + + /* We need to pass a full constraint frame, not just axis. */ + MT_Matrix3x3 localCFrame(MT_Vector3(dat->axX,dat->axY,dat->axZ)); + MT_Vector3 axis0 = localCFrame.getColumn(0); + MT_Vector3 axis1 = localCFrame.getColumn(1); + MT_Vector3 axis2 = localCFrame.getColumn(2); + MT_Vector3 scale = obj_src->NodeGetWorldScaling(); + + /* Apply not only the pivot and axis values, but also take scale into count + * this is not working well, if only one or two axis are scaled, but works ok on + * homogeneous scaling. */ + int constraintId = phys_env->CreateConstraint( + phy_src, phy_dest, (PHY_ConstraintType)dat->type, + (float)(dat->pivX * scale.x()), (float)(dat->pivY * scale.y()), (float)(dat->pivZ * scale.z()), + (float)(axis0.x() * scale.x()), (float)(axis0.y() * scale.y()), (float)(axis0.z() * scale.z()), + (float)(axis1.x() * scale.x()), (float)(axis1.y() * scale.y()), (float)(axis1.z() * scale.z()), + (float)(axis2.x() * scale.x()), (float)(axis2.y() * scale.y()), (float)(axis2.z() * scale.z()), + dat->flag); + + /* PHY_POINT2POINT_CONSTRAINT = 1, + * PHY_LINEHINGE_CONSTRAINT = 2, + * PHY_ANGULAR_CONSTRAINT = 3, + * PHY_CONE_TWIST_CONSTRAINT = 4, + * PHY_VEHICLE_CONSTRAINT = 11, + * PHY_GENERIC_6DOF_CONSTRAINT = 12 */ + + if (!constraintId) + return; + + int dof = 0; + int dof_max = 0; + int dofbit = 0; + + switch (dat->type) { + /* Set all the limits for generic 6DOF constraint. */ + case PHY_GENERIC_6DOF_CONSTRAINT: + dof_max = 6; + dofbit = 1; + break; + /* Set XYZ angular limits for cone twist constraint. */ + case PHY_CONE_TWIST_CONSTRAINT: + dof = 3; + dof_max = 6; + dofbit = 1 << 3; + break; + /* Set only X angular limits for line hinge and angular constraint. */ + case PHY_LINEHINGE_CONSTRAINT: + case PHY_ANGULAR_CONSTRAINT: + dof = 3; + dof_max = 4; + dofbit = 1 << 3; + break; + default: + break; + } + + for (; dof < dof_max; dof++) { + if (dat->flag & dofbit) { + phys_env->SetConstraintParam(constraintId, dof, dat->minLimit[dof], dat->maxLimit[dof]); + } + else { + /* minLimit > maxLimit means free (no limit) for this degree of freedom. */ + phys_env->SetConstraintParam(constraintId, dof, 1.0f, -1.0f); + } + dofbit <<= 1; + } + +} diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h index ff8a3f4f9f9..86f663959f1 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h @@ -22,6 +22,8 @@ subject to the following restrictions: #define __CCDPHYSICSENVIRONMENT_H__ #include "PHY_IPhysicsEnvironment.h" +#include "KX_KetsjiEngine.h" + #include <vector> #include <set> #include <map> @@ -50,8 +52,10 @@ class btBroadphaseInterface; struct btDbvtBroadphase; class btOverlappingPairCache; class btIDebugDraw; +class btDynamicsWorld; class PHY_IVehicle; class CcdOverlapFilterCallBack; +class CcdShapeConstructionInfo; /** CcdPhysicsEnvironment is an experimental mainloop for physics simulation using optional continuous collision detection. * Physics Environment takes care of stepping the simulation and is a container for physics entities. @@ -63,6 +67,9 @@ class CcdPhysicsEnvironment : public PHY_IPhysicsEnvironment friend class CcdOverlapFilterCallBack; btVector3 m_gravity; + // Removes the constraint and his references from the owner and the target. + void RemoveConstraint(btTypedConstraint *con); + protected: btIDebugDraw* m_debugDrawer; @@ -84,6 +91,11 @@ protected: int m_profileTimings; bool m_enableSatCollisionDetection; + float m_deactivationTime; + float m_linearDeactivationThreshold; + float m_angularDeactivationThreshold; + float m_contactBreakingThreshold; + void ProcessFhSprings(double curTime,float timeStep); public: @@ -126,13 +138,20 @@ protected: /// Perform an integration step of duration 'timeStep'. virtual bool ProceedDeltaTime(double curTime,float timeStep,float interval); + /** + * Called by Bullet for every physical simulation (sub)tick. + * Our constructor registers this callback to Bullet, which stores a pointer to 'this' in + * the btDynamicsWorld::getWorldUserInfo() pointer. + */ + static void StaticSimulationSubtickCallback(btDynamicsWorld *world, btScalar timeStep); + void SimulationSubtickCallback(btScalar timeStep); + virtual void DebugDrawWorld(); // virtual bool proceedDeltaTimeOneStep(float timeStep); virtual void SetFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep) { - //based on DEFAULT_PHYSICS_TIC_RATE of 60 hertz - SetNumTimeSubSteps((int)(fixedTimeStep / 60.f)); + SetNumTimeSubSteps((int)(fixedTimeStep / KX_KetsjiEngine::GetTicRate())); } //returns 0.f if no fixed timestep is used @@ -169,7 +188,7 @@ protected: virtual float GetConstraintParam(int constraintId,int param); - virtual void RemoveConstraint(int constraintid); + virtual void RemoveConstraintById(int constraintid); virtual float getAppliedImpulse(int constraintid); @@ -220,16 +239,22 @@ protected: void UpdateCcdPhysicsController(CcdPhysicsController* ctrl, btScalar newMass, int newCollisionFlags, short int newCollisionGroup, short int newCollisionMask); - void DisableCcdPhysicsController(CcdPhysicsController* ctrl); - - void EnableCcdPhysicsController(CcdPhysicsController* ctrl); - void RefreshCcdPhysicsController(CcdPhysicsController* ctrl); + bool IsActiveCcdPhysicsController(CcdPhysicsController *ctrl); + void AddCcdGraphicController(CcdGraphicController* ctrl); void RemoveCcdGraphicController(CcdGraphicController* ctrl); + /** + * Update all physics controllers shape which use the same shape construction info. + * Call RecreateControllerShape on controllers which use the same shape + * construction info that argument shapeInfo. + * You need to call this function when the shape construction info changed. + */ + void UpdateCcdPhysicsControllerShape(CcdShapeConstructionInfo *shapeInfo); + btBroadphaseInterface* GetBroadphase(); btDbvtBroadphase* GetCullingTree() { return m_cullingTree; } @@ -274,12 +299,15 @@ protected: bool isCompoundChild, bool hasCompoundChildren); + /* Set the rigid body joints constraints values for converted objects and replicated group instances. */ + virtual void SetupObjectConstraints(KX_GameObject *obj_src, KX_GameObject *obj_dest, + bRigidBodyJointConstraint *dat); + protected: std::set<CcdPhysicsController*> m_controllers; - std::set<CcdPhysicsController*> m_triggerControllers; PHY_ResponseCallback m_triggerCallbacks[PHY_NUM_RESPONSE]; void* m_triggerCallbacksUserPtrs[PHY_NUM_RESPONSE]; diff --git a/source/gameengine/Physics/Bullet/SConscript b/source/gameengine/Physics/Bullet/SConscript index 2a8249b9558..5c5b1fe6ea6 100644 --- a/source/gameengine/Physics/Bullet/SConscript +++ b/source/gameengine/Physics/Bullet/SConscript @@ -34,7 +34,8 @@ incs = [ '#intern/container', '#intern/guardedalloc', '#intern/string', - '#extern/glew/include', + env['BF_GLEW_INC'], + '#/intern/glew-mx', '#intern/moto/include', '#source/blender/blenkernel', '#source/blender/blenlib', @@ -52,6 +53,7 @@ incs = ' '.join(incs) incs += ' ' + env['BF_BULLET_INC'] defs = [] +defs += env['BF_GL_DEFINITIONS'] if env['WITH_BF_PYTHON']: incs += ' ' + env['BF_PYTHON_INC'] diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp index 979128370ee..99db56bfcef 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp @@ -106,7 +106,7 @@ int DummyPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ct } -void DummyPhysicsEnvironment::RemoveConstraint(int constraintid) +void DummyPhysicsEnvironment::RemoveConstraintById(int constraintid) { if (constraintid) { diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h index cfc8841cac2..929345d7161 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h @@ -68,7 +68,7 @@ public: float axis2X=0,float axis2Y=0,float axis2Z=0,int flag=0 ); - virtual void RemoveConstraint(int constraintid); + virtual void RemoveConstraintById(int constraintid); //complex constraint for vehicles virtual PHY_IVehicle* GetVehicleConstraint(int constraintId) diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h index f9975484fa7..62b163536dd 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsController.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsController.h @@ -32,6 +32,7 @@ #ifndef __PHY_IPHYSICSCONTROLLER_H__ #define __PHY_IPHYSICSCONTROLLER_H__ +#include <vector> #include "PHY_IController.h" class PHY_IMotionState; @@ -89,6 +90,13 @@ class PHY_IPhysicsController : public PHY_IController virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local)=0; virtual void ResolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) = 0; + virtual float GetLinearDamping() const=0; + virtual float GetAngularDamping() const=0; + virtual void SetLinearDamping(float damping)=0; + virtual void SetAngularDamping(float damping)=0; + virtual void SetDamping(float linear, float angular)=0; + + virtual void RefreshCollisions() = 0; virtual void SuspendDynamics(bool ghost=false)=0; virtual void RestoreDynamics()=0; @@ -117,6 +125,11 @@ class PHY_IPhysicsController : public PHY_IController virtual float GetLinVelocityMax() const=0; virtual void SetLinVelocityMax(float val) = 0; + virtual void SetAngularVelocityMin(float val) = 0; + virtual float GetAngularVelocityMin() const = 0; + virtual void SetAngularVelocityMax(float val) = 0; + virtual float GetAngularVelocityMax() const = 0; + MT_Vector3 GetWorldPosition(MT_Vector3& localpos); // Shape control @@ -126,9 +139,12 @@ class PHY_IPhysicsController : public PHY_IController virtual bool IsDynamic() = 0; virtual bool IsCompound() = 0; + virtual bool IsSuspended() const = 0; virtual bool ReinstancePhysicsShape(KX_GameObject *from_gameobj, RAS_MeshObject* from_meshobj) = 0; + /* Method to replicate rigid body joint contraints for group instances. */ + virtual void ReplicateConstraints(KX_GameObject *gameobj, std::vector<KX_GameObject*> constobj) = 0; #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_IPhysicsController") diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h index dd762b02b4e..4b8d36285be 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h @@ -55,6 +55,7 @@ class KX_Scene; struct PHY_ShapeProps; struct PHY_MaterialProps; class PHY_IMotionState; +struct bRigidBodyJointConstraint; /** * pass back information from rayTest @@ -167,7 +168,7 @@ class PHY_IPhysicsEnvironment float axis1X=0,float axis1Y=0,float axis1Z=0, float axis2X=0,float axis2Y=0,float axis2Z=0,int flag=0 )=0; - virtual void RemoveConstraint(int constraintid)=0; + virtual void RemoveConstraintById(int constraintid) = 0; virtual float GetAppliedImpulse(int constraintid) { return 0.0f; } @@ -213,6 +214,9 @@ class PHY_IPhysicsEnvironment bool isCompoundChild, bool hasCompoundChildren) = 0; + /* Set the rigid body joints constraints values for converted objects and replicated group instances. */ + virtual void SetupObjectConstraints(KX_GameObject *obj_src, KX_GameObject *obj_dest, + bRigidBodyJointConstraint *dat) {} #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_IPhysicsEnvironment") diff --git a/source/gameengine/Physics/common/PHY_Pro.h b/source/gameengine/Physics/common/PHY_Pro.h index 7c5d9c9638e..c9b91b06a3c 100644 --- a/source/gameengine/Physics/common/PHY_Pro.h +++ b/source/gameengine/Physics/common/PHY_Pro.h @@ -43,6 +43,8 @@ struct PHY_ShapeProps { MT_Scalar m_friction_scaling[3]; // Scaling for anisotropic friction. Component in range [0, 1] MT_Scalar m_clamp_vel_min; // Clamp the minimum velocity, this ensures an object moves at a minimum speed unless its stationary MT_Scalar m_clamp_vel_max; // Clamp max velocity + MT_Scalar m_clamp_angvel_min; // Clamp the minimum angular velocity. + MT_Scalar m_clamp_angvel_max; // Clamp the maximum angular velocity. bool m_do_anisotropic; // Should I do anisotropic friction? bool m_do_fh; // Should the object have a linear Fh spring? bool m_do_rot_fh; // Should the object have an angular Fh spring? |