Fix for bugs: 1788 (forces) and 1799 (python delattr on game objects)
[blender-staging.git] / source / gameengine / Ketsji / KX_ConvertPhysicsObjects.cpp
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32 #ifdef WIN32
33 #pragma warning (disable : 4786)
34 #endif
35
36 // defines USE_ODE to choose physics engine
37 #include "KX_ConvertPhysicsObject.h"
38 #include "KX_GameObject.h"
39 #include "RAS_MeshObject.h"
40 #include "KX_Scene.h"
41 #include "SYS_System.h"
42
43 #include "PHY_Pro.h" //todo cleanup
44 #include "KX_ClientObjectInfo.h"
45
46 #include "GEN_Map.h"
47 #include "GEN_HashedPtr.h"
48
49 #include "KX_PhysicsEngineEnums.h"
50 #include "PHY_Pro.h"
51
52 #include "KX_MotionState.h" // bridge between motionstate and scenegraph node
53
54 #ifdef HAVE_CONFIG_H
55 #include <config.h>
56 #endif
57
58 #ifdef USE_ODE
59
60 #include "KX_OdePhysicsController.h"
61 #include "OdePhysicsEnvironment.h"
62 #endif //USE_ODE
63
64
65 // USE_SUMO_SOLID is defined in headerfile KX_ConvertPhysicsObject.h
66 #ifdef USE_SUMO_SOLID
67
68 #include "SumoPhysicsEnvironment.h"
69 #include "KX_SumoPhysicsController.h"
70
71
72 // sumo physics specific
73 #include "SM_Object.h"
74 #include "SM_FhObject.h"
75 #include "SM_Scene.h"
76 #include "SM_ClientObjectInfo.h"
77
78 #include "KX_SumoPhysicsController.h"
79
80 static GEN_Map<GEN_HashedPtr,DT_ShapeHandle> map_gamemesh_to_sumoshape;
81 static GEN_Map<GEN_HashedPtr, DT_VertexBaseHandle> map_gamemesh_to_vertex_base_handle;
82
83 // forward declarations
84 static void     BL_RegisterSumoObject(KX_GameObject* gameobj,class SM_Scene* sumoScene,class SM_Object* sumoObj,const STR_String& matname,bool isDynamic,bool isActor);
85 static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope);
86
87
88 void    KX_ConvertSumoObject(   KX_GameObject* gameobj,
89                                 RAS_MeshObject* meshobj,
90                                 KX_Scene* kxscene,
91                                 PHY_ShapeProps* kxshapeprops,
92                                 PHY_MaterialProps*      kxmaterial,
93                                 struct  KX_ObjectProperties*    objprop)
94
95
96 {
97         SM_ShapeProps* smprop = new SM_ShapeProps;
98
99         smprop->m_ang_drag = kxshapeprops->m_ang_drag;
100         smprop->m_do_anisotropic = kxshapeprops->m_do_anisotropic;
101         smprop->m_do_fh = kxshapeprops->m_do_fh;
102         smprop->m_do_rot_fh = kxshapeprops->m_do_rot_fh ;
103         smprop->m_friction_scaling[0]  = kxshapeprops->m_friction_scaling[0];
104         smprop->m_friction_scaling[1]  = kxshapeprops->m_friction_scaling[1];
105         smprop->m_friction_scaling[2]  = kxshapeprops->m_friction_scaling[2];
106         smprop->m_inertia = MT_Vector3(1., 1., 1.) * kxshapeprops->m_inertia;
107         smprop->m_lin_drag = kxshapeprops->m_lin_drag;
108         smprop->m_mass = kxshapeprops->m_mass;
109         smprop->m_radius = objprop->m_radius;
110
111
112         SM_MaterialProps* smmaterial = new SM_MaterialProps;
113
114         smmaterial->m_fh_damping = kxmaterial->m_fh_damping;
115         smmaterial->m_fh_distance = kxmaterial->m_fh_distance;
116         smmaterial->m_fh_normal = kxmaterial->m_fh_normal;
117         smmaterial->m_fh_spring = kxmaterial->m_fh_spring;
118         smmaterial->m_friction = kxmaterial->m_friction;
119         smmaterial->m_restitution = kxmaterial->m_restitution;
120
121         SumoPhysicsEnvironment* sumoEnv =
122                 (SumoPhysicsEnvironment*)kxscene->GetPhysicsEnvironment();
123
124         SM_Scene*       sceneptr = sumoEnv->GetSumoScene();
125
126         SM_Object*      sumoObj=NULL;
127
128         if (objprop->m_dyna && objprop->m_isactor)
129         {
130                 DT_ShapeHandle shape = NULL;
131                 bool polytope = false;
132                 switch (objprop->m_boundclass)
133                 {
134                         case KX_BOUNDBOX:
135                                 shape = DT_NewBox(objprop->m_boundobject.box.m_extends[0], 
136                                                 objprop->m_boundobject.box.m_extends[1], 
137                                                 objprop->m_boundobject.box.m_extends[2]);
138                                 smprop->m_inertia.scale(objprop->m_boundobject.box.m_extends[0]*objprop->m_boundobject.box.m_extends[0],
139                                         objprop->m_boundobject.box.m_extends[1]*objprop->m_boundobject.box.m_extends[1],
140                                         objprop->m_boundobject.box.m_extends[2]*objprop->m_boundobject.box.m_extends[2]);
141                                 smprop->m_inertia *= smprop->m_mass/MT_Vector3(objprop->m_boundobject.box.m_extends).length();
142                                 break;
143                         case KX_BOUNDCYLINDER:
144                                 shape = DT_NewCylinder(smprop->m_radius, objprop->m_boundobject.c.m_height);
145                                 smprop->m_inertia.scale(smprop->m_mass*smprop->m_radius*smprop->m_radius,
146                                         smprop->m_mass*smprop->m_radius*smprop->m_radius,
147                                         smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height);
148                                 break;
149                         case KX_BOUNDCONE:
150                                 shape = DT_NewCone(objprop->m_radius, objprop->m_boundobject.c.m_height);
151                                 smprop->m_inertia.scale(smprop->m_mass*smprop->m_radius*smprop->m_radius,
152                                         smprop->m_mass*smprop->m_radius*smprop->m_radius,
153                                         smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height);
154                                 break;
155                         /* Dynamic mesh objects.  WARNING! slow. */
156                         case KX_BOUNDPOLYTOPE:
157                                 polytope = true;
158                                 // fall through
159                         case KX_BOUNDMESH:
160                                 if (meshobj && meshobj->NumPolygons() > 0)
161                                 {
162                                         if ((shape = CreateShapeFromMesh(meshobj, polytope)))
163                                         {
164                                                 // TODO: calculate proper inertia
165                                                 smprop->m_inertia *= smprop->m_mass*smprop->m_radius*smprop->m_radius;
166                                                 break;
167                                         }
168                                 }
169                                 /* If CreateShapeFromMesh fails, fall through and use sphere */
170                         default:
171                         case KX_BOUNDSPHERE:
172                                 shape = DT_NewSphere(objprop->m_radius);
173                                 smprop->m_inertia *= smprop->m_mass*smprop->m_radius*smprop->m_radius;
174                                 break;
175                                 
176                 }
177                 
178                 sumoObj = new SM_Object(shape, !objprop->m_ghost?smmaterial:NULL,smprop,NULL);
179                 
180                 sumoObj->setRigidBody(objprop->m_angular_rigidbody?true:false);
181                 
182                 BL_RegisterSumoObject(gameobj,sceneptr,sumoObj,"",true, true);
183                 
184         } 
185         else {
186                 // non physics object
187                 if (meshobj)
188                 {
189                         int numpolys = meshobj->NumPolygons();
190                         {
191
192                                 DT_ShapeHandle complexshape=0;
193                                 bool polytope = false;
194
195                                 switch (objprop->m_boundclass)
196                                 {
197                                         case KX_BOUNDBOX:
198                                                 complexshape = DT_NewBox(objprop->m_boundobject.box.m_extends[0], objprop->m_boundobject.box.m_extends[1], objprop->m_boundobject.box.m_extends[2]);
199                                                 break;
200                                         case KX_BOUNDSPHERE:
201                                                 complexshape = DT_NewSphere(objprop->m_boundobject.c.m_radius);
202                                                 break;
203                                         case KX_BOUNDCYLINDER:
204                                                 complexshape = DT_NewCylinder(objprop->m_boundobject.c.m_radius, objprop->m_boundobject.c.m_height);
205                                                 break;
206                                         case KX_BOUNDCONE:
207                                                 complexshape = DT_NewCone(objprop->m_boundobject.c.m_radius, objprop->m_boundobject.c.m_height);
208                                                 break;
209                                         case KX_BOUNDPOLYTOPE:
210                                                 polytope = true;
211                                                 // fall through
212                                         default:
213                                         case KX_BOUNDMESH:
214                                                 if (numpolys>0)
215                                                 {
216                                                         complexshape = CreateShapeFromMesh(meshobj, polytope);
217                                                         //std::cout << "Convert Physics Mesh: " << meshobj->GetName() << std::endl;
218 /*                                                      if (!complexshape) 
219                                                         {
220                                                                 // Something has to be done here - if the object has no polygons, it will not be able to have
221                                                                 //   sensors attached to it. 
222                                                                 DT_Vector3 pt = {0., 0., 0.};
223                                                                 complexshape = DT_NewSphere(1.0);
224                                                                 objprop->m_ghost = evilObject = true;
225                                                         } */
226                                                 }
227                                                 break;
228                                 }
229                                 
230                                 if (complexshape)
231                                 {
232                                         SM_Object *dynamicParent = NULL;
233
234                                         if (objprop->m_dynamic_parent)
235                                         {
236                                                 // problem is how to find the dynamic parent
237                                                 // in the scenegraph
238                                                 KX_SumoPhysicsController* sumoctrl = 
239                                                 (KX_SumoPhysicsController*)
240                                                         objprop->m_dynamic_parent->GetPhysicsController();
241
242                                                 if (sumoctrl)
243                                                 {
244                                                         dynamicParent = sumoctrl->GetSumoObject();
245                                                 }
246
247                                                 assert(dynamicParent);
248                                         }
249                                 
250                                         
251                                         sumoObj = new SM_Object(complexshape,!objprop->m_ghost?smmaterial:NULL,NULL, dynamicParent);    
252                                         const STR_String& matname=meshobj->GetMaterialName(0);
253
254                                         
255                                         BL_RegisterSumoObject(gameobj,sceneptr,
256                                                 sumoObj,
257                                                 matname,
258                                                 objprop->m_dyna,
259                                                 objprop->m_isactor);
260                                 }
261                         }
262                 }
263         }
264
265         // physics object get updated here !
266
267         
268         // lazy evaluation because we might not support scaling !gameobj->UpdateTransform();
269
270         if (objprop->m_in_active_layer && sumoObj)
271         {
272                 sceneptr->add(*sumoObj);
273         }
274
275 }
276
277
278
279 static void     BL_RegisterSumoObject(
280         KX_GameObject* gameobj,
281         class SM_Scene* sumoScene,
282         class SM_Object* sumoObj,
283         const STR_String& matname,
284         bool isDynamic,
285         bool isActor) 
286 {
287                 PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
288
289                 // need easy access, not via 'node' etc.
290                 KX_SumoPhysicsController* physicscontroller = new KX_SumoPhysicsController(sumoScene,sumoObj,motionstate,isDynamic);
291                 gameobj->SetPhysicsController(physicscontroller);
292                 physicscontroller->setClientInfo(gameobj);
293                 
294                 if (!gameobj->getClientInfo())
295                         std::cout << "BL_RegisterSumoObject: WARNING: Object " << gameobj->GetName() << " has no client info" << std::endl;
296                 sumoObj->setClientObject(gameobj->getClientInfo());
297
298                 gameobj->GetSGNode()->AddSGController(physicscontroller);
299
300                 gameobj->getClientInfo()->m_type = (isActor ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC);
301
302                 // store materialname in auxinfo, needed for touchsensors
303                 gameobj->getClientInfo()->m_auxilary_info = (matname.Length() ? (void*)(matname.ReadPtr()+2) : NULL);
304
305                 physicscontroller->SetObject(gameobj->GetSGNode());
306 }
307
308 static DT_ShapeHandle InstancePhysicsComplex(RAS_MeshObject* meshobj, int vtxarray, RAS_IPolyMaterial *mat)
309 {
310         // instance a mesh from a single vertex array & material
311         const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(mat)[vtxarray])[0]);
312         //const KX_IndexArray &index_array = *meshobj->GetIndexCache(mat)[vtxarray];
313         DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getLocalXYZ(), sizeof(RAS_TexVert));
314         
315         DT_ShapeHandle shape = DT_NewComplexShape(vertex_base);
316         
317         std::vector<DT_Index> indices;
318         for (int p = 0; p < meshobj->NumPolygons(); p++)
319         {
320                 RAS_Polygon* poly = meshobj->GetPolygon(p);
321         
322                 // only add polygons that have the collisionflag set
323                 if (poly->IsCollider())
324                 {
325                         DT_VertexIndices(3, poly->GetVertexIndexBase().m_indexarray);
326                         
327                         // tesselate
328                         if (poly->VertexCount() == 4)
329                         {
330                                 DT_Begin();
331                                   DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[0]);
332                                   DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[2]);
333                                   DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[3]);
334                                 DT_End();
335                         }
336                 }
337         }
338
339         //DT_VertexIndices(indices.size(), &indices[0]);
340         DT_EndComplexShape();
341         
342         map_gamemesh_to_vertex_base_handle.insert(GEN_HashedPtr(meshobj), vertex_base);
343         return shape;
344 }
345
346 static DT_ShapeHandle InstancePhysicsPolytope(RAS_MeshObject* meshobj, int vtxarray, RAS_IPolyMaterial *mat)
347 {
348         // instance a mesh from a single vertex array & material
349         const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(mat)[vtxarray])[0]);
350         //const KX_IndexArray &index_array = *meshobj->GetIndexCache(mat)[vtxarray];
351         DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getLocalXYZ(), sizeof(RAS_TexVert));
352         
353         std::vector<DT_Index> indices;
354         for (int p = 0; p < meshobj->NumPolygons(); p++)
355         {
356                 RAS_Polygon* poly = meshobj->GetPolygon(p);
357         
358                 // only add polygons that have the collisionflag set
359                 if (poly->IsCollider())
360                 {
361                         indices.push_back(poly->GetVertexIndexBase().m_indexarray[0]);
362                         indices.push_back(poly->GetVertexIndexBase().m_indexarray[1]);
363                         indices.push_back(poly->GetVertexIndexBase().m_indexarray[2]);
364                         
365                         if (poly->VertexCount() == 4)
366                                 indices.push_back(poly->GetVertexIndexBase().m_indexarray[3]);
367                 }
368         }
369
370         DT_ShapeHandle shape = DT_NewPolytope(vertex_base);
371         DT_VertexIndices(indices.size(), &indices[0]);
372         DT_EndPolytope();
373         
374         map_gamemesh_to_vertex_base_handle.insert(GEN_HashedPtr(meshobj), vertex_base);
375         return shape;
376 }
377
378 // This will have to be a method in a class somewhere...
379 // Update SOLID with a changed physics mesh.
380 // not used... yet.
381 bool ReInstanceShapeFromMesh(RAS_MeshObject* meshobj, int vtxarray, RAS_IPolyMaterial *mat)
382 {
383         DT_VertexBaseHandle *vertex_base = map_gamemesh_to_vertex_base_handle[GEN_HashedPtr(meshobj)];
384         if (vertex_base)
385         {
386                 const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(mat)[vtxarray])[0]);
387                 DT_ChangeVertexBase(*vertex_base, vertex_array[0].getLocalXYZ());
388                 return true;
389         }
390         return false;
391 }
392
393 static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope)
394 {
395
396         DT_ShapeHandle *shapeptr = map_gamemesh_to_sumoshape[GEN_HashedPtr(meshobj)];
397         // Mesh has already been converted: reuse
398         if (shapeptr)
399         {
400                 return *shapeptr;
401         }
402         
403         // Mesh has no polygons!
404         int numpolys = meshobj->NumPolygons();
405         if (!numpolys)
406         {
407                 return NULL;
408         }
409         
410         // Count the number of collision polygons and check they all come from the same 
411         // vertex array
412         int numvalidpolys = 0;
413         int vtxarray = -1;
414         RAS_IPolyMaterial *poly_material = NULL;
415         bool reinstance = true;
416
417         for (int p=0; p<numpolys; p++)
418         {
419                 RAS_Polygon* poly = meshobj->GetPolygon(p);
420         
421                 // only add polygons that have the collisionflag set
422                 if (poly->IsCollider())
423                 {
424                         // check polygon is from the same vertex array
425                         if (poly->GetVertexIndexBase().m_vtxarray != vtxarray)
426                         {
427                                 if (vtxarray < 0)
428                                         vtxarray = poly->GetVertexIndexBase().m_vtxarray;
429                                 else
430                                 {
431                                         reinstance = false;
432                                         vtxarray = -1;
433                                 }
434                         }
435                         
436                         // check poly is from the same material
437                         if (poly->GetMaterial()->GetPolyMaterial() != poly_material)
438                         {
439                                 if (poly_material)
440                                 {
441                                         reinstance = false;
442                                         poly_material = NULL;
443                                 }
444                                 else
445                                         poly_material = poly->GetMaterial()->GetPolyMaterial();
446                         }
447                         
448                         // count the number of collision polys
449                         numvalidpolys++;
450                         
451                         // We have one collision poly, and we can't reinstance, so we
452                         // might as well break here.
453                         if (!reinstance)
454                                 break;
455                 }
456         }
457         
458         // No collision polygons
459         if (numvalidpolys < 1)
460                 return NULL;
461         
462         DT_ShapeHandle shape;
463         if (reinstance)
464         {
465                 if (polytope)
466                         shape = InstancePhysicsPolytope(meshobj, vtxarray, poly_material);
467                 else
468                         shape = InstancePhysicsComplex(meshobj, vtxarray, poly_material);
469         }
470         else
471         {
472                 if (polytope)
473                 {
474                         std::cout << "CreateShapeFromMesh: " << meshobj->GetName() << " is not suitable for polytope." << std::endl;
475                         if (!poly_material)
476                                 std::cout << "                     Check mesh materials." << std::endl;
477                         if (vtxarray < 0)
478                                 std::cout << "                     Check number of vertices." << std::endl;
479                 }
480                 
481                 shape = DT_NewComplexShape(NULL);
482                         
483                 numvalidpolys = 0;
484         
485                 for (int p2=0; p2<numpolys; p2++)
486                 {
487                         RAS_Polygon* poly = meshobj->GetPolygon(p2);
488                 
489                         // only add polygons that have the collisionflag set
490                         if (poly->IsCollider())
491                         {   /* We have to tesselate here because SOLID can only raycast triangles */
492                            DT_Begin();
493                                 /* V1 */
494                                 DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
495                                         poly->GetVertexIndexBase().m_indexarray[2],
496                                         poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
497                                 /* V2 */
498                                 DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
499                                         poly->GetVertexIndexBase().m_indexarray[1],
500                                         poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
501                                 /* V3 */
502                                 DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
503                                         poly->GetVertexIndexBase().m_indexarray[0],
504                                         poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
505                                 
506                                 numvalidpolys++;
507                            DT_End();
508                                 
509                                 if (poly->VertexCount() == 4)
510                                 {
511                                    DT_Begin();
512                                         /* V1 */
513                                         DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
514                                                 poly->GetVertexIndexBase().m_indexarray[3],
515                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
516                                         /* V3 */
517                                         DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
518                                                 poly->GetVertexIndexBase().m_indexarray[2],
519                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
520                                         /* V4 */
521                                         DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
522                                                 poly->GetVertexIndexBase().m_indexarray[0],
523                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
524                                 
525                                         numvalidpolys++;
526                                    DT_End();
527                                 }
528                 
529                         }
530                 }
531                 
532                 DT_EndComplexShape();
533         }
534
535         if (numvalidpolys > 0)
536         {
537                 map_gamemesh_to_sumoshape.insert(GEN_HashedPtr(meshobj),shape);
538                 return shape;
539         }
540
541         delete shape;
542         return NULL;
543 }
544
545 void    KX_ClearSumoSharedShapes()
546 {
547         int numshapes = map_gamemesh_to_sumoshape.size();
548         int i;
549         for (i=0;i<numshapes ;i++)
550         {
551                 DT_ShapeHandle shape = *map_gamemesh_to_sumoshape.at(i);
552                 DT_DeleteShape(shape);
553         }
554         
555         map_gamemesh_to_sumoshape.clear();
556         
557         for (i=0; i < map_gamemesh_to_vertex_base_handle.size(); i++)
558                 DT_DeleteVertexBase(*map_gamemesh_to_vertex_base_handle.at(i));
559         
560         map_gamemesh_to_vertex_base_handle.clear();
561 }
562
563
564
565
566
567 #endif //USE_SUMO_SOLID
568
569
570 #ifdef USE_ODE
571
572 void    KX_ConvertODEEngineObject(KX_GameObject* gameobj,
573                                                          RAS_MeshObject* meshobj,
574                                                          KX_Scene* kxscene,
575                                                         struct  PHY_ShapeProps* shapeprops,
576                                                         struct  PHY_MaterialProps*      smmaterial,
577                                                         struct  KX_ObjectProperties*    objprop)
578 {
579         // not yet, future extension :)
580         bool dyna=objprop->m_dyna;
581         bool fullRigidBody= ( objprop->m_dyna && objprop->m_angular_rigidbody) != 0;
582         bool phantom = objprop->m_ghost;
583         class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
584
585         class ODEPhysicsEnvironment* odeEnv =
586                 (ODEPhysicsEnvironment*)kxscene->GetPhysicsEnvironment();
587
588         dxSpace* space = odeEnv->GetOdeSpace();
589         dxWorld* world = odeEnv->GetOdeWorld();
590
591         if (!objprop->m_implicitsphere &&
592                 MT_fuzzyZero(objprop->m_boundingbox.m_extends[0]) ||
593                 MT_fuzzyZero(objprop->m_boundingbox.m_extends[1]) ||
594                 MT_fuzzyZero(objprop->m_boundingbox.m_extends[2])
595                 )
596         {
597
598         } else
599         {
600
601                 KX_OdePhysicsController* physicscontroller = 
602                         new KX_OdePhysicsController(
603                         dyna,
604                         fullRigidBody,
605                         phantom,
606                         motionstate,
607                         space,
608                         world,
609                         shapeprops->m_mass,
610                         smmaterial->m_friction,
611                         smmaterial->m_restitution,
612                         objprop->m_implicitsphere,
613                         objprop->m_boundingbox.m_center,
614                         objprop->m_boundingbox.m_extends,
615                         objprop->m_radius
616                         );
617
618                 gameobj->SetPhysicsController(physicscontroller);
619                 physicscontroller->setClientInfo(gameobj);                                              
620                 gameobj->GetSGNode()->AddSGController(physicscontroller);
621
622                 bool isActor = objprop->m_isactor;
623                 STR_String materialname;
624                 if (meshobj)
625                         materialname = meshobj->GetMaterialName(0);
626
627                 const char* matname = materialname.ReadPtr();
628
629
630                 physicscontroller->SetObject(gameobj->GetSGNode());
631                                 
632         }
633 }
634
635
636 #endif // USE_ODE