Blender  V2.59
KX_TouchSensor.cpp
Go to the documentation of this file.
00001 /*
00002  * Senses touch and collision events
00003  *
00004  * $Id: KX_TouchSensor.cpp 35171 2011-02-25 13:35:59Z jesterking $
00005  *
00006  * ***** BEGIN GPL LICENSE BLOCK *****
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License
00010  * as published by the Free Software Foundation; either version 2
00011  * of the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software Foundation,
00020  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00021  *
00022  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00023  * All rights reserved.
00024  *
00025  * The Original Code is: all of this file.
00026  *
00027  * Contributor(s): none yet.
00028  *
00029  * ***** END GPL LICENSE BLOCK *****
00030  */
00031 
00037 #include "KX_TouchSensor.h"
00038 #include "SCA_EventManager.h"
00039 #include "SCA_LogicManager.h"
00040 #include "KX_GameObject.h"
00041 #include "KX_TouchEventManager.h"
00042 
00043 #include "PHY_IPhysicsController.h"
00044 
00045 #include <iostream>
00046 #include "PHY_IPhysicsEnvironment.h"
00047 
00048 /* ------------------------------------------------------------------------- */
00049 /* Native functions                                                          */
00050 /* ------------------------------------------------------------------------- */
00051 
00052 void KX_TouchSensor::SynchronizeTransform()
00053 {
00054         // the touch sensor does not require any synchronization: it uses
00055         // the same physical object which is already synchronized by Blender
00056 }
00057 
00058 
00059 void KX_TouchSensor::EndFrame() {
00060         m_colliders->ReleaseAndRemoveAll();
00061         m_hitObject = NULL;
00062         m_bTriggered = false;
00063         m_bColliderHash = 0;
00064 }
00065 
00066 void KX_TouchSensor::UnregisterToManager()
00067 {
00068         // before unregistering the sensor, make sure we release all references
00069         EndFrame();
00070         SCA_ISensor::UnregisterToManager();
00071 }
00072 
00073 bool KX_TouchSensor::Evaluate()
00074 {
00075         bool result = false;
00076         bool reset = m_reset && m_level;
00077         m_reset = false;
00078         if (m_bTriggered != m_bLastTriggered)
00079         {
00080                 m_bLastTriggered = m_bTriggered;
00081                 if (!m_bTriggered)
00082                         m_hitObject = NULL;
00083                 result = true;
00084         }
00085         if (reset)
00086                 // force an event
00087                 result = true;
00088         
00089         if (m_bTouchPulse) { /* pulse on changes to the colliders */
00090                 int count = m_colliders->GetCount();
00091                 
00092                 if (m_bLastCount!=count || m_bColliderHash!=m_bLastColliderHash) {
00093                         m_bLastCount = count;
00094                         m_bLastColliderHash= m_bColliderHash;
00095                         result = true;
00096                 }
00097         }
00098         return result;
00099 }
00100 
00101 KX_TouchSensor::KX_TouchSensor(SCA_EventManager* eventmgr,KX_GameObject* gameobj,bool bFindMaterial,bool bTouchPulse,const STR_String& touchedpropname)
00102 :SCA_ISensor(gameobj,eventmgr),
00103 m_touchedpropname(touchedpropname),
00104 m_bFindMaterial(bFindMaterial),
00105 m_bTouchPulse(bTouchPulse)
00106 /*m_sumoObj(sumoObj),*/
00107 {
00108 //      KX_TouchEventManager* touchmgr = (KX_TouchEventManager*) eventmgr;
00109 //      m_resptable = touchmgr->GetResponseTable();
00110         
00111 //      m_solidHandle = m_sumoObj->getObjectHandle();
00112 
00113         m_colliders = new CListValue();
00114         
00115         KX_ClientObjectInfo *client_info = gameobj->getClientInfo();
00116         //client_info->m_gameobject = gameobj;
00117         //client_info->m_auxilary_info = NULL;
00118         client_info->m_sensors.push_back(this);
00119         
00120         m_physCtrl = dynamic_cast<PHY_IPhysicsController*>(gameobj->GetPhysicsController());
00121         MT_assert( !gameobj->GetPhysicsController() || m_physCtrl );
00122         Init();
00123 }
00124 
00125 void KX_TouchSensor::Init()
00126 {
00127         m_bCollision = false;
00128         m_bTriggered = false;
00129         m_bLastTriggered = (m_invert)?true:false;
00130         m_bLastCount = 0;
00131         m_bColliderHash = m_bLastColliderHash = 0;
00132         m_hitObject =  NULL;
00133         m_reset = true;
00134 }
00135 
00136 KX_TouchSensor::~KX_TouchSensor()
00137 {
00138         //DT_ClearObjectResponse(m_resptable,m_solidHandle);
00139         m_colliders->Release();
00140 }
00141 
00142 CValue* KX_TouchSensor::GetReplica() 
00143 {
00144         KX_TouchSensor* replica = new KX_TouchSensor(*this);
00145         replica->ProcessReplica();
00146         return replica;
00147 }
00148 
00149 void KX_TouchSensor::ProcessReplica()
00150 {
00151         SCA_ISensor::ProcessReplica();
00152         m_colliders = new CListValue();
00153         Init();
00154 }
00155 
00156 void    KX_TouchSensor::ReParent(SCA_IObject* parent)
00157 {
00158         KX_GameObject *gameobj = static_cast<KX_GameObject *>(parent);
00159         PHY_IPhysicsController *sphy = dynamic_cast<PHY_IPhysicsController*>(((KX_GameObject*)parent)->GetPhysicsController());
00160         if (sphy)
00161                 m_physCtrl = sphy;
00162         
00163 //      m_solidHandle = m_sumoObj->getObjectHandle();
00164         KX_ClientObjectInfo *client_info = gameobj->getClientInfo();
00165         //client_info->m_gameobject = gameobj;
00166         //client_info->m_auxilary_info = NULL;
00167         
00168         client_info->m_sensors.push_back(this);
00169         SCA_ISensor::ReParent(parent);
00170 }
00171 
00172 void KX_TouchSensor::RegisterSumo(KX_TouchEventManager *touchman)
00173 {
00174         if (m_physCtrl)
00175         {
00176                 if (touchman->GetPhysicsEnvironment()->requestCollisionCallback(m_physCtrl))
00177                 {
00178                         KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>(m_physCtrl->getNewClientInfo());
00179                         if (client_info->isSensor())
00180                                 touchman->GetPhysicsEnvironment()->addSensor(m_physCtrl);
00181                 }
00182         }
00183 }
00184 void KX_TouchSensor::UnregisterSumo(KX_TouchEventManager* touchman)
00185 {
00186         if (m_physCtrl)
00187         {
00188                 if (touchman->GetPhysicsEnvironment()->removeCollisionCallback(m_physCtrl))
00189                 {
00190                         // no more sensor on the controller, can remove it if it is a sensor object
00191                         KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>(m_physCtrl->getNewClientInfo());
00192                         if (client_info->isSensor())
00193                                 touchman->GetPhysicsEnvironment()->removeSensor(m_physCtrl);
00194                 }
00195         }
00196 }
00197 
00198 // this function is called only for sensor objects
00199 // return true if the controller can collide with the object
00200 bool    KX_TouchSensor::BroadPhaseSensorFilterCollision(void*obj1,void*obj2)
00201 {
00202         assert(obj1==m_physCtrl && obj2);
00203 
00204         KX_GameObject* myobj = (KX_GameObject*)GetParent();
00205         KX_GameObject* myparent = myobj->GetParent();
00206         KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>(((PHY_IPhysicsController*)obj2)->getNewClientInfo());
00207         KX_ClientObjectInfo* my_client_info = static_cast<KX_ClientObjectInfo*>(m_physCtrl->getNewClientInfo());
00208         KX_GameObject* otherobj = ( client_info ? client_info->m_gameobject : NULL);
00209 
00210         // first, decrement refcount as GetParent() increases it
00211         if (myparent)
00212                 myparent->Release();
00213 
00214         // we can only check on persistent characteristic: m_link and m_suspended are not
00215         // good candidate because they are transient. That must be handled at another level
00216         if (!otherobj ||
00217                 otherobj == myparent ||         // don't interact with our parent
00218                 (my_client_info->m_type == KX_ClientObjectInfo::OBACTORSENSOR &&
00219                  client_info->m_type != KX_ClientObjectInfo::ACTOR))    // only with actor objects
00220                 return false;
00221                 
00222         bool found = m_touchedpropname.IsEmpty();
00223         if (!found)
00224         {
00225                 if (m_bFindMaterial)
00226                 {
00227                         if (client_info->m_auxilary_info)
00228                         {
00229                                 found = (!strcmp(m_touchedpropname.Ptr(), (char*)client_info->m_auxilary_info));
00230                         }
00231                 } else
00232                 {
00233                         found = (otherobj->GetProperty(m_touchedpropname) != NULL);
00234                 }
00235         }
00236         return found;
00237 }
00238 
00239 bool    KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_CollData* colldata)
00240 {
00241 //      KX_TouchEventManager* toucheventmgr = (KX_TouchEventManager*)m_eventmgr;
00242         KX_GameObject* parent = (KX_GameObject*)GetParent();
00243 
00244         // need the mapping from PHY_IPhysicsController to gameobjects now
00245         
00246         KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*> (object1 == m_physCtrl? 
00247                                         ((PHY_IPhysicsController*)object2)->getNewClientInfo(): 
00248                                         ((PHY_IPhysicsController*)object1)->getNewClientInfo());
00249 
00250         KX_GameObject* gameobj = ( client_info ? 
00251                         client_info->m_gameobject : 
00252                         NULL);
00253         
00254         // add the same check as in SCA_ISensor::Activate(), 
00255         // we don't want to record collision when the sensor is not active.
00256         if (m_links && !m_suspended &&
00257                 gameobj && (gameobj != parent) && client_info->isActor())
00258         {
00259                 
00260                 bool found = m_touchedpropname.IsEmpty();
00261                 if (!found)
00262                 {
00263                         if (m_bFindMaterial)
00264                         {
00265                                 if (client_info->m_auxilary_info)
00266                                 {
00267                                         found = (!strcmp(m_touchedpropname.Ptr(), (char*)client_info->m_auxilary_info));
00268                                 }
00269                         } else
00270                         {
00271                                 found = (gameobj->GetProperty(m_touchedpropname) != NULL);
00272                         }
00273                 }
00274                 if (found)
00275                 {
00276                         if (!m_colliders->SearchValue(gameobj)) {
00277                                 m_colliders->Add(gameobj->AddRef());
00278                                 
00279                                 if (m_bTouchPulse)
00280                                         m_bColliderHash += (uint_ptr)(static_cast<void *>(&gameobj));
00281                         }
00282                         m_bTriggered = true;
00283                         m_hitObject = gameobj;
00284                         //printf("KX_TouchSensor::HandleCollision\n");
00285                 }
00286                 
00287         } 
00288         return false; // was DT_CONTINUE but this was defined in sumo as false.
00289 }
00290 
00291 #ifdef WITH_PYTHON
00292 
00293 /* ------------------------------------------------------------------------- */
00294 /* Python functions                                                          */
00295 /* ------------------------------------------------------------------------- */
00296 /* Integration hooks ------------------------------------------------------- */
00297 PyTypeObject KX_TouchSensor::Type = {
00298         PyVarObject_HEAD_INIT(NULL, 0)
00299         "KX_TouchSensor",
00300         sizeof(PyObjectPlus_Proxy),
00301         0,
00302         py_base_dealloc,
00303         0,
00304         0,
00305         0,
00306         0,
00307         py_base_repr,
00308         0,0,0,0,0,0,0,0,0,
00309         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00310         0,0,0,0,0,0,0,
00311         Methods,
00312         0,
00313         0,
00314         &SCA_ISensor::Type,
00315         0,0,0,0,0,0,
00316         py_base_new
00317 };
00318 
00319 PyMethodDef KX_TouchSensor::Methods[] = {
00320         {NULL,NULL} //Sentinel
00321 };
00322 
00323 PyAttributeDef KX_TouchSensor::Attributes[] = {
00324         KX_PYATTRIBUTE_STRING_RW("propName",0,100,false,KX_TouchSensor,m_touchedpropname),
00325         KX_PYATTRIBUTE_BOOL_RW("useMaterial",KX_TouchSensor,m_bFindMaterial),
00326         KX_PYATTRIBUTE_BOOL_RW("usePulseCollision",KX_TouchSensor,m_bTouchPulse),
00327         KX_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_TouchSensor, pyattr_get_object_hit),
00328         KX_PYATTRIBUTE_RO_FUNCTION("hitObjectList", KX_TouchSensor, pyattr_get_object_hit_list),
00329         { NULL }        //Sentinel
00330 };
00331 
00332 /* Python API */
00333 
00334 PyObject* KX_TouchSensor::pyattr_get_object_hit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00335 {
00336         KX_TouchSensor* self= static_cast<KX_TouchSensor*>(self_v);
00337         
00338         if (self->m_hitObject)
00339                 return self->m_hitObject->GetProxy();
00340         else
00341                 Py_RETURN_NONE;
00342 }
00343 
00344 PyObject* KX_TouchSensor::pyattr_get_object_hit_list(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00345 {
00346         KX_TouchSensor* self= static_cast<KX_TouchSensor*>(self_v);
00347         return self->m_colliders->GetProxy();
00348 }
00349 
00350 #endif
00351 
00352 /* eof */