Various mem leaks related to CValue reference count fixed
authorBenoit Bolsee <benoit.bolsee@online.be>
Sat, 1 Mar 2008 19:46:50 +0000 (19:46 +0000)
committerBenoit Bolsee <benoit.bolsee@online.be>
Sat, 1 Mar 2008 19:46:50 +0000 (19:46 +0000)
17 files changed:
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Converter/KX_ConvertActuators.cpp
source/gameengine/Converter/KX_ConvertControllers.cpp
source/gameengine/Converter/KX_ConvertProperties.cpp
source/gameengine/Converter/KX_ConvertSensors.cpp
source/gameengine/Expressions/Expression.cpp
source/gameengine/Expressions/Value.cpp
source/gameengine/GameLogic/SCA_IObject.cpp
source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
source/gameengine/GameLogic/SCA_LogicManager.cpp
source/gameengine/GameLogic/SCA_PropertyActuator.cpp
source/gameengine/Ketsji/KX_Camera.cpp
source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp
source/gameengine/Ketsji/KX_KetsjiEngine.cpp
source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp
source/gameengine/Ketsji/KX_Scene.cpp
source/gameengine/Ketsji/KX_Scene.h

index fde54025fc7c231cf150d88322ab25778a41e756..271385bb144c227256132bf6c5549c4c0febb0c2 100644 (file)
@@ -1514,7 +1514,8 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj,
                default:
                        break;
        }
-
+       delete shapeprops;
+       delete smmaterial;
 }
 
 
@@ -1599,7 +1600,8 @@ static KX_GameObject *gameobject_from_blenderobject(
                KX_Camera* gamecamera = gamecamera_from_bcamera(static_cast<Camera*>(ob->data), kxscene, converter);
                gameobj = gamecamera;
                
-               gamecamera->AddRef();
+               //don't add a reference: the camera list in kxscene->m_cameras is not released at the end
+               //gamecamera->AddRef();
                kxscene->AddCamera(gamecamera);
                
                break;
@@ -1845,6 +1847,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
        vector<parentChildLink> vec_parent_child;
        
        CListValue* objectlist = kxscene->GetObjectList();
+       CListValue* inactivelist = kxscene->GetInactiveList();
        CListValue* parentlist = kxscene->GetRootParentList();
        
        SCA_LogicManager* logicmgr = kxscene->GetLogicManager();
@@ -1852,7 +1855,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
        
        CListValue* logicbrick_conversionlist = new CListValue();
        
-       SG_TreeFactory tf;
+       //SG_TreeFactory tf;
        
        // Convert actions to actionmap
        bAction *curAct;
@@ -1990,19 +1993,35 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
                        if (isInActiveLayer)
                        {
                                objectlist->Add(gameobj->AddRef());
-                               tf.Add(gameobj->GetSGNode());
+                               //tf.Add(gameobj->GetSGNode());
                                
                                gameobj->NodeUpdateGS(0,true);
                                gameobj->Bucketize();
                                
                        }
+                       else
+                       {
+                               //we must store this object otherwise it will be deleted 
+                               //at the end of this function if it is not a root object
+                               inactivelist->Add(gameobj->AddRef());
+                       }
                        if (converter->addInitFromFrame){
                                gameobj->NodeSetLocalPosition(posPrev);
                                gameobj->NodeSetLocalOrientation(angor);
                        }
                                                
                }
-                       
+               /* Note about memory leak issues:
+                  When a CValue derived class is created, m_refcount is initialized to 1
+                  so the class must be released after being used to make sure that it won't 
+                  hang in memory. If the object needs to be stored for a long time, 
+                  use AddRef() so that this Release() does not free the object.
+                  Make sure that for any AddRef() there is a Release()!!!! 
+                  Do the same for any object derived from CValue, CExpression and NG_NetworkMessage
+                */
+               if (gameobj)
+                       gameobj->Release();
+
                base = base->next;
        }
 
