diff options
Diffstat (limited to 'source/gameengine/Physics/Bullet')
4 files changed, 580 insertions, 459 deletions
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index 44c4e284e7c..8ea2b4f299d 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) { @@ -588,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; @@ -634,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; } @@ -850,36 +846,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) @@ -1082,6 +1048,25 @@ 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(); @@ -1546,8 +1531,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 @@ -1597,7 +1581,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 @@ -1653,7 +1637,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() @@ -1713,33 +1697,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 /// @@ -1821,7 +1822,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; @@ -1833,7 +1834,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(); @@ -1856,80 +1857,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]; @@ -1939,28 +1943,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 */ } } @@ -1969,43 +1983,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]; @@ -2020,19 +2030,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]; @@ -2041,12 +2051,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]; @@ -2063,7 +2073,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]; @@ -2077,27 +2087,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); @@ -2105,10 +2115,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; @@ -2131,51 +2140,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 * * */ @@ -2187,41 +2195,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++; @@ -2230,42 +2235,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]; @@ -2283,37 +2284,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; } @@ -2322,51 +2323,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 than 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); } } @@ -2374,32 +2370,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); + fv_pt = (poly->VertexCount() == 3 ? tri_verts : quad_verts); - for (; *fv_pt > -1; fv_pt++) - { - v_orig= poly->GetVertex(*fv_pt)->getOrigIndex(); - - 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 */ @@ -2409,55 +2402,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); @@ -2465,8 +2463,6 @@ bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RA return true; } - - bool CcdShapeConstructionInfo::SetProxy(CcdShapeConstructionInfo* shapeInfo) { if (shapeInfo == NULL) @@ -2529,74 +2525,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)); - } - - // 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 ); + 3 * sizeof(btScalar)); } - 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; @@ -2638,10 +2621,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 de40624d7bb..b1d38763fbb 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. @@ -447,6 +448,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 { @@ -498,6 +516,11 @@ 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); @@ -513,7 +536,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(); @@ -598,7 +629,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(); @@ -626,8 +657,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 { @@ -712,6 +747,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; @@ -719,6 +759,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 ac74029fbe3..3670d79a01e 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -461,6 +461,19 @@ m_scalingPropagated(false) void CcdPhysicsEnvironment::AddCcdPhysicsController(CcdPhysicsController* ctrl) { + // the controller is already added we do nothing + if (!m_controllers.insert(ctrl).second) { + return; + } + + /* In the case of compound child controller (see also RemoveCcdPhysicsController) + * we add the controller to the trigger controlers list : m_triggerControllers + * if it use collision callbacks. + */ + if (ctrl->Registered()) { + m_triggerControllers.insert(ctrl); + } + btRigidBody* body = ctrl->GetRigidBody(); btCollisionObject* obj = ctrl->GetCollisionObject(); @@ -469,8 +482,6 @@ void CcdPhysicsEnvironment::AddCcdPhysicsController(CcdPhysicsController* ctrl) if (body) body->setGravity( m_gravity ); - m_controllers.insert(ctrl); - if (body) { //use explicit group/filter for finer control over collision in bullet => near/radar sensor @@ -505,10 +516,32 @@ void CcdPhysicsEnvironment::AddCcdPhysicsController(CcdPhysicsController* ctrl) bool CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController* ctrl) { + // if the physics controller is already removed we do nothing + if (!m_controllers.erase(ctrl)) { + return false; + } + + /* In the case of compound child controller which use collision callbacks + * we remove it from the m_triggerControllers list but leave m_registerCount + * to know in AddCcdPhysicsController if we have to add it in m_triggerControllers + * and to avoid an useless added in RequestCollisionCallback, indeed we can't register + * more than one time a controller. + */ + if (ctrl->Registered()) { + m_triggerControllers.erase(ctrl); + } + //also remove constraint btRigidBody* body = ctrl->GetRigidBody(); if (body) { + 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 = ctrl->getCcdConstraintRef(i); @@ -548,13 +581,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) @@ -562,6 +590,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) { @@ -575,6 +604,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); } @@ -586,43 +618,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(); @@ -636,6 +631,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()) @@ -671,6 +671,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() { @@ -752,8 +765,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++) { @@ -1156,17 +1169,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; @@ -2188,15 +2192,8 @@ 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) @@ -2211,7 +2208,7 @@ bool CcdPhysicsEnvironment::RemoveCollisionCallback(PHY_IPhysicsController* ctrl void CcdPhysicsEnvironment::RemoveSensor(PHY_IPhysicsController* ctrl) { - DisableCcdPhysicsController((CcdPhysicsController*)ctrl); + RemoveCcdPhysicsController((CcdPhysicsController*)ctrl); } void CcdPhysicsEnvironment::AddTouchCallback(int response_class, PHY_ResponseCallback callback, void *user) @@ -2644,9 +2641,6 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl if (!rb0) return 0; - // If either of the controllers is missing, we can't do anything. - if (!c0 || !c1) return 0; - btVector3 pivotInB = rb1 ? rb1->getCenterOfMassTransform().inverse()(rb0->getCenterOfMassTransform()(pivotInA)) : rb0->getCenterOfMassTransform() * pivotInA; btVector3 axisInA(axisX,axisY,axisZ); @@ -2658,6 +2652,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; @@ -2686,6 +2682,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) @@ -2739,7 +2738,7 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl *rb0,s_fixedObject2, frameInA,frameInB,useReferenceFrameA); } - + if (genericConstraint) { //m_constraints.push_back(genericConstraint); @@ -2756,6 +2755,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; @@ -2807,7 +2809,7 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl *rb0,s_fixedObject2, frameInA,frameInB); } - + if (coneTwistContraint) { //m_constraints.push_back(genericConstraint); @@ -2830,6 +2832,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) @@ -3517,20 +3522,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); } @@ -3591,3 +3599,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..94aea215478 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> @@ -52,6 +54,7 @@ class btOverlappingPairCache; class btIDebugDraw; 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. @@ -131,8 +134,7 @@ protected: 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 @@ -220,16 +222,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,6 +282,10 @@ 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: |