diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index fde54025fc7..271385bb144 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -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(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 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; } diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 89a07abe21d..f76a0fb82e5 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -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; diff --git a/source/gameengine/Converter/KX_ConvertControllers.cpp b/source/gameengine/Converter/KX_ConvertControllers.cpp index 5b30f5a4a2e..b277af7dbc2 100644 --- a/source/gameengine/Converter/KX_ConvertControllers.cpp +++ b/source/gameengine/Converter/KX_ConvertControllers.cpp @@ -174,6 +174,8 @@ void BL_ConvertControllers( gameobj->AddController(gamecontroller); converter->RegisterGameController(gamecontroller, bcontr); + //done with gamecontroller + gamecontroller->Release(); } bcontr = bcontr->next; diff --git a/source/gameengine/Converter/KX_ConvertProperties.cpp b/source/gameengine/Converter/KX_ConvertProperties.cpp index a1807732416..ebfb45066b7 100644 --- a/source/gameengine/Converter/KX_ConvertProperties.cpp +++ b/source/gameengine/Converter/KX_ConvertProperties.cpp @@ -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; diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp index d9c49217042..61759ddf654 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.cpp +++ b/source/gameengine/Converter/KX_ConvertSensors.cpp @@ -733,6 +733,8 @@ void BL_ConvertSensors(struct Object* blenderobject, logicmgr->RegisterToSensor(gamecont,gamesensor); } } + // done with gamesensor + gamesensor->Release(); } sens=sens->next; diff --git a/source/gameengine/Expressions/Expression.cpp b/source/gameengine/Expressions/Expression.cpp index 5c5e1abea34..f16f572c322 100644 --- a/source/gameengine/Expressions/Expression.cpp +++ b/source/gameengine/Expressions/Expression.cpp @@ -22,7 +22,9 @@ ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// - +#ifdef _DEBUG +//int gRefCountExpr; +#endif CExpression::CExpression()// : m_cached_calculate(NULL) { m_refcount = 1; diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp index 48898dfc1f5..56208ab4ad5 100644 --- a/source/gameengine/Expressions/Value.cpp +++ b/source/gameengine/Expressions/Value.cpp @@ -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 + +std::vector 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::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 -> 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::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(); } diff --git a/source/gameengine/GameLogic/SCA_IObject.cpp b/source/gameengine/GameLogic/SCA_IObject.cpp index 8971135ecda..fae1b5dfa6b 100644 --- a/source/gameengine/GameLogic/SCA_IObject.cpp +++ b/source/gameengine/GameLogic/SCA_IObject.cpp @@ -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); } diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp index fb8c340b09e..4898dbed95f 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp @@ -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(); } } } diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp index 8b79703a6fc..048d6992c73 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.cpp +++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp @@ -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* controllerarray = *(m_sensorcontrollermap[i]); @@ -72,6 +77,8 @@ SCA_LogicManager::~SCA_LogicManager() } m_eventmanagers.clear(); m_sensorcontrollermapje.clear(); + m_removedActuators.clear(); + m_activeActuators.clear(); } diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp index c3e2066fc65..c798503ae8a 100644 --- a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp +++ b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp @@ -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; } diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp index bb8ea7f23b3..b75662f01c9 100644 --- a/source/gameengine/Ketsji/KX_Camera.cpp +++ b/source/gameengine/Ketsji/KX_Camera.cpp @@ -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(); } diff --git a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp index 5de2ab1b2dc..7b2c514db8a 100644 --- a/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp +++ b/source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp @@ -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) { diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 8febc0e10cd..9e5efad803b 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -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); diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp index 45b2db10b33..7366e374a10 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp @@ -326,6 +326,8 @@ void KX_SCA_AddObjectActuator::InstantAddObject() m_lastCreatedObject = replica; m_lastCreatedObject->AddRef(); + // finished using replica? then release it + replica->Release(); } } diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index f9c2f8e571b..f9fc503f406 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -35,6 +35,7 @@ #pragma warning (disable : 4786) #endif //WIN32 + #include "KX_Scene.h" #include "MT_assert.h" @@ -78,6 +79,13 @@ #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::iterator it = m_shapes.begin(); + while (it != m_shapes.end()) { + shape = *it; + if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE) + { + meshShape = static_cast(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); } diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index 50fcf1a3c40..b857f4f591e 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -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 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 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*