add missing files after merging
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file gameengine/Ketsji/KX_NearSensor.cpp
33  *  \ingroup ketsji
34  */
35
36
37 #include "KX_NearSensor.h"
38 #include "SCA_LogicManager.h"
39 #include "KX_GameObject.h"
40 #include "KX_TouchEventManager.h"
41 #include "KX_Scene.h" // needed to create a replica
42 #include "PHY_IPhysicsEnvironment.h"
43 #include "PHY_IPhysicsController.h"
44 #include "PHY_IMotionState.h"
45
46 KX_NearSensor::KX_NearSensor(SCA_EventManager* eventmgr,
47                                                          KX_GameObject* gameobj,
48                                                          float margin,
49                                                          float resetmargin,
50                                                          bool bFindMaterial,
51                                                          const STR_String& touchedpropname,
52                                                          PHY_IPhysicsController* ctrl)
53                          :KX_TouchSensor(eventmgr,
54                                                          gameobj,
55                                                          bFindMaterial,
56                                                          false,
57                                                          touchedpropname),
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 void KX_NearSensor::SetPhysCtrlRadius()
148 {
149         if (m_bTriggered)
150         {
151                 if (m_physCtrl)
152                 {
153                         m_physCtrl->SetRadius(m_ResetMargin);
154                 }
155         } else
156         {
157                 if (m_physCtrl)
158                 {
159                         m_physCtrl->SetRadius(m_Margin);
160                 }
161         }
162 }
163
164 bool KX_NearSensor::Evaluate()
165 {
166         bool result = false;
167 //      KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
168
169         if (m_bTriggered != m_bLastTriggered)
170         {
171                 m_bLastTriggered = m_bTriggered;
172                 
173                 SetPhysCtrlRadius();
174                 
175                 result = true;
176         }
177
178         return result;
179 }
180
181 // this function is called at broad phase stage to check if the two controller
182 // need to interact at all. It is used for Near/Radar sensor that don't need to
183 // check collision with object not included in filter
184 bool    KX_NearSensor::BroadPhaseFilterCollision(void*obj1,void*obj2)
185 {
186         KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
187         
188         // need the mapping from PHY_IPhysicsController to gameobjects now
189         assert(obj1==m_physCtrl && obj2);
190         KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>((static_cast<PHY_IPhysicsController*>(obj2))->getNewClientInfo());
191
192         KX_GameObject* gameobj = ( client_info ? 
193                         client_info->m_gameobject :
194                         NULL);
195         
196         if (gameobj && (gameobj != parent))
197         {
198                 // only take valid colliders
199                 if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
200                 {
201                         if ((m_touchedpropname.Length() == 0) || 
202                                 (gameobj->GetProperty(m_touchedpropname)))
203                         {
204                                 return true;
205                         }
206                 }
207         }
208
209         return false;
210 }
211
212 bool    KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData * coll_data)
213 {
214 //      KX_TouchEventManager* toucheventmgr = static_cast<KX_TouchEventManager*>(m_eventmgr);
215 //      KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
216         
217         // need the mapping from PHY_IPhysicsController to gameobjects now
218         
219         KX_ClientObjectInfo* client_info =static_cast<KX_ClientObjectInfo*> (obj1 == m_physCtrl? 
220                                         ((PHY_IPhysicsController*)obj2)->getNewClientInfo() : 
221                                         ((PHY_IPhysicsController*)obj1)->getNewClientInfo());
222
223         KX_GameObject* gameobj = ( client_info ? 
224                         client_info->m_gameobject :
225                         NULL);
226         
227         // Add the same check as in SCA_ISensor::Activate(), 
228         // we don't want to record collision when the sensor is not active.
229         if (m_links && !m_suspended &&
230                 gameobj /* done in BroadPhaseFilterCollision() && (gameobj != parent)*/)
231         {
232                 if (!m_colliders->SearchValue(gameobj))
233                         m_colliders->Add(gameobj->AddRef());
234                 // only take valid colliders
235                 // These checks are done already in BroadPhaseFilterCollision()
236                 //if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
237                 //{
238                 //      if ((m_touchedpropname.Length() == 0) || 
239                 //              (gameobj->GetProperty(m_touchedpropname)))
240                 //      {
241                                 m_bTriggered = true;
242                                 m_hitObject = gameobj;
243                 //      }
244                 //}
245         }
246         
247         return false; // was DT_CONTINUE; but this was defined in Sumo as false
248 }
249
250 #ifdef WITH_PYTHON
251
252 /* ------------------------------------------------------------------------- */
253 /* Python Functions                                                                                                                      */
254 /* ------------------------------------------------------------------------- */
255
256 /* ------------------------------------------------------------------------- */
257 /* Python Integration Hooks                                                  */
258 /* ------------------------------------------------------------------------- */
259
260 PyTypeObject KX_NearSensor::Type = {
261         PyVarObject_HEAD_INIT(NULL, 0)
262         "KX_NearSensor",
263         sizeof(PyObjectPlus_Proxy),
264         0,
265         py_base_dealloc,
266         0,
267         0,
268         0,
269         0,
270         py_base_repr,
271         0,0,0,0,0,0,0,0,0,
272         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
273         0,0,0,0,0,0,0,
274         Methods,
275         0,
276         0,
277         &KX_TouchSensor::Type,
278         0,0,0,0,0,0,
279         py_base_new
280 };
281
282 PyMethodDef KX_NearSensor::Methods[] = {
283         //No methods
284         {NULL,NULL} //Sentinel
285 };
286
287 PyAttributeDef KX_NearSensor::Attributes[] = {
288         KX_PYATTRIBUTE_FLOAT_RW_CHECK("distance", 0, 100, KX_NearSensor, m_Margin, CheckResetDistance),
289         KX_PYATTRIBUTE_FLOAT_RW_CHECK("resetDistance", 0, 100, KX_NearSensor, m_ResetMargin, CheckResetDistance),
290         {NULL} //Sentinel
291 };
292
293 #endif // WITH_PYTHON