fixed the mouse-over sensor,
[blender-staging.git] / source / gameengine / Ketsji / KX_RaySensor.cpp
1 /**
2  * Cast a ray and feel for objects
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL/BL DUAL 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. The Blender
12  * Foundation also sells licenses for use in proprietary software under
13  * the Blender License.  See http://www.blender.org/BL/ for information
14  * about this.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
26  * All rights reserved.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL/BL DUAL LICENSE BLOCK *****
33  */
34
35 #include "KX_RaySensor.h"
36 #include "SCA_EventManager.h"
37 #include "SCA_RandomEventManager.h"
38 #include "SCA_LogicManager.h"
39 #include "SCA_IObject.h"
40 #include "KX_ClientObjectInfo.h"
41 #include "KX_GameObject.h"
42 #include "KX_Scene.h"
43
44 #include "KX_RayCast.h"
45 #include "PHY_IPhysicsEnvironment.h"
46 #include "PHY_IPhysicsController.h"
47 #include "KX_IPhysicsController.h"
48
49
50 #ifdef HAVE_CONFIG_H
51 #include <config.h>
52 #endif
53
54 KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr,
55                                         SCA_IObject* gameobj,
56                                         const STR_String& propname,
57                                         bool bFindMaterial,
58                                         double distance,
59                                         int axis,
60                                         KX_Scene* ketsjiScene,
61                                         PyTypeObject* T)
62                         : SCA_ISensor(gameobj,eventmgr, T),
63                                         m_propertyname(propname),
64                                         m_bFindMaterial(bFindMaterial),
65                                         m_distance(distance),
66                                         m_scene(ketsjiScene),
67                                         m_bTriggered(false),
68                                         m_axis(axis),
69                                         m_rayHit(false),
70                                         m_hitObject(NULL)
71
72                                 
73 {
74
75 }
76
77
78
79 KX_RaySensor::~KX_RaySensor() 
80 {
81     /* Nothing to be done here. */
82 }
83
84
85
86 CValue* KX_RaySensor::GetReplica()
87 {
88         CValue* replica = new KX_RaySensor(*this);
89         // this will copy properties and so on...
90         CValue::AddDataToReplica(replica);
91
92         return replica;
93 }
94
95
96
97 bool KX_RaySensor::IsPositiveTrigger()
98 {
99         bool result = m_rayHit;
100
101         if (m_invert)
102                 result = !result;
103         
104         return result;
105 }
106
107 bool KX_RaySensor::RayHit(KX_ClientObjectInfo* info, MT_Point3& hit_point, MT_Vector3& hit_normal, void* const data)
108 {
109         printf("KX_RaySensor::RayHit\n");
110
111         KX_GameObject* obj = (KX_GameObject*)GetParent();
112         SCA_IObject *hitgameobj = info->m_gameobject;
113         if (hitgameobj == obj || info->m_type > KX_ClientObjectInfo::ACTOR)
114         {
115                 printf("false hit\n");
116                 // false hit
117                 return false;
118         }
119         
120         bool bFound = false;
121         if (m_propertyname.Length() == 0)
122         {
123                 bFound = true;
124         }
125         else
126         {
127                 if (m_bFindMaterial)
128                 {
129                         if (info->m_auxilary_info)
130                         {
131                                 bFound = (m_propertyname== ((char*)info->m_auxilary_info));
132                         }
133                 }
134                 else
135                 {
136                         bFound = hitgameobj->GetProperty(m_propertyname) != NULL;
137                 }
138         }
139
140         if (bFound)
141         {
142                 m_rayHit = true;
143                 m_hitObject = hitgameobj;
144                 m_hitPosition = hit_point;
145                 m_hitNormal = hit_normal;
146                         
147         }
148         
149         return true;
150 }
151
152 bool KX_RaySensor::Evaluate(CValue* event)
153 {
154         bool result = false;
155         m_rayHit = false; 
156         m_hitObject = NULL;
157         m_hitPosition = MT_Vector3(0,0,0);
158         m_hitNormal = MT_Vector3(1,0,0);
159         
160         KX_GameObject* obj = (KX_GameObject*)GetParent();
161         MT_Point3 frompoint = obj->NodeGetWorldPosition();
162         MT_Matrix3x3 matje = obj->NodeGetWorldOrientation();
163         MT_Matrix3x3 invmat = matje.inverse();
164         
165         MT_Vector3 todir;
166         switch (m_axis)
167         {
168         case 1: // X
169                 {
170                         todir[0] = invmat[0][0];
171                         todir[1] = invmat[0][1];
172                         todir[2] = invmat[0][2];
173                         break;
174                 }
175         case 0: // Y
176                 {
177                         todir[0] = invmat[1][0];
178                         todir[1] = invmat[1][1];
179                         todir[2] = invmat[1][2];
180                         break;
181                 }
182         case 2: // Z
183                 {
184                         todir[0] = invmat[2][0];
185                         todir[1] = invmat[2][1];
186                         todir[2] = invmat[2][2];
187                         break;
188                 }
189         case 3: // -X
190                 {
191                         todir[0] = -invmat[0][0];
192                         todir[1] = -invmat[0][1];
193                         todir[2] = -invmat[0][2];
194                         break;
195                 }
196         case 4: // -Y
197                 {
198                         todir[0] = -invmat[1][0];
199                         todir[1] = -invmat[1][1];
200                         todir[2] = -invmat[1][2];
201                         break;
202                 }
203         case 5: // -Z
204                 {
205                         todir[0] = -invmat[2][0];
206                         todir[1] = -invmat[2][1];
207                         todir[2] = -invmat[2][2];
208                         break;
209                 }
210         }
211         todir.normalize();
212         m_rayDirection = todir;
213
214         MT_Point3 topoint = frompoint + (m_distance) * todir;
215         MT_Point3 resultpoint;
216         MT_Vector3 resultnormal;
217         PHY_IPhysicsEnvironment* physics_environment = m_scene->GetPhysicsEnvironment();
218         if (!physics_environment)
219         {
220                 std::cout << "WARNING: Ray sensor " << GetName() << ":  There is no physics environment!" << std::endl;
221                 std::cout << "         Check universe for malfunction." << std::endl;
222                 return false;
223         } 
224         KX_IPhysicsController* physics_controller = obj->GetPhysicsController();
225
226         // Use the parent's physics controller if obj has no physics controller.
227         KX_GameObject *parent = obj->GetParent();
228         if (!physics_controller && parent)
229                 physics_controller = parent->GetPhysicsController();
230
231         if (parent)
232                 parent->Release();
233                 
234         KX_RayCast::RayTest(physics_controller, physics_environment, frompoint, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_RaySensor>(this));
235
236 //      do {
237 //              PHY__Vector3 respos;
238 //              PHY__Vector3 resnormal;
239 // 
240 //              PHY_IPhysicsController* hitCtrl = spe->rayTest(physCtrl,
241 //                      frompoint.x(),frompoint.y(),frompoint.z(),
242 //                      topoint.x(),topoint.y(),topoint.z(),
243 //                      respos[0],respos[1],respos[2],
244 //                      resnormal[0],resnormal[1],resnormal[2]);
245 //                      
246 //              if (hitCtrl)
247 //              {
248 // 
249 //                      resultpoint = MT_Vector3(respos);
250 //                      resultnormal = MT_Vector3(resnormal);
251 //                      KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(hitCtrl->getNewClientInfo());
252 //                      bool bFound = false;
253 //                      
254 //                      if (!info)
255 //                      {
256 //                              std::cout<< "WARNING:  Ray sensor " << GetName() << " cannot sense PHY_IPhysicsController  - no client info.\n" << std::endl;
257 //                              ready = true;
258 //                              break;
259 //                      } 
260 //                      
261 //                      
262 // 
263 //              }
264 //              else
265 //              {
266 //                      ready = true;
267 //              }
268 //      }
269 //      while (!ready);
270 //      
271         
272         
273         /* now pass this result to some controller */
274         if (m_rayHit) 
275         {
276                 if (!m_bTriggered)
277                 {
278                         // notify logicsystem that ray is now hitting
279                         result = true;
280                         m_bTriggered = true;
281                 }
282         }
283         else
284         {
285                 if (m_bTriggered)
286                 {
287                         m_bTriggered = false;
288                         // notify logicsystem that ray is not hitting anymore
289                         result = true;
290                 }
291         }
292
293         return result;
294 }
295
296
297
298 /* ------------------------------------------------------------------------- */
299 /* Python functions                                                          */
300 /* ------------------------------------------------------------------------- */
301
302 /* Integration hooks ------------------------------------------------------- */
303 PyTypeObject KX_RaySensor::Type = {
304         PyObject_HEAD_INIT(&PyType_Type)
305         0,
306         "KX_RaySensor",
307         sizeof(KX_RaySensor),
308         0,
309         PyDestructor,
310         0,
311         __getattr,
312         __setattr,
313         0, //&MyPyCompare,
314         __repr,
315         0, //&cvalue_as_number,
316         0,
317         0,
318         0,
319         0
320 };
321
322 PyParentObject KX_RaySensor::Parents[] = {
323         &KX_RaySensor::Type,
324         &SCA_ISensor::Type,
325         &SCA_ILogicBrick::Type,
326         &CValue::Type,
327         NULL
328 };
329
330 PyMethodDef KX_RaySensor::Methods[] = {
331         {"getHitObject",(PyCFunction) KX_RaySensor::sPyGetHitObject,METH_VARARGS, GetHitObject_doc},
332         {"getHitPosition",(PyCFunction) KX_RaySensor::sPyGetHitPosition,METH_VARARGS, GetHitPosition_doc},
333         {"getHitNormal",(PyCFunction) KX_RaySensor::sPyGetHitNormal,METH_VARARGS, GetHitNormal_doc},
334         {"getRayDirection",(PyCFunction) KX_RaySensor::sPyGetRayDirection,METH_VARARGS, GetRayDirection_doc},
335         {NULL,NULL} //Sentinel
336 };
337
338 char KX_RaySensor::GetHitObject_doc[] = 
339 "getHitObject()\n"
340 "\tReturns the name of the object that was hit by this ray.\n";
341 PyObject* KX_RaySensor::PyGetHitObject(PyObject* self, 
342                                                                                    PyObject* args, 
343                                                                                    PyObject* kwds)
344 {
345         if (m_hitObject)
346         {
347                 return m_hitObject->AddRef();
348         }
349         Py_Return;
350 }
351
352
353 char KX_RaySensor::GetHitPosition_doc[] = 
354 "getHitPosition()\n"
355 "\tReturns the position (in worldcoordinates) where the object was hit by this ray.\n";
356 PyObject* KX_RaySensor::PyGetHitPosition(PyObject* self, 
357                                PyObject* args, 
358                                PyObject* kwds)
359 {
360
361         MT_Point3 pos = m_hitPosition;
362
363         PyObject* resultlist = PyList_New(3);
364         int index;
365         for (index=0;index<3;index++)
366         {
367                 PyList_SetItem(resultlist,index,PyFloat_FromDouble(pos[index]));
368         }
369         return resultlist;
370
371 }
372
373 char KX_RaySensor::GetRayDirection_doc[] = 
374 "getRayDirection()\n"
375 "\tReturns the direction from the ray (in worldcoordinates) .\n";
376 PyObject* KX_RaySensor::PyGetRayDirection(PyObject* self, 
377                                PyObject* args, 
378                                PyObject* kwds)
379 {
380
381         MT_Vector3 dir = m_rayDirection;
382
383         PyObject* resultlist = PyList_New(3);
384         int index;
385         for (index=0;index<3;index++)
386         {
387                 PyList_SetItem(resultlist,index,PyFloat_FromDouble(dir[index]));
388         }
389         return resultlist;
390
391 }
392
393 char KX_RaySensor::GetHitNormal_doc[] = 
394 "getHitNormal()\n"
395 "\tReturns the normal (in worldcoordinates) of the object at the location where the object was hit by this ray.\n";
396 PyObject* KX_RaySensor::PyGetHitNormal(PyObject* self, 
397                                PyObject* args, 
398                                PyObject* kwds)
399 {
400         MT_Vector3 pos = m_hitNormal;
401
402         PyObject* resultlist = PyList_New(3);
403         int index;
404         for (index=0;index<3;index++)
405         {
406                 PyList_SetItem(resultlist,index,PyFloat_FromDouble(pos[index]));
407         }
408         return resultlist;
409
410 }
411
412
413
414 PyObject* KX_RaySensor::_getattr(const STR_String& attr) {
415         _getattr_up(SCA_ISensor);
416 }