blender/source/gameengine/Ketsji/KX_TouchSensor.cpp
Mitchell Stokes 60c8c130fe BGE cleanup: KX_GameObject::GetParent() no longer increases the object's refcount.
I'm not sure why this function ever increased the object's refcount. Any
place in the code that calls KX_GameObject::GetParent() has to turn
around and call parent->Release(). Forgetting to call Release() was a
common cause of memory leaks (in fact, KX_SteeringActuator was probably
leaking). If the refcount needs to be increased, the calling code can
handle calling AddRef().
2014-04-30 18:53:32 -07:00

352 lines
10 KiB
C++

/*
* Senses touch and collision events
*
*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 *****
*/
/** \file gameengine/Ketsji/KX_TouchSensor.cpp
* \ingroup ketsji
*/
#include "KX_TouchSensor.h"
#include "SCA_EventManager.h"
#include "SCA_LogicManager.h"
#include "KX_GameObject.h"
#include "KX_TouchEventManager.h"
#include "PHY_IPhysicsController.h"
#include <iostream>
#include "PHY_IPhysicsEnvironment.h"
/* ------------------------------------------------------------------------- */
/* Native functions */
/* ------------------------------------------------------------------------- */
void KX_TouchSensor::SynchronizeTransform()
{
// the touch sensor does not require any synchronization: it uses
// the same physical object which is already synchronized by Blender
}
void KX_TouchSensor::EndFrame()
{
m_colliders->ReleaseAndRemoveAll();
m_hitObject = NULL;
m_bTriggered = false;
m_bColliderHash = 0;
}
void KX_TouchSensor::UnregisterToManager()
{
// before unregistering the sensor, make sure we release all references
EndFrame();
SCA_ISensor::UnregisterToManager();
}
bool KX_TouchSensor::Evaluate()
{
bool result = false;
bool reset = m_reset && m_level;
m_reset = false;
if (m_bTriggered != m_bLastTriggered)
{
m_bLastTriggered = m_bTriggered;
if (!m_bTriggered)
m_hitObject = NULL;
result = true;
}
if (reset)
// force an event
result = true;
if (m_bTouchPulse) { /* pulse on changes to the colliders */
int count = m_colliders->GetCount();
if (m_bLastCount!=count || m_bColliderHash!=m_bLastColliderHash) {
m_bLastCount = count;
m_bLastColliderHash= m_bColliderHash;
result = true;
}
}
return result;
}
KX_TouchSensor::KX_TouchSensor(SCA_EventManager* eventmgr,KX_GameObject* gameobj,bool bFindMaterial,bool bTouchPulse,const STR_String& touchedpropname)
:SCA_ISensor(gameobj,eventmgr),
m_touchedpropname(touchedpropname),
m_bFindMaterial(bFindMaterial),
m_bTouchPulse(bTouchPulse),
m_hitMaterial("")
/*m_sumoObj(sumoObj),*/
{
// KX_TouchEventManager* touchmgr = (KX_TouchEventManager*) eventmgr;
// m_resptable = touchmgr->GetResponseTable();
// m_solidHandle = m_sumoObj->getObjectHandle();
m_colliders = new CListValue();
KX_ClientObjectInfo *client_info = gameobj->getClientInfo();
//client_info->m_gameobject = gameobj;
//client_info->m_auxilary_info = NULL;
client_info->m_sensors.push_back(this);
m_physCtrl = gameobj->GetPhysicsController();
MT_assert( !gameobj->GetPhysicsController() || m_physCtrl );
Init();
}
void KX_TouchSensor::Init()
{
m_bCollision = false;
m_bTriggered = false;
m_bLastTriggered = (m_invert)?true:false;
m_bLastCount = 0;
m_bColliderHash = m_bLastColliderHash = 0;
m_hitObject = NULL;
m_reset = true;
}
KX_TouchSensor::~KX_TouchSensor()
{
//DT_ClearObjectResponse(m_resptable,m_solidHandle);
m_colliders->Release();
}
CValue* KX_TouchSensor::GetReplica()
{
KX_TouchSensor* replica = new KX_TouchSensor(*this);
replica->ProcessReplica();
return replica;
}
void KX_TouchSensor::ProcessReplica()
{
SCA_ISensor::ProcessReplica();
m_colliders = new CListValue();
Init();
}
void KX_TouchSensor::ReParent(SCA_IObject* parent)
{
KX_GameObject *gameobj = static_cast<KX_GameObject *>(parent);
PHY_IPhysicsController *sphy = ((KX_GameObject*)parent)->GetPhysicsController();
if (sphy)
m_physCtrl = sphy;
// m_solidHandle = m_sumoObj->getObjectHandle();
KX_ClientObjectInfo *client_info = gameobj->getClientInfo();
//client_info->m_gameobject = gameobj;
//client_info->m_auxilary_info = NULL;
client_info->m_sensors.push_back(this);
SCA_ISensor::ReParent(parent);
}
void KX_TouchSensor::RegisterSumo(KX_TouchEventManager *touchman)
{
if (m_physCtrl)
{
if (touchman->GetPhysicsEnvironment()->RequestCollisionCallback(m_physCtrl))
{
KX_ClientObjectInfo *client_info = static_cast<KX_ClientObjectInfo*>(m_physCtrl->GetNewClientInfo());
if (client_info->isSensor())
touchman->GetPhysicsEnvironment()->AddSensor(m_physCtrl);
}
}
}
void KX_TouchSensor::UnregisterSumo(KX_TouchEventManager* touchman)
{
if (m_physCtrl)
{
if (touchman->GetPhysicsEnvironment()->RemoveCollisionCallback(m_physCtrl))
{
// no more sensor on the controller, can remove it if it is a sensor object
KX_ClientObjectInfo *client_info = static_cast<KX_ClientObjectInfo*>(m_physCtrl->GetNewClientInfo());
if (client_info->isSensor())
touchman->GetPhysicsEnvironment()->RemoveSensor(m_physCtrl);
}
}
}
// this function is called only for sensor objects
// return true if the controller can collide with the object
bool KX_TouchSensor::BroadPhaseSensorFilterCollision(void*obj1,void*obj2)
{
assert(obj1==m_physCtrl && obj2);
KX_GameObject* myobj = (KX_GameObject*)GetParent();
KX_GameObject* myparent = myobj->GetParent();
KX_ClientObjectInfo *client_info = static_cast<KX_ClientObjectInfo*>(((PHY_IPhysicsController*)obj2)->GetNewClientInfo());
KX_ClientObjectInfo *my_client_info = static_cast<KX_ClientObjectInfo*>(m_physCtrl->GetNewClientInfo());
KX_GameObject* otherobj = ( client_info ? client_info->m_gameobject : NULL);
// we can only check on persistent characteristic: m_link and m_suspended are not
// good candidate because they are transient. That must be handled at another level
if (!otherobj ||
otherobj == myparent || // don't interact with our parent
(my_client_info->m_type == KX_ClientObjectInfo::OBACTORSENSOR &&
client_info->m_type != KX_ClientObjectInfo::ACTOR)) // only with actor objects
return false;
bool found = m_touchedpropname.IsEmpty();
if (!found)
{
if (m_bFindMaterial)
{
if (client_info->m_auxilary_info)
{
found = (!strcmp(m_touchedpropname.Ptr(), (char*)client_info->m_auxilary_info));
}
} else
{
found = (otherobj->GetProperty(m_touchedpropname) != NULL);
}
}
return found;
}
bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_CollData* colldata)
{
// KX_TouchEventManager* toucheventmgr = (KX_TouchEventManager*)m_eventmgr;
KX_GameObject* parent = (KX_GameObject*)GetParent();
// need the mapping from PHY_IPhysicsController to gameobjects now
KX_ClientObjectInfo *client_info = static_cast<KX_ClientObjectInfo*> (object1 == m_physCtrl?
((PHY_IPhysicsController*)object2)->GetNewClientInfo():
((PHY_IPhysicsController*)object1)->GetNewClientInfo());
KX_GameObject* gameobj = ( client_info ?
client_info->m_gameobject :
NULL);
// add the same check as in SCA_ISensor::Activate(),
// we don't want to record collision when the sensor is not active.
if (m_links && !m_suspended &&
gameobj && (gameobj != parent) && client_info->isActor())
{
bool found = m_touchedpropname.IsEmpty();
if (!found)
{
if (m_bFindMaterial)
{
if (client_info->m_auxilary_info)
{
found = (!strcmp(m_touchedpropname.Ptr(), (char*)client_info->m_auxilary_info));
}
} else
{
found = (gameobj->GetProperty(m_touchedpropname) != NULL);
}
}
if (found)
{
if (!m_colliders->SearchValue(gameobj)) {
m_colliders->Add(gameobj->AddRef());
if (m_bTouchPulse)
m_bColliderHash += (uint_ptr)(static_cast<void *>(&gameobj));
}
m_bTriggered = true;
m_hitObject = gameobj;
m_hitMaterial = (client_info->m_auxilary_info ? (char*)client_info->m_auxilary_info : "");
//printf("KX_TouchSensor::HandleCollision\n");
}
}
return false; // was DT_CONTINUE but this was defined in sumo as false.
}
#ifdef WITH_PYTHON
/* ------------------------------------------------------------------------- */
/* Python functions */
/* ------------------------------------------------------------------------- */
/* Integration hooks ------------------------------------------------------- */
PyTypeObject KX_TouchSensor::Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"KX_TouchSensor",
sizeof(PyObjectPlus_Proxy),
0,
py_base_dealloc,
0,
0,
0,
0,
py_base_repr,
0,0,0,0,0,0,0,0,0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
0,0,0,0,0,0,0,
Methods,
0,
0,
&SCA_ISensor::Type,
0,0,0,0,0,0,
py_base_new
};
PyMethodDef KX_TouchSensor::Methods[] = {
{NULL,NULL} //Sentinel
};
PyAttributeDef KX_TouchSensor::Attributes[] = {
KX_PYATTRIBUTE_STRING_RW("propName",0,MAX_PROP_NAME,false,KX_TouchSensor,m_touchedpropname),
KX_PYATTRIBUTE_BOOL_RW("useMaterial",KX_TouchSensor,m_bFindMaterial),
KX_PYATTRIBUTE_BOOL_RW("usePulseCollision",KX_TouchSensor,m_bTouchPulse),
KX_PYATTRIBUTE_STRING_RO("hitMaterial", KX_TouchSensor, m_hitMaterial),
KX_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_TouchSensor, pyattr_get_object_hit),
KX_PYATTRIBUTE_RO_FUNCTION("hitObjectList", KX_TouchSensor, pyattr_get_object_hit_list),
{ NULL } //Sentinel
};
/* Python API */
PyObject *KX_TouchSensor::pyattr_get_object_hit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_TouchSensor* self = static_cast<KX_TouchSensor*>(self_v);
if (self->m_hitObject)
return self->m_hitObject->GetProxy();
else
Py_RETURN_NONE;
}
PyObject *KX_TouchSensor::pyattr_get_object_hit_list(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_TouchSensor* self = static_cast<KX_TouchSensor*>(self_v);
return self->m_colliders->GetProxy();
}
#endif
/* eof */