Blender V2.61 - r43446

KX_TouchSensor.cpp

Go to the documentation of this file.
00001 /*
00002  * Senses touch and collision events
00003  *
00004  *
00005  * ***** BEGIN GPL LICENSE BLOCK *****
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software Foundation,
00019  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00022  * All rights reserved.
00023  *
00024  * The Original Code is: all of this file.
00025  *
00026  * Contributor(s): none yet.
00027  *
00028  * ***** END GPL LICENSE BLOCK *****
00029  */
00030 
00036 #include "KX_TouchSensor.h"
00037 #include "SCA_EventManager.h"
00038 #include "SCA_LogicManager.h"
00039 #include "KX_GameObject.h"
00040 #include "KX_TouchEventManager.h"
00041 
00042 #include "PHY_IPhysicsController.h"
00043 
00044 #include <iostream>
00045 #include "PHY_IPhysicsEnvironment.h"
00046 
00047 /* ------------------------------------------------------------------------- */
00048 /* Native functions                                                          */
00049 /* ------------------------------------------------------------------------- */
00050 
00051 void KX_TouchSensor::SynchronizeTransform()
00052 {
00053     // the touch sensor does not require any synchronization: it uses
00054     // the same physical object which is already synchronized by Blender
00055 }
00056 
00057 
00058 void KX_TouchSensor::EndFrame()
00059 {
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,MAX_PROP_NAME,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 */