index 89a07abe21dc45cdbbe1e72ebc65b70c47a6b177..f76a0fb82e5c5d090629869352dd0acba5632a13 100644 (file)
@@ -934,6 +934,8 @@ void BL_ConvertActuators(char* maggiename,
                        gameobj->AddActuator(baseact);
                        
                        converter->RegisterGameActuator(baseact, bact);
+                       // done with baseact, release it
+                       baseact->Release();
                }
                
                bact = bact->next;
index 5b30f5a4a2e0351ac748106f27e7335265f71437..b277af7dbc24bfe04825a872ea0ac6d7d9d1127a 100644 (file)
@@ -174,6 +174,8 @@ void BL_ConvertControllers(
                        gameobj->AddController(gamecontroller);
                        
                        converter->RegisterGameController(gamecontroller, bcontr);
+                       //done with gamecontroller
+                       gamecontroller->Release();
                }
                
                bcontr = bcontr->next;
index a1807732416a1f7e723e18cb6f83309ce38931a1..ebfb45066b734c12ae8dd17e98dc6290e4089018 100644 (file)
@@ -105,8 +105,9 @@ void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventMan
                        // set a subproperty called 'timer' so that 
                        // we can register the replica of this property 
                        // at the time a game object is replicated (AddObjectActuator triggers this)
-
-                       timeval->SetProperty("timer",new CBoolValue(true));
+                       CValue *bval = new CBoolValue(true);
+                       timeval->SetProperty("timer",bval);
+                       bval->Release();
                        if (isInActiveLayer)
                        {
                                timemgr->AddTimeProperty(timeval);
@@ -128,6 +129,8 @@ void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventMan
                        {
                                scene->AddDebugProperty(gameobj,STR_String(prop->name));
                        }
+                       // done with propval, release it
+                       propval->Release();
                }
 
                prop = prop->next;
index d9c49217042ab33a53a526698e43c7a5efabeb47..61759ddf6547414cbb11d9da912ff94f643d8583 100644 (file)
@@ -733,6 +733,8 @@ void BL_ConvertSensors(struct Object* blenderobject,
                                        logicmgr->RegisterToSensor(gamecont,gamesensor);
                                }
                        }
+                       // done with gamesensor
+                       gamesensor->Release();
                        
                }
                sens=sens->next;
index 5c5e1abea34f985b389c96f3477947dc18505292..f16f572c32228161b39ece4d553537f4ddeb6f07 100644 (file)
@@ -22,7 +22,9 @@
 //////////////////////////////////////////////////////////////////////
 // Construction/Destruction
 //////////////////////////////////////////////////////////////////////
-
+#ifdef _DEBUG
+//int gRefCountExpr;
+#endif
 CExpression::CExpression()// : m_cached_calculate(NULL)
 {
        m_refcount = 1;
index 48898dfc1f57473427e587dac4630c292aea6912..56208ab4ad505959f10ae9df9541a16707e0431f 100644 (file)
@@ -169,7 +169,28 @@ PyObject* CValue::PyGetName(PyObject* self,PyObject* args,PyObject* kwds)
        return pyname;
 }
 
+/*#define CVALUE_DEBUG*/
+#ifdef CVALUE_DEBUG
+int gRefCount;
+struct SmartCValueRef 
+{
+       CValue *m_ref;
+       int m_count;
+       SmartCValueRef(CValue *ref)
+       {
+               m_ref = ref;
+               m_count = gRefCount++;
+       }
+};
 
+#include <vector>
+
+std::vector<SmartCValueRef> gRefList;
+#endif
+
+#ifdef _DEBUG
+//int gRefCountValue;
+#endif
 
 CValue::CValue(PyTypeObject *T)
                : PyObjectPlus(T),
@@ -186,6 +207,12 @@ effect: constucts a CValue
 */
 {
        //debug(gRefCountValue++)       // debugging
+#ifdef _DEBUG
+       //gRefCountValue++;
+#ifdef CVALUE_DEBUG
+       gRefList.push_back(SmartCValueRef(this));
+#endif
+#endif
 }
 
 
