BGE patch #13625: getLinearVelocity() rewrite to use only vector and matrix operations
[blender.git] / source / gameengine / Ketsji / KX_GameObject.cpp
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  * Game object wrapper
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #if defined(_WIN64)
36 typedef unsigned __int64 uint_ptr;
37 #else
38 typedef unsigned long uint_ptr;
39 #endif
40
41 #ifdef WIN32
42 // This warning tells us about truncation of __long__ stl-generated names.
43 // It can occasionally cause DevStudio to have internal compiler warnings.
44 #pragma warning( disable : 4786 )     
45 #endif
46
47
48 #define KX_INERTIA_INFINITE 10000
49 #include "RAS_IPolygonMaterial.h"
50 #include "KX_BlenderMaterial.h"
51 #include "KX_GameObject.h"
52 #include "RAS_MeshObject.h"
53 #include "KX_MeshProxy.h"
54 #include <stdio.h> // printf
55 #include "SG_Controller.h"
56 #include "KX_IPhysicsController.h"
57 #include "SG_Node.h"
58 #include "SG_Controller.h"
59 #include "KX_ClientObjectInfo.h"
60 #include "RAS_BucketManager.h"
61 #include "KX_RayCast.h"
62 #include "KX_PythonInit.h"
63 #include "KX_PyMath.h"
64
65 // This file defines relationships between parents and children
66 // in the game engine.
67
68 #include "KX_SG_NodeRelationships.h"
69
70 KX_GameObject::KX_GameObject(
71         void* sgReplicationInfo,
72         SG_Callbacks callbacks,
73         PyTypeObject* T
74 ) : 
75         SCA_IObject(T),
76         m_bDyna(false),
77         m_layer(0),
78         m_bSuspendDynamics(false),
79         m_bUseObjectColor(false),
80         m_bIsNegativeScaling(false),
81         m_pBlenderObject(NULL),
82         m_bVisible(true),
83         m_pPhysicsController1(NULL),
84         m_pPhysicsEnvironment(NULL),
85         m_pHitObject(NULL),
86         m_isDeformable(false)
87 {
88         m_ignore_activity_culling = false;
89         m_pClient_info = new KX_ClientObjectInfo(this, KX_ClientObjectInfo::ACTOR);
90         m_pSGNode = new SG_Node(this,sgReplicationInfo,callbacks);
91
92         // define the relationship between this node and it's parent.
93         
94         KX_NormalParentRelation * parent_relation = 
95                 KX_NormalParentRelation::New();
96         m_pSGNode->SetParentRelation(parent_relation);
97         
98
99 };
100
101
102
103 KX_GameObject::~KX_GameObject()
104 {
105         // is this delete somewhere ?
106         //if (m_sumoObj)
107         //      delete m_sumoObj;
108         delete m_pClient_info;
109         //if (m_pSGNode)
110         //      delete m_pSGNode;
111         if (m_pSGNode)
112         {
113                 // must go through controllers and make sure they will not use us anymore
114                 // This is important for KX_BulletPhysicsControllers that unregister themselves
115                 // from the object when they are deleted.
116                 SGControllerList::iterator contit;
117                 SGControllerList& controllers = m_pSGNode->GetSGControllerList();
118                 for (contit = controllers.begin();contit!=controllers.end();++contit)
119                 {
120                         (*contit)->ClearObject();
121                 }
122                 m_pSGNode->SetSGClientObject(NULL);
123         }
124 }
125
126
127
128 CValue* KX_GameObject:: Calc(VALUE_OPERATOR op, CValue *val) 
129 {
130         return NULL;
131 }
132
133
134
135 CValue* KX_GameObject::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val)
136 {
137         return NULL;
138 }
139
140
141
142 const STR_String & KX_GameObject::GetText()
143 {
144         return m_text;
145 }
146
147
148
149 float KX_GameObject::GetNumber()
150 {
151         return 0;
152 }
153
154
155
156 STR_String KX_GameObject::GetName()
157 {
158         return m_name;
159 }
160
161
162
163 void KX_GameObject::SetName(STR_String name)
164 {
165         m_name = name;
166 };                                                              // Set the name of the value
167
168
169
170 void KX_GameObject::ReplicaSetName(STR_String name)
171 {
172 }
173
174
175
176
177
178
179 KX_IPhysicsController* KX_GameObject::GetPhysicsController()
180 {
181         return m_pPhysicsController1;
182 }
183
184
185
186
187
188 KX_GameObject* KX_GameObject::GetParent()
189 {
190         KX_GameObject* result = NULL;
191         SG_Node* node = m_pSGNode;
192         
193         while (node && !result)
194         {
195                 node = node->GetSGParent();
196                 if (node)
197                         result = (KX_GameObject*)node->GetSGClientObject();
198         }
199         
200         if (result)
201                 result->AddRef();
202
203         return result;
204         
205 }
206
207 void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj)
208 {
209         if (obj && GetSGNode()->GetSGParent() != obj->GetSGNode())
210         {
211                 // Make sure the objects have some scale
212                 MT_Vector3 scale1 = NodeGetWorldScaling();
213                 MT_Vector3 scale2 = obj->NodeGetWorldScaling();
214                 if (fabs(scale2[0]) < FLT_EPSILON || 
215                         fabs(scale2[1]) < FLT_EPSILON || 
216                         fabs(scale2[2]) < FLT_EPSILON || 
217                         fabs(scale1[0]) < FLT_EPSILON || 
218                         fabs(scale1[1]) < FLT_EPSILON || 
219                         fabs(scale1[2]) < FLT_EPSILON) { return; }
220
221                 // Remove us from our old parent and set our new parent
222                 RemoveParent(scene);
223                 obj->GetSGNode()->AddChild(GetSGNode());
224
225                 // Set us to our new scale, position, and orientation
226                 scale1[0] = scale1[0]/scale2[0];
227                 scale1[1] = scale1[1]/scale2[1];
228                 scale1[2] = scale1[2]/scale2[2];
229                 MT_Matrix3x3 invori = obj->NodeGetWorldOrientation().inverse();
230                 MT_Vector3 newpos = invori*(NodeGetWorldPosition()-obj->NodeGetWorldPosition())*scale1;
231
232                 NodeSetLocalScale(scale1);
233                 NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2]));
234                 NodeSetLocalOrientation(invori*NodeGetWorldOrientation());
235                 NodeUpdateGS(0.f,true);
236                 // object will now be a child, it must be removed from the parent list
237                 CListValue* rootlist = scene->GetRootParentList();
238                 if (rootlist->RemoveValue(this))
239                         // the object was in parent list, decrement ref count as it's now removed
240                         Release();
241         }
242 }
243
244 void KX_GameObject::RemoveParent(KX_Scene *scene)
245 {
246         if (GetSGNode()->GetSGParent())
247         {
248                 // Set us to the right spot 
249                 GetSGNode()->SetLocalScale(GetSGNode()->GetWorldScaling());
250                 GetSGNode()->SetLocalOrientation(GetSGNode()->GetWorldOrientation());
251                 GetSGNode()->SetLocalPosition(GetSGNode()->GetWorldPosition());
252
253                 // Remove us from our parent
254                 GetSGNode()->DisconnectFromParent();
255                 NodeUpdateGS(0.f,true);
256                 // the object is now a root object, add it to the parentlist
257                 CListValue* rootlist = scene->GetRootParentList();
258                 if (!rootlist->SearchValue(this))
259                         // object was not in root list, add it now and increment ref count
260                         rootlist->Add(AddRef());
261         }
262 }
263
264 void KX_GameObject::ProcessReplica(KX_GameObject* replica)
265 {
266         replica->m_pPhysicsController1 = NULL;
267         replica->m_pSGNode = NULL;
268         replica->m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info);
269         replica->m_pClient_info->m_gameobject = replica;
270 }
271
272
273
274 CValue* KX_GameObject::GetReplica()
275 {
276         KX_GameObject* replica = new KX_GameObject(*this);
277         
278         // this will copy properties and so on...
279         CValue::AddDataToReplica(replica);
280         ProcessReplica(replica);
281         
282         return replica;
283 }
284
285
286
287 void KX_GameObject::ApplyForce(const MT_Vector3& force,bool local)
288 {
289         if (m_pPhysicsController1)
290                 m_pPhysicsController1->ApplyForce(force,local);
291 }
292
293
294
295 void KX_GameObject::ApplyTorque(const MT_Vector3& torque,bool local)
296 {
297         if (m_pPhysicsController1)
298                 m_pPhysicsController1->ApplyTorque(torque,local);
299 }
300
301
302
303 void KX_GameObject::ApplyMovement(const MT_Vector3& dloc,bool local)
304 {
305         if (m_pPhysicsController1) // (IsDynamic())
306         {
307                 m_pPhysicsController1->RelativeTranslate(dloc,local);
308         }
309         GetSGNode()->RelativeTranslate(dloc,GetSGNode()->GetSGParent(),local);
310 }
311
312
313
314 void KX_GameObject::ApplyRotation(const MT_Vector3& drot,bool local)
315 {
316         MT_Matrix3x3 rotmat(drot);
317
318         GetSGNode()->RelativeRotate(rotmat,local);
319
320         if (m_pPhysicsController1) { // (IsDynamic())
321                 m_pPhysicsController1->RelativeRotate(rotmat,local); 
322         }
323 }
324
325
326
327 /**
328 GetOpenGL Matrix, returns an OpenGL 'compatible' matrix
329 */
330 double* KX_GameObject::GetOpenGLMatrix()
331 {
332         // todo: optimize and only update if necessary
333         double* fl = m_OpenGL_4x4Matrix.getPointer();
334         MT_Transform trans;
335         
336         trans.setOrigin(GetSGNode()->GetWorldPosition());
337         trans.setBasis(GetSGNode()->GetWorldOrientation());
338         
339         MT_Vector3 scaling = GetSGNode()->GetWorldScaling();
340         m_bIsNegativeScaling = ((scaling[0] < 0.0) ^ (scaling[1] < 0.0) ^ (scaling[2] < 0.0)) ? true : false;
341         trans.scale(scaling[0], scaling[1], scaling[2]);
342         trans.getValue(fl);
343
344         return fl;
345 }
346
347
348
349 void KX_GameObject::Bucketize()
350 {
351         double* fl = GetOpenGLMatrix();
352
353         for (size_t i=0;i<m_meshes.size();i++)
354                 m_meshes[i]->Bucketize(fl, this, m_bUseObjectColor, m_objectColor);
355 }
356
357
358
359 void KX_GameObject::RemoveMeshes()
360 {
361         double* fl = GetOpenGLMatrix();
362
363         for (size_t i=0;i<m_meshes.size();i++)
364                 m_meshes[i]->RemoveFromBuckets(fl, this);
365
366         //note: meshes can be shared, and are deleted by KX_BlenderSceneConverter
367
368         m_meshes.clear();
369 }
370
371
372
373 void KX_GameObject::UpdateNonDynas()
374 {
375         if (m_pPhysicsController1)
376         {
377                 m_pPhysicsController1->SetSumoTransform(true);
378         }
379 }
380
381
382
383 void KX_GameObject::UpdateTransform()
384 {
385         if (m_pPhysicsController1)
386                 m_pPhysicsController1->SetSumoTransform(false);
387 }
388
389 void KX_GameObject::UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene)
390 {
391         ((KX_GameObject*)gameobj)->UpdateTransform();
392 }
393
394
395 void KX_GameObject::SetDebugColor(unsigned int bgra)
396 {
397         for (size_t i=0;i<m_meshes.size();i++)
398                 m_meshes[i]->DebugColor(bgra);  
399 }
400
401
402
403 void KX_GameObject::ResetDebugColor()
404 {
405         SetDebugColor(0xff000000);
406 }
407
408
409
410 void KX_GameObject::UpdateIPO(float curframetime,
411                                                           bool recurse,
412                                                           bool ipo_as_force,
413                                                           bool force_local) 
414 {
415
416         // The ipo-actuator needs a sumo reference... this is retrieved (unfortunately)
417         // by the iposgcontr itself...
418 //              ipocontr->SetSumoReference(gameobj->GetSumoScene(), 
419 //                                                                 gameobj->GetSumoObject());
420
421
422         // The ipo has to be treated as a force, and not a displacement!
423         // For this case, we send some settings to the controller. This
424         // may need some caching...
425         if (ipo_as_force) {
426                 SGControllerList::iterator it = GetSGNode()->GetSGControllerList().begin();
427
428                 while (it != GetSGNode()->GetSGControllerList().end()) {
429                         (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, ipo_as_force);
430                         (*it)->SetOption(SG_Controller::SG_CONTR_IPO_FORCES_ACT_LOCAL, force_local);
431                         it++;
432                 }
433         } 
434
435         // The rest is the 'normal' update procedure.
436         GetSGNode()->SetSimulatedTime(curframetime,recurse);
437         GetSGNode()->UpdateWorldData(curframetime);
438         UpdateTransform();
439 }
440
441 // IPO update
442 void 
443 KX_GameObject::UpdateMaterialData(
444                 MT_Vector4 rgba,
445                 MT_Vector3 specrgb,
446                 MT_Scalar hard,
447                 MT_Scalar spec,
448                 MT_Scalar ref,
449                 MT_Scalar emit,
450                 MT_Scalar alpha
451
452         )
453 {
454         int mesh = 0;
455         if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0) {
456                 RAS_MaterialBucket::Set::iterator mit = m_meshes[mesh]->GetFirstMaterial();
457                 for(; mit != m_meshes[mesh]->GetLastMaterial(); ++mit)
458                 {
459                         RAS_IPolyMaterial* poly = (*mit)->GetPolyMaterial();
460                         if(poly->GetFlag() & RAS_BLENDERMAT )
461                         {
462                                 SetObjectColor(rgba);
463                                 KX_BlenderMaterial *m =  static_cast<KX_BlenderMaterial*>(poly);
464                                 m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha);
465                         }
466                 }
467         }
468 }
469 bool
470 KX_GameObject::GetVisible(
471         void
472         )
473 {
474         return m_bVisible;
475 }
476
477 void
478 KX_GameObject::SetVisible(
479         bool v
480         )
481 {
482         m_bVisible = v;
483 }
484
485 void
486 KX_GameObject::SetLayer(
487         int l
488         )
489 {
490         m_layer = l;
491 }
492
493 int
494 KX_GameObject::GetLayer(
495         void
496         )
497 {
498         return m_layer;
499 }
500
501 // used by Python, and the actuatorshould _not_ be misused by the
502 // scene!
503 void 
504 KX_GameObject::MarkVisible(
505         bool visible
506         )
507 {
508         /* If explicit visibility settings are used, this is
509          * determined on this level. Maybe change this to mesh level
510          * later on? */
511         
512         double* fl = GetOpenGLMatrixPtr()->getPointer();
513         for (size_t i=0;i<m_meshes.size();i++)
514         {
515                 m_meshes[i]->MarkVisible(fl,this,visible,m_bUseObjectColor,m_objectColor);
516         }
517 }
518
519
520 // Always use the flag?
521 void 
522 KX_GameObject::MarkVisible(
523         void
524         )
525 {
526         double* fl = GetOpenGLMatrixPtr()->getPointer();
527         for (size_t i=0;i<m_meshes.size();i++)
528         {
529                 m_meshes[i]->MarkVisible(fl,
530                                          this,
531                                          m_bVisible,
532                                          m_bUseObjectColor,
533                                          m_objectColor
534                         );
535         }
536 }
537
538
539 void KX_GameObject::addLinearVelocity(const MT_Vector3& lin_vel,bool local)
540 {
541         if (m_pPhysicsController1)
542                 m_pPhysicsController1->SetLinearVelocity(lin_vel + m_pPhysicsController1->GetLinearVelocity(),local);
543 }
544
545
546
547 void KX_GameObject::setLinearVelocity(const MT_Vector3& lin_vel,bool local)
548 {
549         if (m_pPhysicsController1)
550                 m_pPhysicsController1->SetLinearVelocity(lin_vel,local);
551 }
552
553
554
555 void KX_GameObject::setAngularVelocity(const MT_Vector3& ang_vel,bool local)
556 {
557         if (m_pPhysicsController1)
558                 m_pPhysicsController1->SetAngularVelocity(ang_vel,local);
559 }
560
561 void KX_GameObject::ResolveCombinedVelocities(
562         const MT_Vector3 & lin_vel,
563         const MT_Vector3 & ang_vel,
564         bool lin_vel_local,
565         bool ang_vel_local
566 ){
567         if (m_pPhysicsController1)
568         {
569
570                 MT_Vector3 lv = lin_vel_local ? NodeGetWorldOrientation() * lin_vel : lin_vel;
571                 MT_Vector3 av = ang_vel_local ? NodeGetWorldOrientation() * ang_vel : ang_vel;
572                 m_pPhysicsController1->resolveCombinedVelocities(
573                         lv.x(),lv.y(),lv.z(),av.x(),av.y(),av.z());
574         }
575 }
576
577
578 void KX_GameObject::SetObjectColor(const MT_Vector4& rgbavec)
579 {
580         m_bUseObjectColor = true;
581         m_objectColor = rgbavec;
582 }
583
584 void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis)
585 {
586         MT_Matrix3x3 orimat;
587         MT_Vector3 vect,ori,z,x,y;
588         MT_Scalar len;
589
590         vect = dir;
591         len = vect.length();
592         if (MT_fuzzyZero(len))
593         {
594                 cout << "alignAxisToVect() Error: Null vector!\n";
595                 return;
596         }
597         // normalize
598         vect /= len;
599         orimat = GetSGNode()->GetWorldOrientation();
600         switch (axis)
601         {       
602                 case 0: //x axis
603                         ori = MT_Vector3(orimat[0][2], orimat[1][2], orimat[2][2]); //pivot axis
604                         if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON) //is the vector paralell to the pivot?
605                                 ori = MT_Vector3(orimat[0][1], orimat[1][1], orimat[2][1]); //change the pivot!
606                         x = vect; 
607                         y = ori.cross(x);
608                         z = x.cross(y);
609                         break;
610                 case 1: //y axis
611                         ori = MT_Vector3(orimat[0][0], orimat[1][0], orimat[2][0]);
612                         if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON)
613                                 ori = MT_Vector3(orimat[0][2], orimat[1][2], orimat[2][2]);
614                         y = vect;
615                         z = ori.cross(y);
616                         x = y.cross(z);
617                         break;
618                 case 2: //z axis
619                         ori = MT_Vector3(orimat[0][1], orimat[1][1], orimat[2][1]);
620                         if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON)
621                                 ori = MT_Vector3(orimat[0][0], orimat[1][0], orimat[2][0]);
622                         z = vect;
623                         x = ori.cross(z);
624                         y = z.cross(x);
625                         break;
626                 default: //wrong input?
627                         cout << "alignAxisToVect(): Wrong axis '" << axis <<"'\n";
628                         return;
629         }
630         x.normalize(); //normalize the vectors
631         y.normalize();
632         z.normalize();
633         orimat = MT_Matrix3x3(  x[0],y[0],z[0],
634                                                         x[1],y[1],z[1],
635                                                         x[2],y[2],z[2]);
636         if (GetSGNode()->GetSGParent() != NULL)
637         {
638                 // the object is a child, adapt its local orientation so that 
639                 // the global orientation is aligned as we want.
640                 MT_Matrix3x3 invori = GetSGNode()->GetSGParent()->GetWorldOrientation().inverse();
641                 NodeSetLocalOrientation(invori*orimat);
642         }
643         else
644                 NodeSetLocalOrientation(orimat);
645 }
646
647 MT_Vector3 KX_GameObject::GetLinearVelocity(bool local)
648 {
649         MT_Vector3 velocity(0.0,0.0,0.0), locvel;
650         MT_Matrix3x3 ori;
651         int i, j; 
652         if (m_pPhysicsController1)
653         {
654                 velocity = m_pPhysicsController1->GetLinearVelocity();
655                 
656                 if (local)
657                 {
658                         ori = GetSGNode()->GetWorldOrientation();
659                         
660                         locvel = velocity * ori;
661                         return locvel;
662                 }
663         }
664         return velocity;        
665 }
666
667
668 // scenegraph node stuff
669
670 void KX_GameObject::NodeSetLocalPosition(const MT_Point3& trans)
671 {
672         if (m_pPhysicsController1)
673         {
674                 m_pPhysicsController1->setPosition(trans);
675         }
676
677         if (GetSGNode())
678                 GetSGNode()->SetLocalPosition(trans);
679 }
680
681
682
683 void KX_GameObject::NodeSetLocalOrientation(const MT_Matrix3x3& rot)
684 {
685         if (m_pPhysicsController1)
686         {
687                 m_pPhysicsController1->setOrientation(rot.getRotation());
688         }
689         if (GetSGNode())
690                 GetSGNode()->SetLocalOrientation(rot);
691         else
692         {
693                 int i;
694                 i=0;
695         }
696 }
697
698
699
700 void KX_GameObject::NodeSetLocalScale(const MT_Vector3& scale)
701 {
702         if (m_pPhysicsController1)
703         {
704                 m_pPhysicsController1->setScaling(scale);
705         }
706         
707         if (GetSGNode())
708                 GetSGNode()->SetLocalScale(scale);
709 }
710
711
712
713 void KX_GameObject::NodeSetRelativeScale(const MT_Vector3& scale)
714 {
715         if (GetSGNode())
716                 GetSGNode()->RelativeScale(scale);
717 }
718
719
720
721 void KX_GameObject::NodeUpdateGS(double time,bool bInitiator)
722 {
723         if (GetSGNode())
724                 GetSGNode()->UpdateWorldData(time);
725 }
726
727
728
729 const MT_Matrix3x3& KX_GameObject::NodeGetWorldOrientation() const
730 {
731         return GetSGNode()->GetWorldOrientation();
732 }
733
734
735
736 const MT_Vector3& KX_GameObject::NodeGetWorldScaling() const
737 {
738         return GetSGNode()->GetWorldScaling();
739 }
740
741
742
743 const MT_Point3& KX_GameObject::NodeGetWorldPosition() const
744 {
745         return GetSGNode()->GetWorldPosition();
746 }
747
748 /* Suspend/ resume: for the dynamic behaviour, there is a simple
749  * method. For the residual motion, there is not. I wonder what the
750  * correct solution is for Sumo. Remove from the motion-update tree?
751  *
752  * So far, only switch the physics and logic.
753  * */
754
755 void KX_GameObject::Resume(void)
756 {
757         if (m_suspended) {
758                 SCA_IObject::Resume();
759                 GetPhysicsController()->RestoreDynamics();
760
761                 m_suspended = false;
762         }
763 }
764
765 void KX_GameObject::Suspend(void)
766 {
767         if ((!m_ignore_activity_culling) 
768                 && (!m_suspended))  {
769                 SCA_IObject::Suspend();
770                 GetPhysicsController()->SuspendDynamics();
771                 m_suspended = true;
772         }
773 }
774
775
776
777
778 /* ------- python stuff ---------------------------------------------------*/
779
780
781
782
783 PyMethodDef KX_GameObject::Methods[] = {
784         {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS},  
785         {"alignAxisToVect",(PyCFunction) KX_GameObject::sPyAlignAxisToVect, METH_VARARGS},
786         {"setPosition", (PyCFunction) KX_GameObject::sPySetPosition, METH_VARARGS},
787         {"getPosition", (PyCFunction) KX_GameObject::sPyGetPosition, METH_VARARGS},
788         {"getOrientation", (PyCFunction) KX_GameObject::sPyGetOrientation, METH_VARARGS},
789         {"setOrientation", (PyCFunction) KX_GameObject::sPySetOrientation, METH_VARARGS},
790         {"getLinearVelocity", (PyCFunction) KX_GameObject::sPyGetLinearVelocity, METH_VARARGS},
791         {"getVelocity", (PyCFunction) KX_GameObject::sPyGetVelocity, METH_VARARGS},
792         {"getMass", (PyCFunction) KX_GameObject::sPyGetMass, METH_VARARGS},
793         {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_VARARGS},
794         {"applyImpulse", (PyCFunction) KX_GameObject::sPyApplyImpulse, METH_VARARGS},
795         {"setCollisionMargin", (PyCFunction) KX_GameObject::sPySetCollisionMargin, METH_VARARGS},
796         {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics,METH_VARARGS},
797         {"restoreDynamics", (PyCFunction)KX_GameObject::sPyRestoreDynamics,METH_VARARGS},
798         {"enableRigidBody", (PyCFunction)KX_GameObject::sPyEnableRigidBody,METH_VARARGS},
799         {"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_VARARGS},
800         {"getParent", (PyCFunction)KX_GameObject::sPyGetParent,METH_VARARGS},
801         {"setParent", (PyCFunction)KX_GameObject::sPySetParent,METH_VARARGS},
802         {"removeParent", (PyCFunction)KX_GameObject::sPyRemoveParent,METH_VARARGS},
803         {"getMesh", (PyCFunction)KX_GameObject::sPyGetMesh,METH_VARARGS},
804         {"getPhysicsId", (PyCFunction)KX_GameObject::sPyGetPhysicsId,METH_VARARGS},
805         KX_PYMETHODTABLE(KX_GameObject, getDistanceTo),
806         KX_PYMETHODTABLE(KX_GameObject, rayCastTo),
807         KX_PYMETHODTABLE(KX_GameObject, rayCast),
808         {NULL,NULL} //Sentinel
809 };
810
811
812
813 /*
814 bool KX_GameObject::ConvertPythonVectorArgs(PyObject* args,
815                                                                                         MT_Vector3& pos,
816                                                                                         MT_Vector3& pos2)
817 {
818         PyObject* pylist;
819         PyObject* pylist2;
820         bool error = (PyArg_ParseTuple(args,"OO",&pylist,&pylist2)) != 0;
821
822         pos = ConvertPythonPylist(pylist);
823         pos2 = ConvertPythonPylist(pylist2);
824                 
825         return error;
826 }
827 */
828
829
830 PyObject* KX_GameObject::sPySetPosition(PyObject* self,
831                                                                                 PyObject* args,
832                                                                                 PyObject* kwds)
833 {
834         return ((KX_GameObject*) self)->PySetPosition(self, args, kwds);
835 }
836         
837
838
839 PyObject* KX_GameObject::PyGetPosition(PyObject* self,
840                                                                            PyObject* args, 
841                                                                            PyObject* kwds)
842 {
843         return PyObjectFrom(NodeGetWorldPosition());
844 }
845
846
847
848 PyTypeObject KX_GameObject::Type = {
849         PyObject_HEAD_INIT(&PyType_Type)
850                 0,
851                 "KX_GameObject",
852                 sizeof(KX_GameObject),
853                 0,
854                 PyDestructor,
855                 0,
856                 __getattr,
857                 __setattr,
858                 0, //&MyPyCompare,
859                 __repr,
860                 0, //&cvalue_as_number,
861                 0,
862                 0,
863                 0,
864                 0
865 };
866
867
868
869 PyParentObject KX_GameObject::Parents[] = {
870         &KX_GameObject::Type,
871                 &SCA_IObject::Type,
872                 &CValue::Type,
873                 NULL
874 };
875
876
877
878
879 PyObject* KX_GameObject::_getattr(const STR_String& attr)
880 {
881         if (m_pPhysicsController1)
882         {
883                 if (attr == "mass")
884                         return PyFloat_FromDouble(GetPhysicsController()->GetMass());
885         }
886
887         if (attr == "parent")
888         {       
889                 KX_GameObject* parent = GetParent();
890                 if (parent)
891                 {
892                         parent->AddRef();
893                         return parent;
894                 }
895                 Py_Return;
896         }
897
898         if (attr == "visible")
899                 return PyInt_FromLong(m_bVisible);
900         
901         if (attr == "position")
902                 return PyObjectFrom(NodeGetWorldPosition());
903         
904         if (attr == "orientation")
905                 return PyObjectFrom(NodeGetWorldOrientation());
906         
907         if (attr == "scaling")
908                 return PyObjectFrom(NodeGetWorldScaling());
909                 
910         if (attr == "name")
911                 return PyString_FromString(m_name.ReadPtr());
912         if (attr == "timeOffset") {
913                 if (m_pSGNode->GetSGParent()->IsSlowParent()) {
914                         return PyFloat_FromDouble(static_cast<KX_SlowParentRelation *>(m_pSGNode->GetSGParent()->GetParentRelation())->GetTimeOffset());
915                 } else {
916                         return PyFloat_FromDouble(0.0);
917                 }
918         }
919         
920         
921         _getattr_up(SCA_IObject);
922 }
923
924 int KX_GameObject::_setattr(const STR_String& attr, PyObject *value)    // _setattr method
925 {
926         if (attr == "mass")
927                 return 1;
928         
929         if (attr == "parent")
930                 return 1;
931                 
932         if (PyInt_Check(value))
933         {
934                 int val = PyInt_AsLong(value);
935                 if (attr == "visible")
936                 {
937                         SetVisible(val != 0);
938                         return 0;
939                 }
940         }
941
942         if (PyFloat_Check(value))
943         {
944                 MT_Scalar val = PyFloat_AsDouble(value);
945                 if (attr == "timeOffset") {
946                         if (m_pSGNode->GetSGParent()->IsSlowParent()) {
947                                 static_cast<KX_SlowParentRelation *>(m_pSGNode->GetSGParent()->GetParentRelation())->SetTimeOffset(val);
948                                 return 0;
949                         } else {
950                                 return 0;
951                         }               
952                 }
953         }
954         
955         if (PySequence_Check(value))
956         {
957                 if (attr == "orientation")
958                 {
959                         MT_Matrix3x3 rot;
960                         if (PyObject_IsMT_Matrix(value, 3))
961                         {
962                                 if (PyMatTo(value, rot))
963                                 {
964                                         NodeSetLocalOrientation(rot);
965                                         NodeUpdateGS(0.f,true);
966                                         return 0;
967                                 }
968                                 return 1;
969                         }
970                         
971                         if (PySequence_Size(value) == 4)
972                         {
973                                 MT_Quaternion qrot;
974                                 if (PyVecTo(value, qrot))
975                                 {
976                                         rot.setRotation(qrot);
977                                         NodeSetLocalOrientation(rot);
978                                         NodeUpdateGS(0.f,true);
979                                         return 0;
980                                 }
981                                 return 1;
982                         }
983                         
984                         if (PySequence_Size(value) == 3)
985                         {
986                                 MT_Vector3 erot;
987                                 if (PyVecTo(value, erot))
988                                 {
989                                         rot.setEuler(erot);
990                                         NodeSetLocalOrientation(rot);
991                                         NodeUpdateGS(0.f,true);
992                                         return 0;
993                                 }
994                                 return 1;
995                         }
996                         
997                         return 1;
998                 }
999                 
1000                 if (attr == "position")
1001                 {
1002                         MT_Point3 pos;
1003                         if (PyVecTo(value, pos))
1004                         {
1005                                 NodeSetLocalPosition(pos);
1006                                 NodeUpdateGS(0.f,true);
1007                                 return 0;
1008                         }
1009                         return 1;
1010                 }
1011                 
1012                 if (attr == "scaling")
1013                 {
1014                         MT_Vector3 scale;
1015                         if (PyVecTo(value, scale))
1016                         {
1017                                 NodeSetLocalScale(scale);
1018                                 NodeUpdateGS(0.f,true);
1019                                 return 0;
1020                         }
1021                         return 1;
1022                 }
1023         }
1024         
1025         if (PyString_Check(value))
1026         {
1027                 if (attr == "name")
1028                 {
1029                         m_name = PyString_AsString(value);
1030                         return 0;
1031                 }
1032         }
1033         
1034         /* Need to have parent settable here too */
1035         
1036         return SCA_IObject::_setattr(attr, value);
1037 }
1038
1039
1040 PyObject* KX_GameObject::PyGetLinearVelocity(PyObject* self, 
1041                                                                                          PyObject* args, 
1042                                                                                          PyObject* kwds)
1043 {
1044         // only can get the velocity if we have a physics object connected to us...
1045         int local = 0;
1046         if (PyArg_ParseTuple(args,"|i",&local))
1047         {
1048                 return PyObjectFrom(GetLinearVelocity((local!=0)));
1049         }
1050         else
1051         {
1052                 return NULL;
1053         }
1054 }
1055
1056
1057
1058 PyObject* KX_GameObject::PySetVisible(PyObject* self,
1059                                                                           PyObject* args,
1060                                                                           PyObject* kwds)
1061 {
1062         int visible = 1;
1063         
1064         if (PyArg_ParseTuple(args,"i",&visible))
1065         {
1066                 MarkVisible(visible!=0);
1067                 m_bVisible = (visible!=0);
1068         }
1069         else
1070         {
1071                 return NULL;         
1072         }
1073         Py_Return;
1074         
1075 }
1076
1077
1078
1079 PyObject* KX_GameObject::PyGetVelocity(PyObject* self, 
1080                                                                            PyObject* args, 
1081                                                                            PyObject* kwds)
1082 {
1083         // only can get the velocity if we have a physics object connected to us...
1084         MT_Vector3 velocity(0.0,0.0,0.0);
1085         MT_Point3 point(0.0,0.0,0.0);
1086         
1087         
1088         PyObject* pypos = NULL;
1089         if (PyArg_ParseTuple(args, "|O", &pypos))
1090         {
1091                 if (pypos)
1092                         PyVecTo(pypos, point);
1093         }
1094         
1095         if (m_pPhysicsController1)
1096         {
1097                 velocity = m_pPhysicsController1->GetVelocity(point);
1098         }
1099         
1100         return PyObjectFrom(velocity);
1101 }
1102
1103
1104
1105 PyObject* KX_GameObject::PyGetMass(PyObject* self, 
1106                                                                    PyObject* args, 
1107                                                                    PyObject* kwds)
1108 {
1109         PyObject* pymass = NULL;
1110         
1111         float mass = GetPhysicsController()->GetMass();
1112         pymass = PyFloat_FromDouble(mass);
1113
1114         if (pymass)
1115                 return pymass;
1116         
1117         Py_Return;
1118 }
1119
1120
1121
1122 PyObject* KX_GameObject::PyGetReactionForce(PyObject* self, 
1123                                                                                         PyObject* args, 
1124                                                                                         PyObject* kwds)
1125 {
1126         // only can get the velocity if we have a physics object connected to us...
1127         return PyObjectFrom(GetPhysicsController()->getReactionForce());
1128 }
1129
1130
1131
1132 PyObject* KX_GameObject::PyEnableRigidBody(PyObject* self, 
1133                                                                                    PyObject* args, 
1134                                                                                    PyObject* kwds)
1135 {
1136         
1137         GetPhysicsController()->setRigidBody(true);
1138
1139         Py_Return;
1140 }
1141
1142
1143
1144 PyObject* KX_GameObject::PyDisableRigidBody(PyObject* self, 
1145                                                                                         PyObject* args, 
1146                                                                                         PyObject* kwds)
1147 {
1148         GetPhysicsController()->setRigidBody(false);
1149
1150         Py_Return;
1151 }
1152
1153
1154
1155 PyObject* KX_GameObject::PyGetParent(PyObject* self, 
1156                                                                          PyObject* args, 
1157                                                                          PyObject* kwds)
1158 {
1159         KX_GameObject* parent = this->GetParent();
1160         if (parent)
1161         {
1162                 parent->AddRef();
1163                 return parent;
1164         }
1165         Py_Return;
1166 }
1167
1168 PyObject* KX_GameObject::PySetParent(PyObject* self, 
1169                                                                          PyObject* args, 
1170                                                                          PyObject* kwds)
1171 {
1172         PyObject* gameobj;
1173         if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj))
1174         {
1175                 // The object we want to set as parent
1176                 CValue *m_ob = (CValue*)gameobj;
1177                 KX_GameObject *obj = ((KX_GameObject*)m_ob);
1178                 KX_Scene *scene = PHY_GetActiveScene();
1179                 
1180                 this->SetParent(scene, obj);
1181         }
1182         Py_Return;
1183 }
1184
1185 PyObject* KX_GameObject::PyRemoveParent(PyObject* self, 
1186                                                                          PyObject* args, 
1187                                                                          PyObject* kwds)
1188 {
1189         KX_Scene *scene = PHY_GetActiveScene();
1190         this->RemoveParent(scene);
1191         Py_Return;
1192 }
1193
1194 PyObject* KX_GameObject::PyGetMesh(PyObject* self, 
1195                                                                    PyObject* args, 
1196                                                                    PyObject* kwds)
1197 {
1198         int mesh = 0;
1199
1200         if (PyArg_ParseTuple(args, "|i", &mesh))
1201         {
1202                 if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0)
1203                 {
1204                         KX_MeshProxy* meshproxy = new KX_MeshProxy(m_meshes[mesh]);
1205                         return meshproxy;
1206                 }
1207         }
1208         Py_Return;
1209 }
1210
1211
1212
1213
1214
1215 PyObject* KX_GameObject::PySetCollisionMargin(PyObject* self, 
1216                                                                                 PyObject* args, 
1217                                                                                 PyObject* kwds)
1218 {
1219         float collisionMargin;
1220         if (PyArg_ParseTuple(args, "f", &collisionMargin))
1221         {
1222                 if (m_pPhysicsController1)
1223                 {
1224                         m_pPhysicsController1->setMargin(collisionMargin);
1225                         Py_Return;
1226                 }
1227
1228         }
1229         
1230         return NULL;
1231 }
1232
1233
1234
1235 PyObject* KX_GameObject::PyApplyImpulse(PyObject* self, 
1236                                                                                 PyObject* args, 
1237                                                                                 PyObject* kwds)
1238 {
1239         PyObject* pyattach;
1240         PyObject* pyimpulse;
1241         if (PyArg_ParseTuple(args, "OO", &pyattach, &pyimpulse))
1242         {
1243                 MT_Point3  attach;
1244                 MT_Vector3 impulse;
1245                 if (m_pPhysicsController1)
1246                 {
1247                         if (PyVecTo(pyattach, attach) && PyVecTo(pyimpulse, impulse))
1248                         {
1249                                 m_pPhysicsController1->applyImpulse(attach, impulse);
1250                                 Py_Return;
1251                         }
1252                 }
1253
1254         }
1255         
1256         return NULL;
1257 }
1258
1259
1260
1261 PyObject* KX_GameObject::PySuspendDynamics(PyObject* self, 
1262                                                                                    PyObject* args, 
1263                                                                                    PyObject* kwds)
1264 {
1265         if (m_bSuspendDynamics)
1266         {
1267                 Py_Return;
1268         }
1269         
1270         if (m_pPhysicsController1)
1271         {
1272                 m_pPhysicsController1->SuspendDynamics();
1273         }
1274         m_bSuspendDynamics = true;
1275         
1276         Py_Return;
1277 }
1278
1279
1280
1281 PyObject* KX_GameObject::PyRestoreDynamics(PyObject* self, 
1282                                                                                    PyObject* args, 
1283                                                                                    PyObject* kwds)
1284 {
1285         
1286         if (!m_bSuspendDynamics)
1287         {
1288                 Py_Return;
1289         }
1290         
1291         if (m_pPhysicsController1)
1292         {
1293                 m_pPhysicsController1->RestoreDynamics();
1294         }
1295         m_bSuspendDynamics = false;
1296         
1297         Py_Return;
1298 }
1299
1300
1301
1302 PyObject* KX_GameObject::PyGetOrientation(PyObject* self,
1303                                                                                   PyObject* args,
1304                                                                                   PyObject* kwds) //keywords
1305 {
1306         return PyObjectFrom(NodeGetWorldOrientation());
1307 }
1308
1309
1310
1311 PyObject* KX_GameObject::PySetOrientation(PyObject* self, 
1312                                                                                   PyObject* args, 
1313                                                                                   PyObject* kwds)
1314 {
1315         PyObject* pylist;
1316         
1317         if (PyArg_ParseTuple(args,"O",&pylist))
1318         {
1319                 MT_Matrix3x3 matrix;
1320                 if (PyObject_IsMT_Matrix(pylist, 3) && PyMatTo(pylist, matrix))
1321                 {
1322                         NodeSetLocalOrientation(matrix);
1323                         NodeUpdateGS(0.f,true);
1324                         Py_Return;
1325                 }
1326         
1327                 MT_Quaternion quat;
1328                 if (PyVecTo(pylist, quat))
1329                 {
1330                         matrix.setRotation(quat);
1331                         NodeSetLocalOrientation(matrix);
1332                         NodeUpdateGS(0.f,true);
1333                         Py_Return;
1334                 }
1335         }
1336         return NULL;
1337 }
1338
1339 PyObject* KX_GameObject::PyAlignAxisToVect(PyObject* self, 
1340                                                                                   PyObject* args, 
1341                                                                                   PyObject* kwds)
1342 {
1343         PyObject* pyvect;
1344         int axis = 2; //z axis is the default
1345         
1346         if (PyArg_ParseTuple(args,"O|i",&pyvect,&axis))
1347         {
1348                 MT_Vector3 vect;
1349                 if (PyVecTo(pyvect, vect))
1350                 {
1351                         AlignAxisToVect(vect,axis);                             
1352                         Py_Return;
1353                 }
1354         }
1355         return NULL;
1356 }
1357
1358 PyObject* KX_GameObject::PySetPosition(PyObject* self, 
1359                                                                            PyObject* args, 
1360                                                                            PyObject* kwds)
1361 {
1362         MT_Point3 pos;
1363         if (PyVecArgTo(args, pos))
1364         {
1365                 NodeSetLocalPosition(pos);
1366                 NodeUpdateGS(0.f,true);
1367                 Py_Return;
1368         }
1369         
1370         return NULL;
1371 }
1372
1373 PyObject* KX_GameObject::PyGetPhysicsId(PyObject* self,
1374                                                                                            PyObject* args,
1375                                                                                            PyObject* kwds)
1376 {
1377         KX_IPhysicsController* ctrl = GetPhysicsController();
1378         uint_ptr physid=0;
1379         if (ctrl)
1380         {
1381                 physid= (uint_ptr)ctrl->GetUserData();
1382         }
1383         return PyInt_FromLong((long)physid);
1384 }
1385
1386 KX_PYMETHODDEF_DOC(KX_GameObject, getDistanceTo,
1387 "getDistanceTo(other): get distance to another point/KX_GameObject")
1388 {
1389         MT_Point3 b;
1390         if (PyVecArgTo(args, b))
1391         {
1392                 return PyFloat_FromDouble(NodeGetWorldPosition().distance(b));
1393         }
1394         PyErr_Clear();
1395         
1396         PyObject *pyother;
1397         if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &pyother))
1398         {
1399                 KX_GameObject *other = static_cast<KX_GameObject*>(pyother);
1400                 return PyFloat_FromDouble(NodeGetWorldPosition().distance(other->NodeGetWorldPosition()));
1401         }
1402         
1403         return NULL;
1404 }
1405
1406 bool KX_GameObject::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data)
1407 {
1408
1409         KX_GameObject* hitKXObj = client->m_gameobject;
1410         
1411         if (client->m_type > KX_ClientObjectInfo::ACTOR)
1412         {
1413                 // false hit
1414                 return false;
1415         }
1416
1417         if (m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL)
1418         {
1419                 m_pHitObject = hitKXObj;
1420                 return true;
1421         }
1422
1423         return false;
1424         
1425 }
1426
1427 KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo,
1428 "rayCastTo(other,dist,prop): look towards another point/KX_GameObject and return first object hit within dist that matches prop\n"
1429 " prop = property name that object must have; can be omitted => detect any object\n"
1430 " dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to other\n"
1431 " other = 3-tuple or object reference")
1432 {
1433         MT_Point3 toPoint;
1434         PyObject* pyarg;
1435         float dist = 0.0f;
1436         char *propName = NULL;
1437
1438         if (!PyArg_ParseTuple(args,"O|fs", &pyarg, &dist, &propName))
1439                 return NULL;
1440
1441         if (!PyVecTo(pyarg, toPoint))
1442         {
1443                 KX_GameObject *other;
1444                 PyErr_Clear();
1445                 if (!PyType_IsSubtype(pyarg->ob_type, &KX_GameObject::Type))
1446                         return NULL;
1447                 other = static_cast<KX_GameObject*>(pyarg);
1448                 toPoint = other->NodeGetWorldPosition();
1449         }
1450         MT_Point3 fromPoint = NodeGetWorldPosition();
1451         if (dist != 0.0f)
1452         {
1453                 MT_Vector3 toDir = toPoint-fromPoint;
1454                 toDir.normalize();
1455                 toPoint = fromPoint + (dist) * toDir;
1456         }
1457
1458         MT_Point3 resultPoint;
1459         MT_Vector3 resultNormal;
1460         PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment();
1461         KX_IPhysicsController *spc = GetPhysicsController();
1462         KX_GameObject *parent = GetParent();
1463         if (!spc && parent)
1464                 spc = parent->GetPhysicsController();
1465         if (parent)
1466                 parent->Release();
1467         
1468         m_pHitObject = NULL;
1469         if (propName)
1470                 m_testPropName = propName;
1471         else
1472                 m_testPropName.SetLength(0);
1473         KX_RayCast::RayTest(spc, pe, fromPoint, toPoint, resultPoint, resultNormal, KX_RayCast::Callback<KX_GameObject>(this));
1474
1475     if (m_pHitObject)
1476         {
1477                 m_pHitObject->AddRef();
1478                 return m_pHitObject;
1479         }
1480         Py_Return;
1481 }
1482
1483 KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
1484 "rayCast(to,from,dist,prop): cast a ray and return tuple (object,hit,normal) of contact point with object within dist that matches prop or None if no hit\n"
1485 " prop = property name that object must have; can be omitted => detect any object\n"
1486 " dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to to\n"
1487 " from = 3-tuple or object reference for origin of ray (if object, use center of object)\n"
1488 "        Can None or omitted => start from self object center\n"
1489 " to = 3-tuple or object reference for destination of ray (if object, use center of object)\n"
1490 "Note: the object on which you call this method matters: the ray will ignore it if it goes through it\n")
1491 {
1492         MT_Point3 toPoint;
1493         MT_Point3 fromPoint;
1494         PyObject* pyto;
1495         PyObject* pyfrom = NULL;
1496         float dist = 0.0f;
1497         char *propName = NULL;
1498         KX_GameObject *other;
1499
1500         if (!PyArg_ParseTuple(args,"O|Ofs", &pyto, &pyfrom, &dist, &propName))
1501                 return NULL;
1502
1503         if (!PyVecTo(pyto, toPoint))
1504         {
1505                 PyErr_Clear();
1506                 if (!PyType_IsSubtype(pyto->ob_type, &KX_GameObject::Type))
1507                         return NULL;
1508                 other = static_cast<KX_GameObject*>(pyto);
1509                 toPoint = other->NodeGetWorldPosition();
1510         }
1511         if (!pyfrom || pyfrom == Py_None)
1512         {
1513                 fromPoint = NodeGetWorldPosition();
1514         }
1515         else if (!PyVecTo(pyfrom, fromPoint))
1516         {
1517                 PyErr_Clear();
1518                 if (!PyType_IsSubtype(pyfrom->ob_type, &KX_GameObject::Type))
1519                         return NULL;
1520                 other = static_cast<KX_GameObject*>(pyfrom);
1521                 fromPoint = other->NodeGetWorldPosition();
1522         }
1523
1524         if (dist != 0.0f)
1525         {
1526                 MT_Vector3 toDir = toPoint-fromPoint;
1527                 toDir.normalize();
1528                 toPoint = fromPoint + (dist) * toDir;
1529         }
1530
1531         MT_Point3 resultPoint;
1532         MT_Vector3 resultNormal;
1533         PHY_IPhysicsEnvironment* pe = GetPhysicsEnvironment();
1534         KX_IPhysicsController *spc = GetPhysicsController();
1535         KX_GameObject *parent = GetParent();
1536         if (!spc && parent)
1537                 spc = parent->GetPhysicsController();
1538         if (parent)
1539                 parent->Release();
1540         
1541         m_pHitObject = NULL;
1542         if (propName)
1543                 m_testPropName = propName;
1544         else
1545                 m_testPropName.SetLength(0);
1546         KX_RayCast::RayTest(spc, pe, fromPoint, toPoint, resultPoint, resultNormal, KX_RayCast::Callback<KX_GameObject>(this));
1547
1548     if (m_pHitObject)
1549         {
1550                 PyObject* returnValue = PyTuple_New(3);
1551                 if (!returnValue)
1552                         return NULL;
1553                 PyTuple_SET_ITEM(returnValue, 0, m_pHitObject->AddRef());
1554                 PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(resultPoint));
1555                 PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(resultNormal));
1556                 return returnValue;
1557                 //return Py_BuildValue("(O,(fff),(fff))", 
1558                 //      m_pHitObject->AddRef(),         // trick: KX_GameObject are not true Python object, they use a difference reference count system
1559                 //      resultPoint[0], resultPoint[1], resultPoint[2],
1560                 //      resultNormal[0], resultNormal[1], resultNormal[2]);
1561         }
1562         return Py_BuildValue("OOO", Py_None, Py_None, Py_None);
1563         //Py_Return;
1564 }
1565
1566 /* --------------------------------------------------------------------- 
1567  * Some stuff taken from the header
1568  * --------------------------------------------------------------------- */
1569 void KX_GameObject::Relink(GEN_Map<GEN_HashedPtr, void*> *map_parameter)        
1570 {
1571         /* intentionally empty ? */
1572 }
1573