BGE bug #17491 fixed: BGE, Dupli instance with different scale, massive slowdown.
authorBenoit Bolsee <benoit.bolsee@online.be>
Thu, 21 Aug 2008 15:19:54 +0000 (15:19 +0000)
committerBenoit Bolsee <benoit.bolsee@online.be>
Thu, 21 Aug 2008 15:19:54 +0000 (15:19 +0000)
The root cause of this bug is the fact that Bullet shapes
are shared between duplicated game objects. As the physics
object scale is stored in the shape, all duplicas must
have the same scale otherwise the physics representation
is incorrect.
This fix introduces a mechanism to duplicate shapes at
runtime so that Bullet shapes are not shared anymore.
The drawback is an increased memory consuption.
A reference count mechanism will be introduced in a
later revision to keep Bullet shape shared between
duplicas that have the same scale.

projectfiles_vc7/gameengine/physics/PHY_Physics/PHY_Bullet/PHY_Bullet.vcproj
source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp
source/gameengine/Ketsji/KX_Scene.cpp
source/gameengine/Ketsji/KX_Scene.h
source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
source/gameengine/Physics/Bullet/CcdPhysicsController.h
source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
source/gameengine/Physics/common/PHY_DynamicTypes.h

index 9a807f2d39a692558ae7de61fed8a296a7b8e64a..a2bd76897bc5d4ca3b97212860e4398099dd911b 100644 (file)
                        <Tool
                                Name="VCCLCompilerTool"
                                Optimization="0"
-                               AdditionalIncludeDirectories="..\..\..\..\..\..\build\msvc_7\intern\moto\include;..\..\..\..\..\..\build\msvc_7\extern\bullet\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet"
+                               AdditionalIncludeDirectories="..\..\..\..\..\..\build\msvc_7\intern\moto\include;..\..\..\..\..\..\build\msvc_7\intern\string\include;..\..\..\..\..\..\build\msvc_7\extern\bullet\include;..\..\..\..\..\source\gameengine\Physics\common;..\..\..\..\..\source\gameengine\Physics\Bullet;..\..\..\..\..\source\gameengine\Rasterizer;..\..\..\..\..\source\kernel\gen_system"
                                PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
                                MinimalRebuild="FALSE"
                                BasicRuntimeChecks="3"