@@ -199,6 +226,18 @@ effect: deletes the object
        ClearProperties();
 
        assertd (m_refcount==0);
+#ifdef CVALUE_DEBUG
+       std::vector<SmartCValueRef>::iterator it;
+       for (it=gRefList.begin(); it!=gRefList.end(); it++)
+       {
+               if (it->m_ref == this)
+               {
+                       *it = gRefList.back();
+                       gRefList.pop_back();
+                       break;
+               }
+       }
+#endif
 }
 
 
@@ -293,7 +332,7 @@ void CValue::SetProperty(const STR_String & name,CValue* ioProperty)
        }
        
        // Add property at end of array
-       (*m_pNamedPropertyArray)[name] = ioProperty;//->Add(ioProperty);
+       (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty);
 }
 
 
@@ -356,10 +395,13 @@ bool CValue::RemoveProperty(const STR_String & inName)
        if (m_pNamedPropertyArray == NULL)
                return false;
 
-       // Scan all properties, as soon as we find one with <inName> -> Remove it
-//     CValue* val = (*m_pNamedPropertyArray)[inName];
-       if (m_pNamedPropertyArray->erase(inName)) return true;
-       
+       CValue* val = GetProperty(inName);
+       if (NULL != val) 
+       {
+               val->Release();
+               m_pNamedPropertyArray->erase(inName);
+               return true;
+       }
        return false;
 }
 
@@ -379,7 +421,7 @@ void CValue::ClearProperties()
        !(it == m_pNamedPropertyArray->end());it++)
        {
                CValue* tmpval = (*it).second;
-               STR_String name = (*it).first;
+               //STR_String name = (*it).first;
                tmpval->Release();
        }
 
@@ -469,8 +511,9 @@ void CValue::CloneProperties(CValue *replica)
                for ( std::map<STR_String,CValue*>::iterator it = m_pNamedPropertyArray->begin();
                !(it == m_pNamedPropertyArray->end());it++)
                {
-                       
-                       replica->SetProperty((*it).first,(*it).second->GetReplica());
+                       CValue *val = (*it).second->GetReplica();
+                       replica->SetProperty((*it).first,val);
+                       val->Release();
                }
        }
 
@@ -489,10 +532,6 @@ double*            CValue::GetVector3(bool bGetTransformedVec)
 }
 
 
-
-
-
-
 /*---------------------------------------------------------------------------------------------------------------------
        Reference Counting
 ---------------------------------------------------------------------------------------------------------------------*/
@@ -504,6 +543,9 @@ CValue *CValue::AddRef()
        // Increase global reference count, used to see at the end of the program
        // if all CValue-derived classes have been dereferenced to 0
        //debug(gRefCountValue++);
+#ifdef _DEBUG
+       //gRefCountValue++;
+#endif
        m_refcount++; 
        return this;
 }
@@ -518,7 +560,9 @@ int CValue::Release()
        // Decrease global reference count, used to see at the end of the program
        // if all CValue-derived classes have been dereferenced to 0
        //debug(gRefCountValue--);
-
+#ifdef _DEBUG
+       //gRefCountValue--;
+#endif
        // Decrease local reference count, if it reaches 0 the object should be freed
        if (--m_refcount > 0)
        {
@@ -546,6 +590,9 @@ void CValue::DisableRefCount()
        m_refcount--;
 
        //debug(gRefCountValue--);
+#ifdef _DEBUG
+       //gRefCountValue--;
+#endif
        m_ValFlags.RefCountDisabled=true;
 }
 
@@ -590,11 +637,14 @@ CValue*   CValue::FindIdentifier(const STR_String& identifiername)
        } else
        {
                result = GetProperty(identifiername);
+               if (result)
+                       return result->AddRef();
+       }
+       if (!result)
+       {
+               // warning here !!!
+               result = new CErrorValue(identifiername+" not found");
        }
