svn merge -r 21041:21301 https://svn.blender.org/svnroot/bf-blender/branches/blender2...
[blender.git] / source / gameengine / Ketsji / KX_NearSensor.cpp
1 /**
2  * Sense if other objects are near
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #include "KX_NearSensor.h"
33 #include "SCA_LogicManager.h"
34 #include "KX_GameObject.h"
35 #include "KX_TouchEventManager.h"
36 #include "KX_Scene.h" // needed to create a replica
37 #include "PHY_IPhysicsEnvironment.h"
38 #include "PHY_IPhysicsController.h"
39 #include "PHY_IMotionState.h"
40
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44 KX_NearSensor::KX_NearSensor(SCA_EventManager* eventmgr,
45                                                          KX_GameObject* gameobj,
46                                                          float margin,
47                                                          float resetmargin,
48                                                          bool bFindMaterial,
49                                                          const STR_String& touchedpropname,
50                                                          class KX_Scene* scene,
51                                                          PHY_IPhysicsController* ctrl)
52                          :KX_TouchSensor(eventmgr,
53                                                          gameobj,
54                                                          bFindMaterial,
55                                                          false,
56                                                          touchedpropname
57                                                          /*, scene */),
58                          m_Margin(margin),
59                          m_ResetMargin(resetmargin)
60
61 {
62
63         gameobj->getClientInfo()->m_sensors.remove(this);
64         m_client_info = new KX_ClientObjectInfo(gameobj, KX_ClientObjectInfo::SENSOR);
65         m_client_info->m_sensors.push_back(this);
66         
67         //DT_ShapeHandle shape = (DT_ShapeHandle) vshape;
68         m_physCtrl = ctrl;
69         if (m_physCtrl)
70         {
71                 m_physCtrl->SetMargin(m_Margin);
72                 m_physCtrl->setNewClientInfo(m_client_info);
73         }
74         SynchronizeTransform();
75 }
76
77 void KX_NearSensor::SynchronizeTransform()
78 {
79         // The near and radar sensors are using a different physical object which is 
80         // not linked to the parent object, must synchronize it.
81         if (m_physCtrl)
82         {
83                 PHY_IMotionState* motionState = m_physCtrl->GetMotionState();
84                 KX_GameObject* parent = ((KX_GameObject*)GetParent());
85                 const MT_Point3& pos = parent->NodeGetWorldPosition();
86                 float ori[12];
87                 parent->NodeGetWorldOrientation().getValue(ori);
88                 motionState->setWorldPosition(pos[0], pos[1], pos[2]);
89                 motionState->setWorldOrientation(ori);
90                 m_physCtrl->WriteMotionStateToDynamics(true);
91         }
92 }
93
94 CValue* KX_NearSensor::GetReplica()
95 {
96         KX_NearSensor* replica = new KX_NearSensor(*this);
97         replica->ProcessReplica();
98         return replica;
99 }
100
101 void KX_NearSensor::ProcessReplica()
102 {
103         KX_TouchSensor::ProcessReplica();
104         
105         m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::SENSOR);
106         
107         if (m_physCtrl)
108         {
109                 m_physCtrl = m_physCtrl->GetReplica();
110                 if (m_physCtrl)
111                 {
112                         //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->addSensor(replica->m_physCtrl);
113                         m_physCtrl->SetMargin(m_Margin);
114                         m_physCtrl->setNewClientInfo(m_client_info);
115                 }
116                 
117         }
118 }
119
120 void KX_NearSensor::ReParent(SCA_IObject* parent)
121 {
122         SCA_ISensor::ReParent(parent);
123         m_client_info->m_gameobject = static_cast<KX_GameObject*>(parent); 
124         m_client_info->m_sensors.push_back(this);
125         //Synchronize here with the actual parent.
126         SynchronizeTransform();
127 }
128
129
130
131 KX_NearSensor::~KX_NearSensor()
132 {
133         // for nearsensor, the sensor is the 'owner' of sumoobj
134         // for touchsensor, it's the parent
135         if (m_physCtrl)
136         {
137                 //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->removeSensor(m_physCtrl);
138                 delete m_physCtrl;
139                 m_physCtrl = NULL;
140         }
141         
142                 
143         if (m_client_info)
144                 delete m_client_info;
145 }
146
147
148 bool KX_NearSensor::Evaluate()
149 {
150         bool result = false;
151 //      KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
152
153         if (m_bTriggered != m_bLastTriggered)
154         {
155                 m_bLastTriggered = m_bTriggered;
156                 if (m_bTriggered)
157                 {
158                         if (m_physCtrl)
159                         {
160                                 m_physCtrl->SetRadius(m_ResetMargin);
161                         }
162                 } else
163                 {
164                         if (m_physCtrl)
165                         {
166                                 m_physCtrl->SetRadius(m_Margin);
167                         }
168
169                 }
170                 result = true;
171         }
172
173         return result;
174 }
175
176 // this function is called at broad phase stage to check if the two controller
177 // need to interact at all. It is used for Near/Radar sensor that don't need to
178 // check collision with object not included in filter
179 bool    KX_NearSensor::BroadPhaseFilterCollision(void*obj1,void*obj2)
180 {
181         KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
182         
183         // need the mapping from PHY_IPhysicsController to gameobjects now
184         assert(obj1==m_physCtrl && obj2);
185         KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>((static_cast<PHY_IPhysicsController*>(obj2))->getNewClientInfo());
186
187         KX_GameObject* gameobj = ( client_info ? 
188                         client_info->m_gameobject :
189                         NULL);
190         
191         if (gameobj && (gameobj != parent))
192         {
193                 // only take valid colliders
194                 if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
195                 {
196                         if ((m_touchedpropname.Length() == 0) || 
197                                 (gameobj->GetProperty(m_touchedpropname)))
198                         {
199                                 return true;
200                         }
201                 }
202         }
203
204         return false;
205 }
206
207 bool    KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData * coll_data)
208 {
209 //      KX_TouchEventManager* toucheventmgr = static_cast<KX_TouchEventManager*>(m_eventmgr);
210 //      KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
211         
212         // need the mapping from PHY_IPhysicsController to gameobjects now
213         
214         KX_ClientObjectInfo* client_info =static_cast<KX_ClientObjectInfo*> (obj1 == m_physCtrl? 
215                                         ((PHY_IPhysicsController*)obj2)->getNewClientInfo() : 
216                                         ((PHY_IPhysicsController*)obj1)->getNewClientInfo());
217
218         KX_GameObject* gameobj = ( client_info ? 
219                         client_info->m_gameobject :
220                         NULL);
221         
222         // Add the same check as in SCA_ISensor::Activate(), 
223         // we don't want to record collision when the sensor is not active.
224         if (m_links && !m_suspended &&
225                 gameobj /* done in BroadPhaseFilterCollision() && (gameobj != parent)*/)
226         {
227                 if (!m_colliders->SearchValue(gameobj))
228                         m_colliders->Add(gameobj->AddRef());
229                 // only take valid colliders
230                 // These checks are done already in BroadPhaseFilterCollision()
231                 //if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
232                 //{
233                 //      if ((m_touchedpropname.Length() == 0) || 
234                 //              (gameobj->GetProperty(m_touchedpropname)))
235                 //      {
236                                 m_bTriggered = true;
237                                 m_hitObject = gameobj;
238                 //      }
239                 //}
240         }
241         
242         return false; // was DT_CONTINUE; but this was defined in Sumo as false
243 }
244
245
246 /* ------------------------------------------------------------------------- */
247 /* Python Functions                                                                                                                      */
248 /* ------------------------------------------------------------------------- */
249
250 //No methods
251
252 /* ------------------------------------------------------------------------- */
253 /* Python Integration Hooks                                                  */
254 /* ------------------------------------------------------------------------- */
255
256 PyTypeObject KX_NearSensor::Type = {
257 #if (PY_VERSION_HEX >= 0x02060000)
258         PyVarObject_HEAD_INIT(NULL, 0)
259 #else
260         /* python 2.5 and below */
261         PyObject_HEAD_INIT( NULL )  /* required py macro */
262         0,                          /* ob_size */
263 #endif
264         "KX_NearSensor",
265         sizeof(PyObjectPlus_Proxy),
266         0,
267         py_base_dealloc,
268         0,
269         0,
270         0,
271         0,
272         py_base_repr,
273         0,0,0,0,0,0,0,0,0,
274         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
275         0,0,0,0,0,0,0,
276         Methods,
277         0,
278         0,
279         &KX_TouchSensor::Type,
280         0,0,0,0,0,0,
281         py_base_new
282 };
283
284 PyMethodDef KX_NearSensor::Methods[] = {
285         //No methods
286         {NULL,NULL} //Sentinel
287 };
288
289 PyAttributeDef KX_NearSensor::Attributes[] = {
290         KX_PYATTRIBUTE_FLOAT_RW_CHECK("distance", 0, 100, KX_NearSensor, m_Margin, CheckResetDistance),
291         KX_PYATTRIBUTE_FLOAT_RW_CHECK("resetDistance", 0, 100, KX_NearSensor, m_ResetMargin, CheckResetDistance),
292         {NULL} //Sentinel
293 };