Blender V2.61 - r43446
|
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 */