-       if (result)
-               return result->AddRef();
-       // warning here !!!
-       result = new CErrorValue(identifiername+" not found");
        return result;
 }
 
@@ -717,7 +767,7 @@ int CValue::_setattr(const STR_String& attr,PyObject* pyobj)
                        oldprop->SetValue(vallie);
                } else
                {
-                       SetProperty(attr,vallie->AddRef());
+                       SetProperty(attr,vallie);
                }
                vallie->Release();
        }
index 8971135ecdaee740d1ccaa0ba83d81fd82a762ee..fae1b5dfa6b7e791dcf14e3d50d7a42069d5581c 100644 (file)
@@ -101,6 +101,7 @@ SCA_ActuatorList& SCA_IObject::GetActuators()
 
 void SCA_IObject::AddSensor(SCA_ISensor* act)
 {
+       act->AddRef();
        m_sensors.push_back(act);
 }
 
@@ -108,6 +109,7 @@ void SCA_IObject::AddSensor(SCA_ISensor* act)
 
 void SCA_IObject::AddController(SCA_IController* act)
 {
+       act->AddRef();
        m_controllers.push_back(act);
 }
 
@@ -115,6 +117,7 @@ void SCA_IObject::AddController(SCA_IController* act)
 
 void SCA_IObject::AddActuator(SCA_IActuator* act)
 {
+       act->AddRef();
        m_actuators.push_back(act);
 }
 
index fb8c340b09e813904972184afbd6a63bd4fa964d..4898dbed95faae05e28a5c7b977074722d593c6d 100644 (file)
@@ -212,6 +212,7 @@ void SCA_KeyboardSensor::AddToTargetProp(int keyIndex)
                                        newprop.SetLength(oldlength - 1);
                                        CStringValue * newstringprop = new CStringValue(newprop, m_targetprop);
                                        GetParent()->SetProperty(m_targetprop, newstringprop);
+                                       newstringprop->Release();
                                }                               
                        } else {
                                /* append */
@@ -219,6 +220,7 @@ void SCA_KeyboardSensor::AddToTargetProp(int keyIndex)
                                STR_String newprop = tprop->GetText() + pchar;
                                CStringValue * newstringprop = new CStringValue(newprop, m_targetprop);                 
                                GetParent()->SetProperty(m_targetprop, newstringprop);
+                               newstringprop->Release();
                        }
                } else {
                        if (!IsDelete(keyIndex)) {
@@ -227,6 +229,7 @@ void SCA_KeyboardSensor::AddToTargetProp(int keyIndex)
                                STR_String newprop = pchar;
                                CStringValue * newstringprop = new CStringValue(newprop, m_targetprop);                 
                                GetParent()->SetProperty(m_targetprop, newstringprop);
+                               newstringprop->Release();
                        }
                }
        }
