blender/source/gameengine/GameLogic/SCA_LogicManager.cpp
Benoit Bolsee 07abb9dee2 BGE performance:
- Vast performance increase when removing scene containing large number of 
  objects: the sensor/controller map was updated for each deleted object, 
  causing massive slow down when the number of objects was large (O(n^2)).
- Use reference when scanning the sensor map => avoid useless copy.
- Remove dynamically the object bounding box from the DBVT when the object
  is invisible => faster culling.
2009-05-01 20:34:23 +00:00

552 lines
13 KiB
C++

/**
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
* Regulates the top-level logic behaviour for one scene.
*/
#include "Value.h"
#include "SCA_LogicManager.h"
#include "SCA_ISensor.h"
#include "SCA_IController.h"
#include "SCA_IActuator.h"
#include "SCA_EventManager.h"
#include "SCA_PythonController.h"
#include <set>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
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++)
{
CValue** gameobjptr = m_mapStringToGameObjects.at(i);
assert(gameobjptr);
if (gameobjptr)
(*gameobjptr)->Release();
}
*/
/*for (int i=0;i<m_sensorcontrollermap.size();i++)
{
vector<SCA_IController*>* controllerarray = *(m_sensorcontrollermap[i]);
delete controllerarray;
}
*/
for (vector<SCA_EventManager*>::iterator it = m_eventmanagers.begin();!(it==m_eventmanagers.end());it++)
{
delete (*it);
}
m_eventmanagers.clear();
m_sensorcontrollermapje.clear();
m_removedActuators.clear();
m_activeActuators.clear();
}
// this function is a performance helper when the scene is destoyed
// without it, the map updated for each object... a massive slow down when there are
// large number of objects. By clearing the map upfront we avoid the waster of time.
void SCA_LogicManager::RemoveSensorMap()
{
m_sensorcontrollermapje.clear();
}
/*
// this kind of fixes bug 398 but breakes games, so better leave it out for now.
// a removed object's gameobject (and logicbricks and stuff) didn't get released
// because it was still in the m_mapStringToGameObjects map.
void SCA_LogicManager::RemoveGameObject(const STR_String& gameobjname)
{
int numgameobj = m_mapStringToGameObjects.size();
for (int i = 0; i < numgameobj; i++)
{
CValue** gameobjptr = m_mapStringToGameObjects.at(i);
assert(gameobjptr);
if (gameobjptr)
{
if ((*gameobjptr)->GetName() == gameobjname)
(*gameobjptr)->Release();
}
}
m_mapStringToGameObjects.remove(gameobjname);
}
*/
void SCA_LogicManager::RegisterEventManager(SCA_EventManager* eventmgr)
{
m_eventmanagers.push_back(eventmgr);
}
void SCA_LogicManager::RegisterGameObjectName(const STR_String& gameobjname,
CValue* gameobj)
{
STR_HashedString mn = gameobjname;
m_mapStringToGameObjects.insert(mn,gameobj);
}
void SCA_LogicManager::RegisterGameMeshName(const STR_String& gamemeshname, void* blendobj)
{
STR_HashedString mn = gamemeshname;
m_map_gamemeshname_to_blendobj.insert(mn, blendobj);
}
void SCA_LogicManager::RegisterGameObj(void* blendobj, CValue* gameobj)
{
m_map_blendobj_to_gameobj.insert(CHashedPtr(blendobj), gameobj);
}
void SCA_LogicManager::UnregisterGameObj(void* blendobj, CValue* gameobj)
{
void **obp = m_map_blendobj_to_gameobj[CHashedPtr(blendobj)];
if (obp && (CValue*)(*obp) == gameobj)
m_map_blendobj_to_gameobj.remove(CHashedPtr(blendobj));
}
CValue* SCA_LogicManager::GetGameObjectByName(const STR_String& gameobjname)
{
STR_HashedString mn = "OB"+gameobjname;
CValue** gameptr = m_mapStringToGameObjects[mn];
if (gameptr)
return *gameptr;
return NULL;
}
CValue* SCA_LogicManager::FindGameObjByBlendObj(void* blendobj)
{
void **obp= m_map_blendobj_to_gameobj[CHashedPtr(blendobj)];
return obp?(CValue*)(*obp):NULL;
}
void* SCA_LogicManager::FindBlendObjByGameMeshName(const STR_String& gamemeshname)
{
STR_HashedString mn = gamemeshname;
void **obp= m_map_gamemeshname_to_blendobj[mn];
return obp?*obp:NULL;
}
void SCA_LogicManager::RemoveSensor(SCA_ISensor* sensor)
{
sensormap_t::const_iterator mit = m_sensorcontrollermapje.find(sensor);
if (mit != m_sensorcontrollermapje.end())
{
const controllerlist& contlist = mit->second;
for (controllerlist::const_iterator c= contlist.begin();!(c==contlist.end());c++)
{
(*c)->UnlinkSensor(sensor);
}
m_sensorcontrollermapje.erase(sensor);
}
sensor->UnregisterToManager();
}
void SCA_LogicManager::RemoveController(SCA_IController* controller)
{
controller->UnlinkAllSensors();
controller->UnlinkAllActuators();
sensormap_t::iterator sit;
for (sit = m_sensorcontrollermapje.begin();!(sit==m_sensorcontrollermapje.end());++sit)
{
(*sit).second.remove(controller);
}
}
void SCA_LogicManager::RemoveDestroyedActuator(SCA_IActuator* actuator)
{
m_removedActuators.push_back(SmartActuatorPtr(actuator,0));
// take care that no controller can use this actuator again !
sensormap_t::const_iterator sit;
for (sit = m_sensorcontrollermapje.begin();!(sit==m_sensorcontrollermapje.end());++sit)
{
const controllerlist& contlist = sit->second;
for (list<SCA_IController*>::const_iterator c= contlist.begin();!(c==contlist.end());c++)
{
(*c)->UnlinkActuator(actuator);
}
}
}
void SCA_LogicManager::RegisterToSensor(SCA_IController* controller,SCA_ISensor* sensor)
{
m_sensorcontrollermapje[sensor].push_back(controller);
controller->LinkToSensor(sensor);
}
void SCA_LogicManager::RegisterToActuator(SCA_IController* controller,SCA_IActuator* actua)
{
controller->LinkToActuator(actua);
}
void SCA_LogicManager::BeginFrame(double curtime, double fixedtime)
{
for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin(); !(ie==m_eventmanagers.end()); ie++)
(*ie)->NextFrame(curtime, fixedtime);
// for this frame, look up for activated sensors, and build the collection of triggered controllers
// int numsensors = this->m_activatedsensors.size(); /*unused*/
for (vector<SCA_ISensor*>::const_iterator is=m_activatedsensors.begin();
!(is==m_activatedsensors.end());is++)
{
SCA_ISensor* sensor = *is;
const controllerlist& contlist = m_sensorcontrollermapje[sensor];
for (list<SCA_IController*>::const_iterator c= contlist.begin();
!(c==contlist.end());c++)
{
SCA_IController* contr = *c;//controllerarray->at(c);
if (contr->IsActive())
{
m_triggeredControllerSet.insert(SmartControllerPtr(contr,0));
// So that the controller knows which sensor has activited it.
// Only needed for the python controller though.
if (contr->GetType() == &SCA_PythonController::Type)
{
SCA_PythonController* pythonController = (SCA_PythonController*)contr;
pythonController->AddTriggeredSensor(sensor);
}
}
}
//sensor->SetActive(false);
}
// int numtriggered = triggeredControllerSet.size(); /*unused*/
for (set<SmartControllerPtr>::iterator tit=m_triggeredControllerSet.begin();
!(tit==m_triggeredControllerSet.end());tit++)
{
(*tit)->Trigger(this);
}
m_triggeredControllerSet.clear();
}
void SCA_LogicManager::UpdateFrame(double curtime, bool frame)
{
vector<SmartActuatorPtr>::iterator ra;
for (ra = m_removedActuators.begin(); !(ra == m_removedActuators.end()); ra++)
{
m_activeActuators.erase(*ra);
(*ra)->SetActive(false);
}
m_removedActuators.clear();
// About to run actuators, but before update the sensors for those which depends on actuators
for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin(); !(ie==m_eventmanagers.end()); ie++)
(*ie)->UpdateFrame();
for (set<SmartActuatorPtr>::iterator ia = m_activeActuators.begin();!(ia==m_activeActuators.end());ia++)
{
//SCA_IActuator* actua = *ia;
if (!(*ia)->Update(curtime, frame))
{
//*ia = m_activeactuators.back();
m_removedActuators.push_back(*ia);
(*ia)->SetActive(false);
//m_activeactuators.pop_back();
} else if ((*ia)->IsNoLink())
{
// This actuator has no more links but it still active
// make sure it will get a negative event on next frame to stop it
// Do this check after Update() rather than before to make sure
// that all the actuators that are activated at same time than a state
// actuator have a chance to execute.
CValue* event = new CBoolValue(false);
(*ia)->RemoveAllEvents();
(*ia)->AddEvent(event);
}
}
for ( ra = m_removedActuators.begin(); !(ra == m_removedActuators.end()); ra++)
{
m_activeActuators.erase(*ra);
(*ra)->SetActive(false);
}
m_removedActuators.clear();
}
void* SCA_LogicManager::GetActionByName (const STR_String& actname)
{
STR_HashedString an = "AC"+actname;
void** actptr = m_mapStringToActions[an];
if (actptr)
return *actptr;
return NULL;
}
void* SCA_LogicManager::GetMeshByName(const STR_String& meshname)
{
STR_HashedString mn = "ME"+meshname;
void** meshptr = m_mapStringToMeshes[mn];
if (meshptr)
return *meshptr;
return NULL;
}
void SCA_LogicManager::RegisterMeshName(const STR_String& meshname,void* mesh)
{
STR_HashedString mn = meshname;
m_mapStringToMeshes.insert(mn,mesh);
}
void SCA_LogicManager::RegisterActionName(const STR_String& actname,void* action)
{
STR_HashedString an = actname;
m_mapStringToActions.insert(an, action);
}
void SCA_LogicManager::EndFrame()
{
for (vector<SCA_ISensor*>::const_iterator is=m_activatedsensors.begin();
!(is==m_activatedsensors.end());is++)
{
SCA_ISensor* sensor = *is;
sensor->SetActive(false);
}
m_activatedsensors.clear();
for (vector<SCA_EventManager*>::const_iterator ie=m_eventmanagers.begin();
!(ie==m_eventmanagers.end());ie++)
{
(*ie)->EndFrame();
}
}
void SCA_LogicManager::AddActivatedSensor(SCA_ISensor* sensor)
{
// each frame, only add sensor once, and to avoid a seek, or bloated container
// hold a flag in each sensor, with the 'framenr'
if (!sensor->IsActive())
{
sensor->SetActive(true);
m_activatedsensors.push_back(sensor);
}
}
void SCA_LogicManager::AddTriggeredController(SCA_IController* controller, SCA_ISensor* sensor)
{
m_triggeredControllerSet.insert(SmartControllerPtr(controller,0));
// so that the controller knows which sensor has activited it
// only needed for python controller
if (controller->GetType() == &SCA_PythonController::Type)
{
SCA_PythonController* pythonController = (SCA_PythonController*)controller;
pythonController->AddTriggeredSensor(sensor);
}
}
void SCA_LogicManager::AddActiveActuator(SCA_IActuator* actua,CValue* event)
{
if (!actua->IsActive())
{
actua->SetActive(true);
m_activeActuators.insert(SmartActuatorPtr(actua,0));
}
actua->AddEvent(event->AddRef());
}
SCA_EventManager* SCA_LogicManager::FindEventManager(int eventmgrtype)
{
// find an eventmanager of a certain type
SCA_EventManager* eventmgr = NULL;
for (vector<SCA_EventManager*>::const_iterator i=
m_eventmanagers.begin();!(i==m_eventmanagers.end());i++)
{
SCA_EventManager* emgr = *i;
if (emgr->GetType() == eventmgrtype)
{
eventmgr = emgr;
break;
}
}
return eventmgr;
}
SmartActuatorPtr::SmartActuatorPtr(const SmartActuatorPtr& other)
{
this->m_actuator = other.m_actuator;
this->m_actuator->AddRef();
}
SmartActuatorPtr::SmartActuatorPtr(SCA_IActuator* actua,int dummy)
: m_actuator(actua)
{
actua->AddRef();
}
SmartActuatorPtr::~SmartActuatorPtr()
{
m_actuator->Release();
}
bool SmartActuatorPtr::operator <(const SmartActuatorPtr& other) const
{
return m_actuator->LessComparedTo(*other);
}
bool SmartActuatorPtr::operator ==(const SmartActuatorPtr& other) const
{
bool result2 = other->LessComparedTo(m_actuator);
return (m_actuator->LessComparedTo(*other) && result2);
}
SCA_IActuator* SmartActuatorPtr::operator->() const
{
return m_actuator;
}
SCA_IActuator* SmartActuatorPtr::operator*() const
{
return m_actuator;
}
SmartControllerPtr::SmartControllerPtr(const SmartControllerPtr& copy)
{
this->m_controller = copy.m_controller;
this->m_controller->AddRef();
}
SmartControllerPtr::SmartControllerPtr(SCA_IController* contr,int dummy)
: m_controller(contr)
{
m_controller->AddRef();
}
SmartControllerPtr::~SmartControllerPtr()
{
m_controller->Release();
}
bool SmartControllerPtr::operator <(const SmartControllerPtr& other) const
{
return m_controller->LessComparedTo(*other);
}
bool SmartControllerPtr::operator ==(const SmartControllerPtr& other) const
{
return (m_controller->LessComparedTo(*other) && other->LessComparedTo(m_controller));
}
SCA_IController* SmartControllerPtr::operator->() const
{
return m_controller;
}
SCA_IController* SmartControllerPtr::operator*() const
{
return m_controller;
}