index e0cd5a3bc9e458431de5624a0a5c0e6bc465873d..c95ab954022dfd40ca69c1249788f997cb705d53 100644 (file)
@@ -680,188 +680,6 @@ void      KX_ConvertODEEngineObject(KX_GameObject* gameobj,
 
 
 // forward declarations
-static btCollisionShape* CreateBulletShapeFromMesh(RAS_MeshObject* meshobj, bool polytope)
-{
-       if (!meshobj)
-               return 0;
-
-       btCollisionShape* collisionMeshShape = 0;
-       btConvexHullShape* convexHullShape = 0;
-       btTriangleMeshShape* concaveShape = 0;
-
-       btTriangleMesh* collisionMeshData = 0;
-
-       //see if there is any polygons, if not, bail out.
-
-       int numPoints = 0;
-       btVector3* points = 0;
-
-       // Mesh has no polygons!
-       int numpolys = meshobj->NumPolygons();
-       if (!numpolys)
-       {
-               return NULL;
-       }
-
-       // Count the number of collision polygons and check they all come from the same 
-       // vertex array
-       int numvalidpolys = 0;
-       int vtxarray = -1;
-       RAS_IPolyMaterial *poly_material = NULL;
-       bool reinstance = true;
-
-       for (int p=0; p<numpolys; p++)
-       {
-               RAS_Polygon* poly = meshobj->GetPolygon(p);
-
-               // only add polygons that have the collisionflag set
-               if (poly->IsCollider())
-               {
-                       // check polygon is from the same vertex array
-                       if (poly->GetVertexIndexBase().m_vtxarray != vtxarray)
-                       {
-                               if (vtxarray < 0)
-                                       vtxarray = poly->GetVertexIndexBase().m_vtxarray;
-                               else
-                               {
-                                       reinstance = false;
-                                       vtxarray = -1;
-                               }
-                       }
-
-                       // check poly is from the same material
-                       if (poly->GetMaterial()->GetPolyMaterial() != poly_material)
-                       {
-                               if (poly_material)
-                               {
-                                       reinstance = false;
-                                       poly_material = NULL;
-                               }
-                               else
-                                       poly_material = poly->GetMaterial()->GetPolyMaterial();
-                       }
-
-                       // count the number of collision polys
-                       numvalidpolys++;
-
-                       // We have one collision poly, and we can't reinstance, so we
-                       // might as well break here.
-                       if (!reinstance)
-                               break;
-               }
-       }
-
-       // No collision polygons
-       if (numvalidpolys < 1)
-               return NULL;
-
-
-       if (polytope)
-       {
-               convexHullShape = new btConvexHullShape(&points[0].getX(),numPoints);
-               collisionMeshShape = convexHullShape;
-       } else
-       {
-               collisionMeshData = new btTriangleMesh();
-//             concaveShape = new btTriangleMeshShape(collisionMeshData);
-               //collisionMeshShape = concaveShape;
-
-       }
-
-
-       numvalidpolys = 0;
-
-       for (int p2=0; p2<numpolys; p2++)
-       {
-               RAS_Polygon* poly = meshobj->GetPolygon(p2);
-
-               // only add polygons that have the collisionflag set
-               if (poly->IsCollider())
-               {   
-                       //Bullet can raycast any shape, so
-                       if (polytope)
-                       {
-                               for (int i=0;i<poly->VertexCount();i++)
-                               {
-                                       const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
-                                               poly->GetVertexIndexBase().m_indexarray[i],
-                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
-                                       btPoint3 point(vtx[0],vtx[1],vtx[2]);
-                                       convexHullShape->addPoint(point);
-                               }
-                               if (poly->VertexCount())
-                                       numvalidpolys++;
-
-                       } else
-                       {
-                               {
-                                       const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
-                                               poly->GetVertexIndexBase().m_indexarray[2],
-                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
-                                       btPoint3 vertex0(vtx[0],vtx[1],vtx[2]);
-                                       vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
-                                               poly->GetVertexIndexBase().m_indexarray[1],
-                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
-                                       btPoint3 vertex1(vtx[0],vtx[1],vtx[2]);
-                                       vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
-                                               poly->GetVertexIndexBase().m_indexarray[0],
-                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
-                                       btPoint3 vertex2(vtx[0],vtx[1],vtx[2]);
-                                       collisionMeshData->addTriangle(vertex0,vertex1,vertex2);
-                                       numvalidpolys++;
-                               }
-                               if (poly->VertexCount() == 4)
-                               {
-                                       const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
-                                               poly->GetVertexIndexBase().m_indexarray[3],
-                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
-                                       btPoint3 vertex0(vtx[0],vtx[1],vtx[2]);
-                                       vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
-                                               poly->GetVertexIndexBase().m_indexarray[2],
-                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
-                                       btPoint3 vertex1(vtx[0],vtx[1],vtx[2]);
-                                       vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
-                                               poly->GetVertexIndexBase().m_indexarray[0],
-                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
-                                       btPoint3 vertex2(vtx[0],vtx[1],vtx[2]);
-                                       collisionMeshData->addTriangle(vertex0,vertex1,vertex2);
-                                       numvalidpolys++;
-                               }
-
-                       }               
-               }
-       }
-
-
-
-       if (numvalidpolys > 0)
-       {
-               
-               if (!polytope)
-               {
-                       bool useQuantization = true;
-                       concaveShape = new btBvhTriangleMeshShape( collisionMeshData, useQuantization );
-                       //concaveShape = new btTriangleMeshShape( collisionMeshData );
-
-                       concaveShape->recalcLocalAabb();
-                       if (collisionMeshShape)
-                               delete collisionMeshShape;
-                       collisionMeshShape = concaveShape;
-
-               } 
-               
-               
-
-               return collisionMeshShape;
-       }
-       if (collisionMeshShape)
-               delete collisionMeshShape;
-       if (collisionMeshData)
-               delete collisionMeshData;
-       return NULL;
-
-}
-
 
 void   KX_ConvertBulletObject( class   KX_GameObject* gameobj,
        class   RAS_MeshObject* meshobj,
@@ -878,6 +696,7 @@ void        KX_ConvertBulletObject( class   KX_GameObject* gameobj,
        bool isbulletdyna = false;
        CcdConstructionInfo ci;
        class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
+       class CcdShapeConstructionInfo *shapeInfo = new CcdShapeConstructionInfo();
 
        
 
@@ -894,120 +713,80 @@ void     KX_ConvertBulletObject( class   KX_GameObject* gameobj,
        ci.m_gravity = btVector3(0,0,0);
        ci.m_localInertiaTensor =btVector3(0,0,0);
        ci.m_mass = objprop->m_dyna ? shapeprops->m_mass : 0.f;
+       shapeInfo->m_radius = objprop->m_radius;
        isbulletdyna = objprop->m_dyna;
        
        ci.m_localInertiaTensor = btVector3(ci.m_mass/3.f,ci.m_mass/3.f,ci.m_mass/3.f);
        
-       btTransform trans;
-       trans.setIdentity();
-       
        btCollisionShape* bm = 0;
 
        switch (objprop->m_boundclass)
        {
        case KX_BOUNDSPHERE:
                {
-                       float radius = objprop->m_radius;
-                       btVector3 inertiaHalfExtents (
-                               radius,
-                               radius,
-                               radius);
+                       //float radius = objprop->m_radius;
+                       //btVector3 inertiaHalfExtents (
+                       //      radius,
+                       //      radius,
+                       //      radius);
                        
                        //blender doesn't support multisphere, but for testing:
 
                        //bm = new MultiSphereShape(inertiaHalfExtents,,&trans.getOrigin(),&radius,1);
-                       bm = new btSphereShape(objprop->m_radius);
-                       bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
+                       shapeInfo->m_shapeType = PHY_SHAPE_SPHERE;
+                       bm = shapeInfo->CreateBulletShape();
                        break;
                };
        case KX_BOUNDBOX:
                {
-                       MT_Vector3 halfExtents (
+                       shapeInfo->m_halfExtend.setValue(
                                objprop->m_boundobject.box.m_extends[0],
-                       objprop->m_boundobject.box.m_extends[1],
-                       objprop->m_boundobject.box.m_extends[2]);
-
-                       halfExtents /= 2.f;
-
-                       //btVector3 he (halfExtents[0]-CONVEX_DISTANCE_MARGIN ,halfExtents[1]-CONVEX_DISTANCE_MARGIN ,halfExtents[2]-CONVEX_DISTANCE_MARGIN );
-                       //he = he.absolute();
-
-                       btVector3 he (halfExtents[0],halfExtents[1],halfExtents[2]);
-                       he = he.absolute();
-
+                               objprop->m_boundobject.box.m_extends[1],
+                               objprop->m_boundobject.box.m_extends[2]);
 
-                       bm = new btBoxShape(he);
-                       bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
+                       shapeInfo->m_halfExtend /= 2.0;
+                       shapeInfo->m_halfExtend = shapeInfo->m_halfExtend.absolute();
+                       shapeInfo->m_shapeType = PHY_SHAPE_BOX;
+                       bm = shapeInfo->CreateBulletShape();
                        break;
                };
        case KX_BOUNDCYLINDER:
                {
-                       btVector3 halfExtents (
+                       shapeInfo->m_halfExtend.setValue(
                                objprop->m_boundobject.c.m_radius,
                                objprop->m_boundobject.c.m_radius,
                                objprop->m_boundobject.c.m_height * 0.5f
                        );
-                       bm = new btCylinderShapeZ(halfExtents);
-                       bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
-
+                       shapeInfo->m_shapeType = PHY_SHAPE_CYLINDER;
+                       bm = shapeInfo->CreateBulletShape();
                        break;
                }
 
-               case KX_BOUNDCONE:
+       case KX_BOUNDCONE:
                {
-                               btVector3 halfExtents (objprop->m_boundobject.box.m_extends[0],
-                               objprop->m_boundobject.box.m_extends[1],
-                               objprop->m_boundobject.box.m_extends[2]);
-
-
-                               halfExtents /= 2.f;
-
-                               bm = new btConeShapeZ(objprop->m_boundobject.c.m_radius,objprop->m_boundobject.c.m_height);
-                               bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
-
+                       shapeInfo->m_radius = objprop->m_boundobject.c.m_radius;
+                       shapeInfo->m_height = objprop->m_boundobject.c.m_height;
+                       shapeInfo->m_shapeType = PHY_SHAPE_CONE;
+                       bm = shapeInfo->CreateBulletShape();
                        break;
                }
-               case KX_BOUNDPOLYTOPE:
-                       {
-                               bm = CreateBulletShapeFromMesh(meshobj,true);
-                               if (bm)
-                               {
-                                       bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
-                               }
-                               break;
-                       }
-               case KX_BOUNDMESH:
-                       {
-                               if (!ci.m_mass)
-                               {                               
-                                       bm = CreateBulletShapeFromMesh(meshobj,false);
-                                       ci.m_localInertiaTensor.setValue(0.f,0.f,0.f);
-                                       //no moving concave meshes, so don't bother calculating inertia
-                                       //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
-                               }
-
-                               break;
-                       }
-
-       default:
-               //interpret the shape as a concave triangle-mesh
+       case KX_BOUNDPOLYTOPE:
                {
-                       if (meshobj)
-                       {
-                               bm = CreateBulletShapeFromMesh(meshobj,false);
-                               ci.m_localInertiaTensor.setValue(0.f,0.f,0.f);
-
-                       //      assert(0);
-
-                                       /*
-                               meshobj->ScheduleCollisionPolygons();
-
-                               KX_DeformableMesh* gfxmesh = new KX_DeformableMesh(meshobj);
-                               gfxmesh->sendFixedMapping();
-                               //trianglemesh
-                               bm = new TriangleMeshInterface(gfxmesh,trans);
-                               */
+                       shapeInfo->SetMesh(meshobj, true);
+                       bm = shapeInfo->CreateBulletShape();
+                       break;
+               }
+       case KX_BOUNDMESH:
+               {
+                       if (!ci.m_mass)
+                       {                               
+                               shapeInfo->SetMesh(meshobj, false);
+                               bm = shapeInfo->CreateBulletShape();
+                               //no moving concave meshes, so don't bother calculating inertia
+                               //bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
                        }
+
+                       break;
                }
        }
 
@@ -1017,10 +796,13 @@ void     KX_ConvertBulletObject( class   KX_GameObject* gameobj,
        if (!bm)
        {
                delete motionstate;
+               delete shapeInfo;
                return;
        }
 
        bm->setMargin(0.06);
+       if (objprop->m_dyna)
+               bm->calculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
 
 
 
@@ -1030,31 +812,28 @@ void     KX_ConvertBulletObject( class   KX_GameObject* gameobj,
                        //take relative transform into account!
                        KX_BulletPhysicsController* parentCtrl = (KX_BulletPhysicsController*)objprop->m_dynamic_parent->GetPhysicsController();
                        assert(parentCtrl);
+                       CcdShapeConstructionInfo* parentShapeInfo = parentCtrl->GetShapeInfo();
                        btRigidBody* rigidbody = parentCtrl->GetRigidBody();
                        btCollisionShape* colShape = rigidbody->getCollisionShape();
                        assert(colShape->isCompound());
                        btCompoundShape* compoundShape = (btCompoundShape*)colShape;
-                       btTransform childTrans;
-                       childTrans.setIdentity();
-                       NodeList& children = objprop->m_dynamic_parent->GetSGNode()->GetSGChildren();
 
                        MT_Point3 childPos = gameobj->GetSGNode()->GetLocalPosition();
                        MT_Matrix3x3 childRot = gameobj->GetSGNode()->GetLocalOrientation();
                        MT_Vector3 childScale = gameobj->GetSGNode()->GetLocalScale();
 
                        bm->setLocalScaling(btVector3(childScale.x(),childScale.y(),childScale.z()));
-                       childTrans.setOrigin(btVector3(childPos.x(),childPos.y(),childPos.z()));
+                       shapeInfo->m_childTrans.setOrigin(btVector3(childPos.x(),childPos.y(),childPos.z()));
                        float rotval[12];
                        childRot.getValue(rotval);
                        btMatrix3x3 newRot;
                        newRot.setValue(rotval[0],rotval[1],rotval[2],rotval[4],rotval[5],rotval[6],rotval[8],rotval[9],rotval[10]);
                        newRot = newRot.transpose();
 
-                       childTrans.setBasis(newRot);
-                               
-
-                       compoundShape->addChildShape(childTrans,bm);
-                       kxscene->AddShape(bm);
+                       shapeInfo->m_childTrans.setBasis(newRot);
+                       parentShapeInfo->AddShape(shapeInfo);   
+                       
+                       compoundShape->addChildShape(shapeInfo->m_childTrans,bm);
                        //do some recalc?
                        //recalc inertia for rigidbody
                        if (!rigidbody->isStaticOrKinematicObject())
@@ -1069,15 +848,16 @@ void     KX_ConvertBulletObject( class   KX_GameObject* gameobj,
 
                if (objprop->m_hasCompoundChildren)
                {
-                       //replace shape by compoundShape
+                       // create a compound shape info
+                       CcdShapeConstructionInfo *compoundShapeInfo = new CcdShapeConstructionInfo();
+                       compoundShapeInfo->m_shapeType = PHY_SHAPE_COMPOUND;
+                       compoundShapeInfo->AddShape(shapeInfo);
+                       // create the compound shape manually as we already have the child shape
                        btCompoundShape* compoundShape = new btCompoundShape();
-                       btTransform identTrans;
-                       identTrans.setIdentity();
-                       compoundShape->addChildShape(identTrans,bm);
-                       //note abount compoundShape: Bullet does not delete the child shapes when 
-                       //the compound shape is deleted, so insert also the child shapes 
-                       kxscene->AddShape(bm);
+                       compoundShape->addChildShape(shapeInfo->m_childTrans,bm);
+                       // now replace the shape
                        bm = compoundShape;
+                       shapeInfo = compoundShapeInfo;
                }
 
 
@@ -1113,6 +893,7 @@ void       KX_ConvertBulletObject( class   KX_GameObject* gameobj,
 
 
        ci.m_collisionShape = bm;
+       ci.m_shapeInfo = shapeInfo;
        ci.m_friction = smmaterial->m_friction;//tweak the friction a bit, so the default 0.5 works nice
        ci.m_restitution = smmaterial->m_restitution;
        ci.m_physicsEnv = env;
@@ -1125,8 +906,9 @@ void       KX_ConvertBulletObject( class   KX_GameObject* gameobj,
        ci.m_collisionFilterMask = (isbulletdyna) ? short(CcdConstructionInfo::AllFilter) : short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter);
        ci.m_bRigid = objprop->m_dyna && objprop->m_angular_rigidbody;
        KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna);
-       //remember that we created a shape so that we can delete it when the scene is removed (bullet will not delete it) 
-       kxscene->AddShape(bm);
+       // shapeInfo is reference counted, decrement now as we don't use it anymore
+       if (shapeInfo)
+               shapeInfo->Release();
 
        if (objprop->m_in_active_layer)
        {
index 2828663c63df602a45cdd716af1c97212313776d..ab3692d2411b1402a760ea45731e3888bcac6076 100644 (file)
@@ -234,40 +234,9 @@ KX_Scene::~KX_Scene()
        {
                delete m_bucketmanager;
        }
-#ifdef USE_BULLET
-       // This is a fix for memory leaks in bullet: the collision shapes is not destroyed 
-       // when the physical controllers are destroyed. The reason is that shapes are shared
-       // between replicas of an object. There is no reference count in Bullet so the
-       // only workaround that does not involve changes in Bullet is to save in this array
-       // the list of shapes that are created when the scene is created (see KX_ConvertPhysicsObjects.cpp)
-       class btCollisionShape* shape;
-       class btTriangleMeshShape* meshShape;
-       vector<class btCollisionShape*>::iterator it = m_shapes.begin();
-       while (it != m_shapes.end()) {
-               shape = *it;
-               if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)
-               {
-                       meshShape = static_cast<btTriangleMeshShape*>(shape);
-                       // shapes based on meshes use an interface that contains the vertices.
-                       // Again the idea is to be able to share the interface between shapes but
-                       // this is not used in Blender: each base object will have its own interface 
-                       btStridingMeshInterface* meshInterface = meshShape->getMeshInterface();
-                       if (meshInterface)
-                               delete meshInterface;
-               }
-               delete shape;
-               it++;
-       }
-#endif
        //Py_DECREF(m_attrlist);
 }
 
-void KX_Scene::AddShape(class btCollisionShape*shape)
-{
-       m_shapes.push_back(shape);
-}
-
-
 void KX_Scene::SetProjectionMatrix(MT_CmMatrix4x4& pmat)
 {
        m_projectionmat = pmat;
index 80a2abe287ad2e464ecf4a4d68fab9537273aeb2..1c56dd1ee55ef794e68b0510b311af63af06310e 100644 (file)
@@ -121,11 +121,6 @@ protected:
         * The set of cameras for this scene
         */
        list<class KX_Camera*>       m_cameras;
-       /**
-        * The set of bullet shapes that must be deleted at the end of the scene
-        * to avoid memory leak (not deleted by bullet because shape are shared between replicas)
-        */
-       vector<class btCollisionShape*> m_shapes;
        /**
         * Various SCA managers used by the scene
         */
@@ -322,7 +317,6 @@ public:
        int NewRemoveObject(CValue* gameobj);
        void ReplaceMesh(CValue* gameobj,
                                         void* meshobj);
-       void AddShape(class btCollisionShape* shape);
        /**
         * @section Logic stuff
         * Initiate an update of the logic system.
index b872fae61388750bd1cb8eeea4e3c2a7540d9621..a28af5f963559ccaee668dc349920f9409f5ac67 100644 (file)
@@ -18,6 +18,7 @@ subject to the following restrictions:
 
 #include "PHY_IMotionState.h"
 #include "CcdPhysicsEnvironment.h"
+#include "RAS_MeshObject.h"
 
 
 class BP_Proxy;
@@ -44,7 +45,14 @@ CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci)
        m_newClientInfo = 0;
        m_registerCount = 0;
                
+       // copy pointers locally to allow smart release
        m_MotionState = ci.m_MotionState;
+       m_collisionShape = ci.m_collisionShape;
+       // shape info is shared, increment ref count
+       m_shapeInfo = ci.m_shapeInfo;
+       if (m_shapeInfo)
+               m_shapeInfo->AddRef();
+       
        m_bulletMotionState = 0;
        
        
@@ -116,7 +124,7 @@ void CcdPhysicsController::CreateRigidbody()
 
        m_body = new btRigidBody(m_cci.m_mass,
                m_bulletMotionState,
-               m_cci.m_collisionShape,
+               m_collisionShape,
                m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor,
                m_cci.m_linearDamping,m_cci.m_angularDamping,
                m_cci.m_friction,m_cci.m_restitution);
@@ -144,6 +152,19 @@ void CcdPhysicsController::CreateRigidbody()
        }
 }
 
+static void DeleteBulletShape(btCollisionShape* shape)
+{
+       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;
+       }
+       delete shape;
+}
+
 CcdPhysicsController::~CcdPhysicsController()
 {
        //will be reference counted, due to sharing
@@ -155,6 +176,27 @@ CcdPhysicsController::~CcdPhysicsController()
        if (m_bulletMotionState)
                delete m_bulletMotionState;
        delete m_body;
+
+       if (m_collisionShape)
+       {
+               // collision shape is always unique to the controller, can delete it here
+               if (m_collisionShape->isCompound())
+               {
+                       // bullet does not delete the child shape, must do it here
+                       btCompoundShape* compoundShape = (btCompoundShape*)m_collisionShape;
+                       int numChild = compoundShape->getNumChildShapes();
+                       for (int i=numChild-1 ; i >= 0; i--)
+                       {
+                               btCollisionShape* childShape = compoundShape->getChildShape(i);
+                               DeleteBulletShape(childShape);
+                       }
+               }
+               DeleteBulletShape(m_collisionShape);
+       }
+       if (m_shapeInfo)
+       {
+               m_shapeInfo->Release();
+       }
 }
 
 
@@ -219,11 +261,33 @@ void              CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionsta
 {
        m_MotionState = motionstate;
        m_registerCount = 0;
-       
+       m_collisionShape = NULL;
+
+       // always create a new shape to avoid scaling bug
+       if (m_shapeInfo)
+       {
+               m_shapeInfo->AddRef();
+               m_collisionShape = m_shapeInfo->CreateBulletShape();
+
+               if (m_collisionShape)
+               {
+                       // new shape has no scaling, apply initial scaling
+                       m_collisionShape->setLocalScaling(m_cci.m_scaling);
+                       if (m_cci.m_mass)
+                               m_collisionShape->calculateLocalInertia(m_cci.m_mass, m_cci.m_localInertiaTensor);
+               }
+       }
 
        m_body = 0;
        CreateRigidbody();
-       
+
+       if (m_body)
+       {
+               if (m_cci.m_mass)
+               {
+                       m_body->setMassProps(m_cci.m_mass, m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor);
+               } 
+       }                       
        m_cci.m_physicsEnv->addCcdPhysicsController(this);
 
 
@@ -597,29 +661,32 @@ bool CcdPhysicsController::wantsSleeping()
 
 PHY_IPhysicsController*        CcdPhysicsController::GetReplica()
 {
-       //very experimental, shape sharing is not implemented yet.
-       //just support btSphereShape/ConeShape for now
-
+       // This is used only to replicate Near and Radar sensor controllers
+       // The replication of object physics controller is done in KX_BulletPhysicsController::GetReplica()
        CcdConstructionInfo cinfo = m_cci;
-       if (cinfo.m_collisionShape)
+       if (m_shapeInfo)
+       {
+               // This situation does not normally happen
+               cinfo.m_collisionShape = m_shapeInfo->CreateBulletShape();
+       } 
+       else if (m_collisionShape)
        {
-               switch (cinfo.m_collisionShape->getShapeType())
+               switch (m_collisionShape->getShapeType())
                {
                case SPHERE_SHAPE_PROXYTYPE:
                        {
-                               btSphereShape* orgShape = (btSphereShape*)cinfo.m_collisionShape;
+                               btSphereShape* orgShape = (btSphereShape*)m_collisionShape;
                                cinfo.m_collisionShape = new btSphereShape(*orgShape);
                                break;
                        }
 
-                       case CONE_SHAPE_PROXYTYPE:
+               case CONE_SHAPE_PROXYTYPE:
                        {
-                               btConeShape* orgShape = (btConeShape*)cinfo.m_collisionShape;
+                               btConeShape* orgShape = (btConeShape*)m_collisionShape;
                                cinfo.m_collisionShape = new btConeShape(*orgShape);
                                break;
                        }
 
-
                default:
                        {
                                return 0;
@@ -628,6 +695,7 @@ PHY_IPhysicsController*     CcdPhysicsController::GetReplica()
        }
 
        cinfo.m_MotionState = new DefaultMotionState();
+       cinfo.m_shapeInfo = m_shapeInfo;
 
        CcdPhysicsController* replica = new CcdPhysicsController(cinfo);
        return replica;
@@ -689,3 +757,198 @@ void      DefaultMotionState::calculateWorldTransformations()
 
 }
 
+// Shape constructor
+bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, bool polytope)
+{
+       // assume no shape information
+       m_shapeType = PHY_SHAPE_NONE;
+       m_vertexArray.clear();
+
+       if (!meshobj)
+               return false;
+
+       // Mesh has no polygons!
+       int numpolys = meshobj->NumPolygons();
+       if (!numpolys)
+       {
+               return false;
+       }
+
+       // check that we have at least one colliding polygon
+       int numvalidpolys = 0;
+
+       for (int p=0; p<numpolys; p++)
+       {
+               RAS_Polygon* poly = meshobj->GetPolygon(p);
+
+               // only add polygons that have the collisionflag set
+               if (poly->IsCollider())
+               {
+                       numvalidpolys++;
+                       break;
+               }
+       }
+
+       // No collision polygons
+       if (numvalidpolys < 1)
+               return false;
+
+       m_shapeType = (polytope) ? PHY_SHAPE_POLYTOPE : PHY_SHAPE_MESH;
+
+       numvalidpolys = 0;
+
+       for (int p2=0; p2<numpolys; p2++)
+       {
+               RAS_Polygon* poly = meshobj->GetPolygon(p2);
+
+               // only add polygons that have the collisionflag set
+               if (poly->IsCollider())
+               {   
+                       //Bullet can raycast any shape, so
+                       if (polytope)
+                       {
+                               for (int i=0;i<poly->VertexCount();i++)
+                               {
+                                       const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
+                                               poly->GetVertexIndexBase().m_indexarray[i],
+                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+                                       btPoint3 point(vtx[0],vtx[1],vtx[2]);
+                                       m_vertexArray.push_back(point);
+                                       numvalidpolys++;
+                               }
+                       } else
+                       {
+                               {
+                                       const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
+                                               poly->GetVertexIndexBase().m_indexarray[2],
+                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+                                       btPoint3 vertex0(vtx[0],vtx[1],vtx[2]);
+                                       vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
+                                               poly->GetVertexIndexBase().m_indexarray[1],
+                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+                                       btPoint3 vertex1(vtx[0],vtx[1],vtx[2]);
+                                       vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
+                                               poly->GetVertexIndexBase().m_indexarray[0],
+                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+                                       btPoint3 vertex2(vtx[0],vtx[1],vtx[2]);
+                                       m_vertexArray.push_back(vertex0);
+                                       m_vertexArray.push_back(vertex1);
+                                       m_vertexArray.push_back(vertex2);
+                                       numvalidpolys++;
+                               }
+                               if (poly->VertexCount() == 4)
+                               {
+                                       const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
+                                               poly->GetVertexIndexBase().m_indexarray[3],
+                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+                                       btPoint3 vertex0(vtx[0],vtx[1],vtx[2]);
+                                       vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
+                                               poly->GetVertexIndexBase().m_indexarray[2],
+                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+                                       btPoint3 vertex1(vtx[0],vtx[1],vtx[2]);
+                                       vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
+                                               poly->GetVertexIndexBase().m_indexarray[0],
+                                               poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
+                                       btPoint3 vertex2(vtx[0],vtx[1],vtx[2]);
+                                       m_vertexArray.push_back(vertex0);
+                                       m_vertexArray.push_back(vertex1);
+                                       m_vertexArray.push_back(vertex2);
+                                       numvalidpolys++;
+                               }
+                       }               
+               }
+       }
+
+       if (!numvalidpolys)
+       {
+               // should not happen
+               m_shapeType = PHY_SHAPE_NONE;
+               return false;
+       }
+       return true;
+}
+
+btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape()
+{
+       btCollisionShape* collisionShape = 0;
+       btTriangleMeshShape* concaveShape = 0;
+       btTriangleMesh* collisionMeshData = 0;
+       btCompoundShape* compoundShape = 0;
+       CcdShapeConstructionInfo* nextShapeInfo;
+
+       switch (m_shapeType) 
+       {
+       case PHY_SHAPE_BOX:
+               collisionShape = new btBoxShape(m_halfExtend);
+               break;
+
+       case PHY_SHAPE_SPHERE:
+               collisionShape = new btSphereShape(m_radius);
+               break;
+
+       case PHY_SHAPE_CYLINDER:
+               collisionShape = new btCylinderShapeZ(m_halfExtend);
+               break;
+
+       case PHY_SHAPE_CONE:
+               collisionShape = new btConeShapeZ(m_radius, m_height);
+               break;
+
+       case PHY_SHAPE_POLYTOPE:
+               collisionShape = new btConvexHullShape(&m_vertexArray.begin()->getX(), m_vertexArray.size());
+               break;
+
+       case PHY_SHAPE_MESH:
+               collisionMeshData = new btTriangleMesh();
+               // m_vertexArray is necessarily a multiple of 3
+               for (std::vector<btPoint3>::iterator it=m_vertexArray.begin(); it != m_vertexArray.end(); )
+               {
+            collisionMeshData->addTriangle(*it++,*it++,*it++);
+               }
+               concaveShape = new btBvhTriangleMeshShape( collisionMeshData, true );
+               concaveShape->recalcLocalAabb();
+               collisionShape = concaveShape;
+               break;
+
+       case PHY_SHAPE_COMPOUND:
+               if (m_nextShape)
+               {
+                       compoundShape = new btCompoundShape();
+                       for (nextShapeInfo=m_nextShape; nextShapeInfo; nextShapeInfo = nextShapeInfo->m_nextShape)
+                       {
+                               collisionShape = nextShapeInfo->CreateBulletShape();
+                               if (collisionShape)
+                               {
+                                       compoundShape->addChildShape(nextShapeInfo->m_childTrans, collisionShape);
+                               }
+                       }
+                       collisionShape = compoundShape;
+               }
+       }
+       return collisionShape;
+}
+
+void CcdShapeConstructionInfo::AddShape(CcdShapeConstructionInfo* shapeInfo)
+{
+       CcdShapeConstructionInfo* nextShape = this;
+       while (nextShape->m_nextShape != NULL)
+               nextShape = nextShape->m_nextShape;
+       nextShape->m_nextShape = shapeInfo;
+}
+
+CcdShapeConstructionInfo::~CcdShapeConstructionInfo()
+{
+       CcdShapeConstructionInfo* childShape = m_nextShape;
+
+       while (childShape)
+       {
+               CcdShapeConstructionInfo* nextShape = childShape->m_nextShape;
+               childShape->m_nextShape = NULL;
+               childShape->Release();
+               childShape = nextShape;
+       }
+       
+       m_vertexArray.clear();
+}
+
+
index 448e5622eff579fb0ba3f9d8142f437027cacd79..1e1a38aa2a6661bc52463866ca9e94e3abcb2739 100644 (file)
@@ -17,11 +17,14 @@ subject to the following restrictions:
 #ifndef BULLET2_PHYSICSCONTROLLER_H
 #define BULLET2_PHYSICSCONTROLLER_H
 
+#include <vector>
+
 #include "PHY_IPhysicsController.h"
 
 ///    PHY_IPhysicsController is the abstract simplified Interface to a physical object.
 ///    It contains the IMotionState and IDeformableMesh Interfaces.
 #include "btBulletDynamicsCommon.h"
+#include "LinearMath/btTransform.h"
 
 #include "PHY_IMotionState.h"
 
@@ -31,8 +34,66 @@ extern float gAngularSleepingTreshold;
 extern bool gDisableDeactivation;
 class CcdPhysicsEnvironment;
 class btMotionState;
+class RAS_MeshObject;
+class btCollisionShape;
+
+// Shape contructor
+// It contains all the information needed to create a simple bullet shape at runtime
+class CcdShapeConstructionInfo
+{
+public:
+       CcdShapeConstructionInfo() :
+               m_shapeType(PHY_SHAPE_NONE),
+               m_radius(1.0),
+               m_height(1.0),
+               m_halfExtend(0.f,0.f,0.f),
+               m_nextShape(NULL),
+               m_refCount(1)
+       {
+               m_childTrans.setIdentity();
+       }
 
+       ~CcdShapeConstructionInfo();
 
+       CcdShapeConstructionInfo* AddRef()
+       { 
+               m_refCount++;
+               return this;
+       }
+
+       int Release()
+       {
+               if (--m_refCount > 0)
+                       return m_refCount;
+               delete this;
+               return 0;
+       }
+
+       void AddShape(CcdShapeConstructionInfo* shapeInfo);
+
+       CcdShapeConstructionInfo* GetNextShape()
+       {
+               return m_nextShape;
+       }
+
+       bool SetMesh(RAS_MeshObject* mesh, bool polytope);
+
+       btCollisionShape* CreateBulletShape();
+
+       // member variables
+       PHY_ShapeType                   m_shapeType;
+       btScalar                                m_radius;
+       btScalar                                m_height;
+       btVector3                               m_halfExtend;
+       btTransform                             m_childTrans;
+       std::vector<btPoint3>   m_vertexArray;  // Contains both vertex array for polytope shape and
+                                                                                       // triangle array for concave mesh shape.
+                                                                                       // In this case a triangle is made of 3 consecutive points
+protected:
+       CcdShapeConstructionInfo* m_nextShape;  // for compound shape
+       int                                             m_refCount;             // this class is shared between replicas
+                                                                                       // keep track of users so that we can release it 
+};
 
 struct CcdConstructionInfo
 {
@@ -65,6 +126,7 @@ struct CcdConstructionInfo
                m_collisionFilterMask(AllFilter),
                m_collisionShape(0),
                m_MotionState(0),
+               m_shapeInfo(0),
                m_physicsEnv(0),
                m_inertiaFactor(1.f)
        {
@@ -89,8 +151,11 @@ struct CcdConstructionInfo
        short int       m_collisionFilterGroup;
        short int       m_collisionFilterMask;
 
+       ///these pointers are used as argument passing for the CcdPhysicsController constructor
+       ///and not anymore after that
        class btCollisionShape* m_collisionShape;
        class PHY_IMotionState* m_MotionState;
+       class CcdShapeConstructionInfo* m_shapeInfo;
        
        CcdPhysicsEnvironment*  m_physicsEnv; //needed for self-replication
        float   m_inertiaFactor;//tweak the inertia (hooked up to Blender 'formfactor'
@@ -106,6 +171,9 @@ class CcdPhysicsController : public PHY_IPhysicsController
        btRigidBody* m_body;
        class PHY_IMotionState*         m_MotionState;
        btMotionState*  m_bulletMotionState;
+       class btCollisionShape* m_collisionShape;
+       class CcdShapeConstructionInfo* m_shapeInfo;
+
        friend class CcdPhysicsEnvironment;     // needed when updating the controller
 
 
@@ -137,6 +205,7 @@ class CcdPhysicsController : public PHY_IPhysicsController
 
 
                btRigidBody* GetRigidBody() { return m_body;}
+               CcdShapeConstructionInfo* GetShapeInfo() { return m_shapeInfo; }
 
                btCollisionShape*       GetCollisionShape() { 
                        return m_body->getCollisionShape();
index dfbcf115fd7c764da0bcef63804216c1bfbba7e2..d8e05fab8390cd3cc615e03a988b52172a8b53b3 100644 (file)
@@ -1370,8 +1370,9 @@ int                       CcdPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl
 PHY_IPhysicsController* CcdPhysicsEnvironment::CreateConeController(float coneradius,float coneheight)
 {
        CcdConstructionInfo     cinfo;
-       //This is a memory leak: Bullet does not delete the shape and it cannot be added to 
-       //the KX_Scene.m_shapes list -- too bad but that's not a lot of data
+
+       // we don't need a CcdShapeConstructionInfo for this shape:
+       // it is simple enough for the standard copy constructor (see CcdPhysicsController::GetReplica)
        cinfo.m_collisionShape = new btConeShape(coneradius,coneheight);
        cinfo.m_MotionState = 0;
        cinfo.m_physicsEnv = this;
index c289b9d8bcb7c57bd0c11c91e39fe4d62db7f8cd..3b3e42c38d241e5be44936f441865247af08878c 100644 (file)
@@ -87,6 +87,18 @@ typedef enum PHY_ConstraintType {
 
 } PHY_ConstraintType;
 
+typedef enum PHY_ShapeType {
+       PHY_SHAPE_NONE,
+       PHY_SHAPE_BOX,
+       PHY_SHAPE_SPHERE,
+       PHY_SHAPE_CYLINDER,
+       PHY_SHAPE_CONE,
+       PHY_SHAPE_MESH,
+       PHY_SHAPE_POLYTOPE,
+       PHY_SHAPE_COMPOUND
+} PHY_ShapeType;
+
+
 typedef float  PHY_Vector3[3];
 
 #endif //__PHY_DYNAMIC_TYPES