index 8b79703a6fc91d6c9ca1337d26fdeb9c85391e1c..048d6992c7390fb6d8e2acc6197ee161019c4584 100644 (file)
@@ -51,6 +51,10 @@ SCA_LogicManager::SCA_LogicManager()
 
 SCA_LogicManager::~SCA_LogicManager()
 {
+       /* AddRef() is not used when the objects are added to m_mapStringToGameObjects
+          so Release() should not be used either. The memory leak big is fixed
+          in BL_ConvertBlenderObjects()
+
        int numgameobj = m_mapStringToGameObjects.size();
        for (int i = 0; i < numgameobj; i++)
        {
@@ -58,8 +62,9 @@ SCA_LogicManager::~SCA_LogicManager()
                assert(gameobjptr);
                if (gameobjptr)
                        (*gameobjptr)->Release();
-
+    
        }
+       */
        /*for (int i=0;i<m_sensorcontrollermap.size();i++)
        {
                vector<SCA_IController*>* controllerarray = *(m_sensorcontrollermap[i]);
@@ -72,6 +77,8 @@ SCA_LogicManager::~SCA_LogicManager()
        }
        m_eventmanagers.clear();
        m_sensorcontrollermapje.clear();
+       m_removedActuators.clear();
+       m_activeActuators.clear();
 }
 
 
index c3e2066fc65bcd5fa23dffe581c8118945fbf391..c798503ae8abaaeb0dbab58ad18a0b3b988e3e8a 100644 (file)
@@ -90,12 +90,11 @@ bool SCA_PropertyActuator::Update()
                                if (oldprop)
                                {
                                        oldprop->SetValue(newval);
-                                       newval->Release();
                                } else
                                {
                                        propowner->SetProperty(m_propname,newval);
                                }
-
+                               newval->Release();
                                break;
                        }
                case KX_ACT_PROP_ADD:
@@ -123,9 +122,11 @@ bool SCA_PropertyActuator::Update()
                                        CValue* copyprop = m_sourceObj->GetProperty(m_exprtxt);
                                        if (copyprop)
                                        {
+                                               CValue *val = copyprop->GetReplica();
                                                GetParent()->SetProperty(
                                                         m_propname,
-                                                       copyprop->GetReplica());
+                                                        val);
+                                               val->Release();
 
                                        }
                                }
@@ -239,11 +240,12 @@ PyObject* SCA_PropertyActuator::PySetProperty(PyObject* self, PyObject* args, Py
 
        CValue* prop = GetParent()->FindIdentifier(nameArg);
 
-       if (prop) {
+       if (!prop->IsError()) {
                m_propname = nameArg;
        } else {
                ; /* not found ... */
        }
+       prop->Release();
        
        Py_Return;
 }
index bb8ea7f23b381c4f9c63674dfe381c9c6ff61ae0..b75662f01c96416402844178dbe43afa300cb68f 100644 (file)
@@ -58,7 +58,9 @@ KX_Camera::KX_Camera(void* sgReplicationInfo,
        m_name = "cam";
        m_projection_matrix.setIdentity();
        m_modelview_matrix.setIdentity();
-       SetProperty("camera",new CIntValue(1));
+       CValue* val = new CIntValue(1);
+       SetProperty("camera",val);
+       val->Release();
 }
 
 
index 5de2ab1b2dccbd10d7422125c4067caffb36b794..7b2c514db8aa025d43425321685434d29eb8db79 100644 (file)
@@ -858,6 +858,8 @@ static btCollisionShape* CreateBulletShapeFromMesh(RAS_MeshObject* meshobj, bool
                        //concaveShape = new btTriangleMeshShape( collisionMeshData );
 
                        concaveShape->recalcLocalAabb();
+                       if (collisionMeshShape)
+                               delete collisionMeshShape;
                        collisionMeshShape = concaveShape;
 
                } 
@@ -866,8 +868,10 @@ static btCollisionShape* CreateBulletShapeFromMesh(RAS_MeshObject* meshobj, bool
 
                return collisionMeshShape;
        }
-
-       delete collisionMeshShape;
+       if (collisionMeshShape)
+               delete collisionMeshShape;
+       if (collisionMeshData)
+               delete collisionMeshData;
        return NULL;
 
 }
