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