@@ -1021,7 +1025,10 @@ void     KX_ConvertBulletObject( class   KX_GameObject* gameobj,
 //     ci.m_localInertiaTensor.setValue(0.1f,0.1f,0.1f);
 
        if (!bm)
+       {
+               delete motionstate;
                return;
+       }
 
        bm->setMargin(0.06);
 
@@ -1057,6 +1064,7 @@ void      KX_ConvertBulletObject( class   KX_GameObject* gameobj,
                                
 
                        compoundShape->addChildShape(childTrans,bm);
+                       kxscene->AddShape(bm);
                        //do some recalc?
                        //recalc inertia for rigidbody
                        if (!rigidbody->isStaticOrKinematicObject())
@@ -1076,6 +1084,9 @@ void      KX_ConvertBulletObject( class   KX_GameObject* gameobj,
                        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);
                        bm = compoundShape;
                }
 
@@ -1112,9 +1123,6 @@ void      KX_ConvertBulletObject( class   KX_GameObject* gameobj,
 
 
        ci.m_collisionShape = bm;
-       
-
-       
        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;
@@ -1127,6 +1135,8 @@ void      KX_ConvertBulletObject( class   KX_GameObject* gameobj,
        ci.m_collisionFilterMask = (isbulletdyna) ? short(CcdConstructionInfo::AllFilter) : short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter);
 
        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);
 
        if (objprop->m_in_active_layer)
        {
index 8febc0e10cd0dc8dd4eba730c97a7675f27887f8..9e5efad803b5309681804d973384e6a2644fc5c1 100644 (file)
@@ -1047,6 +1047,8 @@ void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
                scene->SetActiveCamera(activecam);
                scene->GetObjectList()->Add(activecam->AddRef());
                scene->GetRootParentList()->Add(activecam->AddRef());
+               //done with activecam
+               activecam->Release();
        }
        
        scene->UpdateParents(0.0);
index 45b2db10b33a73b91fc474459d38f40dbf9e1642..7366e374a107140aeb908295759f1b0896b943c5 100644 (file)
@@ -326,6 +326,8 @@ void        KX_SCA_AddObjectActuator::InstantAddObject()
                
                m_lastCreatedObject = replica;
                m_lastCreatedObject->AddRef();
+               // finished using replica? then release it
+               replica->Release();
        }
 }
 
index f9c2f8e571b085741ccc0888fcd1ed37f2d271e1..f9fc503f406139e392111750453fbcbe82cbd3b9 100644 (file)
@@ -35,6 +35,7 @@
 #pragma warning (disable : 4786)
 #endif //WIN32
 
+
 #include "KX_Scene.h"
 #include "MT_assert.h"
 
 #include "BL_SkinDeformer.h"
 #include "BL_DeformableGameObject.h"
 
+// to get USE_BULLET!
+#include "KX_ConvertPhysicsObject.h"
+
+#ifdef USE_BULLET
+#include "CcdPhysicsEnvironment.h"
+#include "CcdPhysicsController.h"
+#endif
 
 void* KX_SceneReplicationFunc(SG_IObject* node,void* gameobj,void* scene)
 {
@@ -124,6 +132,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
        m_objectlist = new CListValue();
        m_parentlist = new CListValue();
        m_lightlist= new CListValue();
+       m_inactivelist = new CListValue();
        m_euthanasyobjects = new CListValue();
        m_delayReleaseObjects = new CListValue();
 
@@ -183,6 +192,9 @@ KX_Scene::~KX_Scene()
        if (m_parentlist)
                m_parentlist->Release();
        
+       if (m_inactivelist)
+               m_inactivelist->Release();
+
        if (m_lightlist)
                m_lightlist->Release();
        
@@ -210,11 +222,38 @@ 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)
@@ -243,6 +282,11 @@ CListValue* KX_Scene::GetRootParentList()
        return m_parentlist;
 }
 
+CListValue* KX_Scene::GetInactiveList()
+{
+       return m_inactivelist;
+}
+
 
 
 CListValue* KX_Scene::GetLightList()
@@ -415,7 +459,7 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal
        replicanode->SetSGClientObject(newobj);
 
        // this is the list of object that are send to the graphics pipeline
-       m_objectlist->Add(newobj);
+       m_objectlist->Add(newobj->AddRef());
        newobj->Bucketize();
 
        // logic cannot be replicated, until the whole hierarchy is replicated.
@@ -571,7 +615,9 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
                // add a timebomb to this object
                // for now, convert between so called frames and realtime
                m_tempObjectList->Add(replica->AddRef());
-               replica->SetProperty("::timebomb",new CFloatValue(lifespan*0.02));
+               CValue *fval = new CFloatValue(lifespan*0.02);
+               replica->SetProperty("::timebomb",fval);
+               fval->Release();
        }
 
        // add to 'rootparent' list (this is the list of top hierarchy objects, updated each frame)
@@ -634,7 +680,7 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
        replica->GetSGNode()->UpdateWorldData(0);
        replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox());
        replica->GetSGNode()->SetRadius(originalobj->GetSGNode()->Radius());
-       
+       //      don't release replica here because we are returning it, not done with it...
        return replica;
 }
 
@@ -654,7 +700,8 @@ void KX_Scene::RemoveObject(class CValue* gameobj)
                // recursively destruct
                node->Destruct();
        }
-       newobj->SetSGNode(0);
+       //no need to do that: the object is destroyed and memory released 
+       //newobj->SetSGNode(0);
 }
 
 void KX_Scene::DelayedReleaseObject(CValue* gameobj)
@@ -704,6 +751,7 @@ void KX_Scene::NewRemoveObject(class CValue* gameobj)
        {
                m_logicmgr->RemoveDestroyedActuator(*ita);
        }
+       // the sensors/controllers/actuators must also be released, this is done in ~SCA_IObject
 
        // now remove the timer properties from the time manager
        int numprops = newobj->GetPropertyCount();
@@ -724,12 +772,15 @@ void KX_Scene::NewRemoveObject(class CValue* gameobj)
                newobj->Release();
        if (m_parentlist->RemoveValue(newobj))
                newobj->Release();
+       if (m_inactivelist->RemoveValue(newobj))
+               newobj->Release();
        if (m_euthanasyobjects->RemoveValue(newobj))
                newobj->Release();
                
        if (newobj == m_active_camera)
        {
-               m_active_camera->Release();
+               //no AddRef done on m_active_camera so no Release
+               //m_active_camera->Release();
                m_active_camera = NULL;
        }
 }
@@ -1108,6 +1159,8 @@ void KX_Scene::LogicEndFrame()
        for (i = numobj - 1; i >= 0; i--)
        {
                KX_GameObject* gameobj = (KX_GameObject*)m_euthanasyobjects->GetValue(i);
+               // KX_Scene::RemoveObject will also remove the object from this list
+               // that's why we start from the end
                this->RemoveObject(gameobj);
        }
 
@@ -1115,11 +1168,11 @@ void KX_Scene::LogicEndFrame()
        for (i = numobj-1;i>=0;i--)
        {
                KX_GameObject* gameobj = (KX_GameObject*)m_delayReleaseObjects->GetValue(i);
-               m_delayReleaseObjects->RemoveValue(gameobj);    
-               
+               // This list is not for object removal, but just object release
+               gameobj->Release();
        }
-       
-
+       // empty the list as we have removed all references
+       m_delayReleaseObjects->Resize(0);       
 }
 
 
index 50fcf1a3c40d06eb7ec64d16a7424e4023390378..b857f4f591eb49180f44a8123037bb449ec62cbc 100644 (file)
@@ -85,6 +85,7 @@ class RAS_IPolyMaterial;
 class RAS_IRasterizer;
 class RAS_IRenderTools;
 class SCA_JoystickManager;
+class btCollisionShape;
 /**
  * The KX_Scene holds all data for an independent scene. It relates
  * KX_Objects to the specific objects in the modules.
@@ -111,6 +112,7 @@ protected:
        CListValue*                     m_objectlist;
        CListValue*                     m_parentlist; // all 'root' parents
        CListValue*                     m_lightlist;
+       CListValue*                     m_inactivelist; // all objects that are not in the active layer
 
        /**
         *  The tree of objects in the scene.
@@ -121,7 +123,11 @@ 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
         */
@@ -300,6 +306,7 @@ public:
        void NewRemoveObject(CValue* gameobj);
        void ReplaceMesh(CValue* gameobj,
                                         void* meshobj);
+       void AddShape(class btCollisionShape* shape);
        /**
         * @section Logic stuff
         * Initiate an update of the logic system.
@@ -313,6 +320,10 @@ public:
 
                CListValue*                             
        GetObjectList(
+       );
+
+               CListValue*                             
+       GetInactiveList(
        );
 
                CListValue*