Fixed several bugs: python refcounting related and Bullet related (basic add/remove...
[blender.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 #include "MT_assert.h"
37
38 // defines USE_ODE to choose physics engine
39 #include "KX_ConvertPhysicsObject.h"
40 #include "KX_GameObject.h"
41 #include "RAS_MeshObject.h"
42 #include "KX_Scene.h"
43 #include "SYS_System.h"
44
45 #include "PHY_Pro.h" //todo cleanup
46 #include "KX_ClientObjectInfo.h"
47
48 #include "GEN_Map.h"
49 #include "GEN_HashedPtr.h"
50
51 #include "KX_PhysicsEngineEnums.h"
52 #include "PHY_Pro.h"
53
54 #include "KX_MotionState.h" // bridge between motionstate and scenegraph node
55
56 #ifdef USE_ODE
57
58 #include "KX_OdePhysicsController.h"
59 #include "OdePhysicsEnvironment.h"
60 #endif //USE_ODE
61
62
63 // USE_SUMO_SOLID is defined in headerfile KX_ConvertPhysicsObject.h
64 #ifdef USE_SUMO_SOLID
65
66
67 #include "SumoPhysicsEnvironment.h"
68 #include "KX_SumoPhysicsController.h"
69
70
71 // sumo physics specific
72 #include "SM_Object.h"
73 #include "SM_FhObject.h"
74 #include "SM_Scene.h"
75 #include "SM_ClientObjectInfo.h"
76
77 #include "KX_SumoPhysicsController.h"
78
79 struct KX_PhysicsInstance
80 {
81         DT_VertexBaseHandle     m_vertexbase;
82         int                     m_vtxarray;
83         RAS_IPolyMaterial*      m_material;
84         
85         KX_PhysicsInstance(DT_VertexBaseHandle vertex_base, int vtxarray, RAS_IPolyMaterial* mat)
86                 : m_vertexbase(vertex_base),
87                   m_vtxarray(vtxarray),
88                   m_material(mat)
89         {
90         }
91         
92         ~KX_PhysicsInstance()
93         {
94                 DT_DeleteVertexBase(m_vertexbase);
95         }
96 };
97
98 static GEN_Map<GEN_HashedPtr,DT_ShapeHandle> map_gamemesh_to_sumoshape;
99 static GEN_Map<GEN_HashedPtr, KX_PhysicsInstance*> map_gamemesh_to_instance;
100
101 // forward declarations
102 static void     BL_RegisterSumoObject(KX_GameObject* gameobj,class SM_Scene* sumoScene,class SM_Object* sumoObj,const STR_String& matname,bool isDynamic,bool isActor);
103 static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope);
104
105 void    KX_ConvertSumoObject(   KX_GameObject* gameobj,
106                                 RAS_MeshObject* meshobj,
107                                 KX_Scene* kxscene,
108                                 PHY_ShapeProps* kxshapeprops,
109                                 PHY_MaterialProps*      kxmaterial,
110                                 struct  KX_ObjectProperties*    objprop)
111
112
113 {
114         SM_ShapeProps* smprop = new SM_ShapeProps;
115
116         smprop->m_ang_drag = kxshapeprops->m_ang_drag;
117         smprop->m_do_anisotropic = kxshapeprops->m_do_anisotropic;
118         smprop->m_do_fh = kxshapeprops->m_do_fh;
119         smprop->m_do_rot_fh = kxshapeprops->m_do_rot_fh ;
120         smprop->m_friction_scaling[0]  = kxshapeprops->m_friction_scaling[0];
121         smprop->m_friction_scaling[1]  = kxshapeprops->m_friction_scaling[1];
122         smprop->m_friction_scaling[2]  = kxshapeprops->m_friction_scaling[2];
123         smprop->m_inertia = MT_Vector3(1., 1., 1.) * kxshapeprops->m_inertia;
124         smprop->m_lin_drag = kxshapeprops->m_lin_drag;
125         smprop->m_mass = kxshapeprops->m_mass;
126         smprop->m_radius = objprop->m_radius;
127
128
129         SM_MaterialProps* smmaterial = new SM_MaterialProps;
130
131         smmaterial->m_fh_damping = kxmaterial->m_fh_damping;
132         smmaterial->m_fh_distance = kxmaterial->m_fh_distance;
133         smmaterial->m_fh_normal = kxmaterial->m_fh_normal;
134         smmaterial->m_fh_spring = kxmaterial->m_fh_spring;
135         smmaterial->m_friction = kxmaterial->m_friction;
136         smmaterial->m_restitution = kxmaterial->m_restitution;
137
138         SumoPhysicsEnvironment* sumoEnv =
139                 (SumoPhysicsEnvironment*)kxscene->GetPhysicsEnvironment();
140
141         SM_Scene*       sceneptr = sumoEnv->GetSumoScene();
142
143         SM_Object*      sumoObj=NULL;
144
145         if (objprop->m_dyna && objprop->m_isactor)
146         {
147                 DT_ShapeHandle shape = NULL;
148                 bool polytope = false;
149                 switch (objprop->m_boundclass)
150                 {
151                         case KX_BOUNDBOX:
152                                 shape = DT_NewBox(objprop->m_boundobject.box.m_extends[0], 
153                                                 objprop->m_boundobject.box.m_extends[1], 
154                                                 objprop->m_boundobject.box.m_extends[2]);
155                                 smprop->m_inertia.scale(objprop->m_boundobject.box.m_extends[0]*objprop->m_boundobject.box.m_extends[0],
156                                         objprop->m_boundobject.box.m_extends[1]*objprop->m_boundobject.box.m_extends[1],
157                                         objprop->m_boundobject.box.m_extends[2]*objprop->m_boundobject.box.m_extends[2]);
158                                 smprop->m_inertia *= smprop->m_mass/MT_Vector3(objprop->m_boundobject.box.m_extends).length();
159                                 break;
160                         case KX_BOUNDCYLINDER:
161                                 shape = DT_NewCylinder(smprop->m_radius, objprop->m_boundobject.c.m_height);
162                                 smprop->m_inertia.scale(smprop->m_mass*smprop->m_radius*smprop->m_radius,
163                                         smprop->m_mass*smprop->m_radius*smprop->m_radius,
164                                         smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height);
165                                 break;
166                         case KX_BOUNDCONE:
167                                 shape = DT_NewCone(objprop->m_radius, objprop->m_boundobject.c.m_height);
168                                 smprop->m_inertia.scale(smprop->m_mass*smprop->m_radius*smprop->m_radius,
169                                         smprop->m_mass*smprop->m_radius*smprop->m_radius,
170                                         smprop->m_mass*objprop->m_boundobject.c.m_height*objprop->m_boundobject.c.m_height);
171                                 break;
172                         /* Dynamic mesh objects.  WARNING! slow. */
173                         case KX_BOUNDPOLYTOPE:
174                                 polytope = true;
175                                 // fall through
176                         case KX_BOUNDMESH:
177                                 if (meshobj && meshobj->NumPolygons() > 0)
178                                 {
179                                         if ((shape = CreateShapeFromMesh(meshobj, polytope)))
180                                         {
181                                                 // TODO: calculate proper inertia
182                                                 smprop->m_inertia *= smprop->m_mass*smprop->m_radius*smprop->m_radius;
183                                                 break;
184                                         }
185                                 }
186                                 /* If CreateShapeFromMesh fails, fall through and use sphere */
187                         default:
188                         case KX_BOUNDSPHERE:
189                                 shape = DT_NewSphere(objprop->m_radius);
190                                 smprop->m_inertia *= smprop->m_mass*smprop->m_radius*smprop->m_radius;
191                                 break;
192                                 
193                 }
194                 
195                 sumoObj = new SM_Object(shape, !objprop->m_ghost?smmaterial:NULL,smprop,NULL);
196                 
197                 sumoObj->setRigidBody(objprop->m_angular_rigidbody?true:false);
198                 
199                 BL_RegisterSumoObject(gameobj,sceneptr,sumoObj,"",true, true);
200                 
201         } 
202         else {
203                 // non physics object
204                 if (meshobj)
205                 {
206                         int numpolys = meshobj->NumPolygons();
207                         {
208
209                                 DT_ShapeHandle complexshape=0;
210                                 bool polytope = false;
211
212                                 switch (objprop->m_boundclass)
213                                 {
214                                         case KX_BOUNDBOX:
215                                                 complexshape = DT_NewBox(objprop->m_boundobject.box.m_extends[0], objprop->m_boundobject.box.m_extends[1], objprop->m_boundobject.box.m_extends[2]);
216                                                 break;
217                                         case KX_BOUNDSPHERE:
218                                                 complexshape = DT_NewSphere(objprop->m_boundobject.c.m_radius);
219                                                 break;
220                                         case KX_BOUNDCYLINDER:
221                                                 complexshape = DT_NewCylinder(objprop->m_boundobject.c.m_radius, objprop->m_boundobject.c.m_height);
222                                                 break;
223                                         case KX_BOUNDCONE:
224                                                 complexshape = DT_NewCone(objprop->m_boundobject.c.m_radius, objprop->m_boundobject.c.m_height);
225                                                 break;
226                                         case KX_BOUNDPOLYTOPE:
227                                                 polytope = true;
228                                                 // fall through
229                                         default:
230                                         case KX_BOUNDMESH:
231                                                 if (numpolys>0)
232                                                 {
233                                                         complexshape = CreateShapeFromMesh(meshobj, polytope);
234                                                         //std::cout << "Convert Physics Mesh: " << meshobj->GetName() << std::endl;
235 /*                                                      if (!complexshape) 
236                                                         {
237                                                                 // Something has to be done here - if the object has no polygons, it will not be able to have
238                                                                 //   sensors attached to it. 
239                                                                 DT_Vector3 pt = {0., 0., 0.};
240                                                                 complexshape = DT_NewSphere(1.0);
241                                                                 objprop->m_ghost = evilObject = true;
242                                                         } */
243                                                 }
244                                                 break;
245                                 }
246                                 
247                                 if (complexshape)
248                                 {
249                                         SM_Object *dynamicParent = NULL;
250
251                                         if (objprop->m_dynamic_parent)
252                                         {
253                                                 // problem is how to find the dynamic parent
254                                                 // in the scenegraph
255                                                 KX_SumoPhysicsController* sumoctrl = 
256                                                 (KX_SumoPhysicsController*)
257                                                         objprop->m_dynamic_parent->GetPhysicsController();
258
259                                                 if (sumoctrl)
260                                                 {
261                                                         dynamicParent = sumoctrl->GetSumoObject();
262                                                 }
263
264                                                 MT_assert(dynamicParent);
265                                         }
266                                 
267                                         
268                                         sumoObj = new SM_Object(complexshape,!objprop->m_ghost?smmaterial:NULL,NULL, dynamicParent);    
269                                         const STR_String& matname=meshobj->GetMaterialName(0);
270
271                                         
272                                         BL_RegisterSumoObject(gameobj,sceneptr,
273                                                 sumoObj,
274                                                 matname,
275                                                 objprop->m_dyna,
276                                                 objprop->m_isactor);
277                                 }
278                         }
279                 }
280         }
281
282         // physics object get updated here !
283
284         
285         // lazy evaluation because we might not support scaling !gameobj->UpdateTransform();
286
287         if (objprop->m_in_active_layer && sumoObj)
288         {
289                 sceneptr->add(*sumoObj);
290         }
291
292 }
293
294
295
296 static void     BL_RegisterSumoObject(
297         KX_GameObject* gameobj,
298         class SM_Scene* sumoScene,
299         class SM_Object* sumoObj,
300         const STR_String& matname,
301         bool isDynamic,
302         bool isActor) 
303 {
304                 PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
305
306                 // need easy access, not via 'node' etc.
307                 KX_SumoPhysicsController* physicscontroller = new KX_SumoPhysicsController(sumoScene,sumoObj,motionstate,isDynamic);
308                 gameobj->SetPhysicsController(physicscontroller,isDynamic);
309
310                 
311                 if (!gameobj->getClientInfo())
312                         std::cout << "BL_RegisterSumoObject: WARNING: Object " << gameobj->GetName() << " has no client info" << std::endl;
313                 physicscontroller->setNewClientInfo(gameobj->getClientInfo());
314                 
315
316                 gameobj->GetSGNode()->AddSGController(physicscontroller);
317
318                 gameobj->getClientInfo()->m_type = (isActor ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC);
319
320                 // store materialname in auxinfo, needed for touchsensors
321                 gameobj->getClientInfo()->m_auxilary_info = (matname.Length() ? (void*)(matname.ReadPtr()+2) : NULL);
322
323                 physicscontroller->SetObject(gameobj->GetSGNode());
324 }
325
326 static DT_ShapeHandle InstancePhysicsComplex(RAS_MeshObject* meshobj, int vtxarray, RAS_IPolyMaterial *mat)
327 {
328         // instance a mesh from a single vertex array & material
329         const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(mat)[vtxarray])[0]);
330         //const KX_IndexArray &index_array = *meshobj->GetIndexCache(mat)[vtxarray];
331         DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getLocalXYZ(), sizeof(RAS_TexVert));
332         
333         DT_ShapeHandle shape = DT_NewComplexShape(vertex_base);
334         
335         std::vector<DT_Index> indices;
336         for (int p = 0; p < meshobj->NumPolygons(); p++)
337         {
338                 RAS_Polygon* poly = meshobj->GetPolygon(p);
339         
340                 // only add polygons that have the collisionflag set
341                 if (poly->IsCollider())
342                 {
343                         DT_VertexIndices(3, poly->GetVertexIndexBase().m_indexarray);
344                         
345                         // tesselate
346                         if (poly->VertexCount() == 4)
347                         {
348                                 DT_Begin();
349                                   DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[0]);
350                                   DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[2]);
351                                   DT_VertexIndex(poly->GetVertexIndexBase().m_indexarray[3]);
352                                 DT_End();
353                         }
354                 }
355         }
356
357         //DT_VertexIndices(indices.size(), &indices[0]);
358         DT_EndComplexShape();
359         
360         map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, vtxarray, mat));
361         return shape;
362 }
363
364 static DT_ShapeHandle InstancePhysicsPolytope(RAS_MeshObject* meshobj, int vtxarray, RAS_IPolyMaterial *mat)
365 {
366         // instance a mesh from a single vertex array & material
367         const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(mat)[vtxarray])[0]);
368         //const KX_IndexArray &index_array = *meshobj->GetIndexCache(mat)[vtxarray];
369         DT_VertexBaseHandle vertex_base = DT_NewVertexBase(vertex_array[0].getLocalXYZ(), sizeof(RAS_TexVert));
370         
371         std::vector<DT_Index> indices;
372         for (int p = 0; p < meshobj->NumPolygons(); p++)
373         {
374                 RAS_Polygon* poly = meshobj->GetPolygon(p);
375         
376                 // only add polygons that have the collisionflag set
377                 if (poly->IsCollider())
378                 {
379                         indices.push_back(poly->GetVertexIndexBase().m_indexarray[0]);
380                         indices.push_back(poly->GetVertexIndexBase().m_indexarray[1]);
381                         indices.push_back(poly->GetVertexIndexBase().m_indexarray[2]);
382                         
383                         if (poly->VertexCount() == 4)
384                                 indices.push_back(poly->GetVertexIndexBase().m_indexarray[3]);
385                 }
386         }
387
388         DT_ShapeHandle shape = DT_NewPolytope(vertex_base);
389         DT_VertexIndices(indices.size(), &indices[0]);
390         DT_EndPolytope();
391         
392         map_gamemesh_to_instance.insert(GEN_HashedPtr(meshobj), new KX_PhysicsInstance(vertex_base, vtxarray, mat));
393         return shape;
394 }
395
396 // This will have to be a method in a class somewhere...
397 // Update SOLID with a changed physics mesh.
398 // not used... yet.
399 bool KX_ReInstanceShapeFromMesh(RAS_MeshObject* meshobj)
400 {
401         KX_PhysicsInstance *instance = *map_gamemesh_to_instance[GEN_HashedPtr(meshobj)];
402         if (instance)
403         {
404                 const RAS_TexVert *vertex_array = &((*meshobj->GetVertexCache(instance->m_material)[instance->m_vtxarray])[0]);
405                 DT_ChangeVertexBase(instance->m_vertexbase, vertex_array[0].getLocalXYZ());
406                 return true;
407         }
408         return false;
409 }
410
411 static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj, bool polytope)
412 {
413
414         DT_ShapeHandle *shapeptr = map_gamemesh_to_sumoshape[GEN_HashedPtr(meshobj)];
415         // Mesh has already been converted: reuse
416         if (shapeptr)
417         {
418                 return *shapeptr;
419         }
420         
421         // Mesh has no polygons!
422         int numpolys = meshobj->NumPolygons();
423         if (!numpolys)
424         {
425                 return NULL;
426         }
427         
428         // Count the number of collision polygons and check they all come from the same 
429         // vertex array
430         int numvalidpolys = 0;
431         int vtxarray = -1;
432         RAS_IPolyMaterial *poly_material = NULL;
433         bool reinstance = true;
434
435         for (int p=0; p<numpolys; p++)
436         {
437                 RAS_Polygon* poly = meshobj->GetPolygon(p);
438         
439                 // only add polygons that have the collisionflag set
440                 if (poly->IsCollider())
441                 {
442                         // check polygon is from the same vertex array
443                         if (poly->GetVertexIndexBase().m_vtxarray != vtxarray)
444                         {
445                                 if (vtxarray < 0)
446                                         vtxarray = poly->GetVertexIndexBase().m_vtxarray;
447                                 else
448                                 {
449                                         reinstance = false;
450                                         vtxarray = -1;
451                                 }
452                         }
453                         
454                         // check poly is from the same material
455                         if (poly->GetMaterial()->GetPolyMaterial() != poly_material)
456                         {
457                                 if (poly_material)
458                                 {
459                                         reinstance = false;
460                                         poly_material = NULL;
461                                 }
462                                 else
463                                         poly_material = poly->GetMaterial()->GetPolyMaterial();
464                         }
465                         
466                         // count the number of collision polys
467                         numvalidpolys++;
468                         
469                         // We have one collision poly, and we can't reinstance, so we
470                         // might as well break here.
471                         if (!reinstance)
472                                 break;
473                 }
474         }
475         
476         // No collision polygons
477         if (numvalidpolys < 1)
478                 return NULL;
479         
480         DT_ShapeHandle shape;
481         if (reinstance)
482         {
483                 if (polytope)
484                         shape = InstancePhysicsPolytope(meshobj, vtxarray, poly_material);
485                 else
486                         shape = InstancePhysicsComplex(meshobj, vtxarray, poly_material);
487         }
488         else
489         {
490                 if (polytope)
491                 {
492                         std::cout << "CreateShapeFromMesh: " << meshobj->GetName() << " is not suitable for polytope." << std::endl;
493                         if (!poly_material)
494                                 std::cout << "                     Check mesh materials." << std::endl;
495                         if (vtxarray < 0)
496                                 std::cout << "                     Check number of vertices." << std::endl;
497                 }
498                 
499                 shape = DT_NewComplexShape(NULL);
500                         
501                 numvalidpolys = 0;
502         
503                 for (int p2=0; p2<numpolys; p2++)
504                 {
505                         RAS_Polygon* poly = meshobj->GetPolygon(p2);
506                 
507                         // only add polygons that have the collisionflag set
508                         if (poly->IsCollider())
509                         {   /* We have to tesselate here because SOLID can only raycast triangles */
510                            DT_Begin();
511                                 /* V1 */
512                                 DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
513                                         poly->GetVertexIndexBase().m_indexarray[2],
514                                         poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
515                                 /* V2 */
516                                 DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
517                                         poly->GetVertexIndexBase().m_indexarray[1],
518                                         poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
519                                 /* V3 */
520                                 DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
521                                         poly->GetVertexIndexBase().m_indexarray[0],
522                                         poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
523                                 
524                                 numvalidpolys++;
525                            DT_End();
526                                 
527                                 if (poly->VertexCount() == 4)
528                                 {
529                                    DT_Begin();
530                                         /* V1 */
531                                         DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
532                                                 poly->GetVertexIndexBase().m_indexarray[3],
533                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
534                                         /* V3 */
535                                         DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
536                                                 poly->GetVertexIndexBase().m_indexarray[2],
537                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
538                                         /* V4 */
539                                         DT_Vertex(meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
540                                                 poly->GetVertexIndexBase().m_indexarray[0],
541                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ());
542                                 
543                                         numvalidpolys++;
544                                    DT_End();
545                                 }
546                 
547                         }
548                 }
549                 
550                 DT_EndComplexShape();
551         }
552
553         if (numvalidpolys > 0)
554         {
555                 map_gamemesh_to_sumoshape.insert(GEN_HashedPtr(meshobj),shape);
556                 return shape;
557         }
558
559         delete shape;
560         return NULL;
561 }
562
563 void    KX_ClearSumoSharedShapes()
564 {
565         int numshapes = map_gamemesh_to_sumoshape.size();
566         int i;
567         for (i=0;i<numshapes ;i++)
568         {
569                 DT_ShapeHandle shape = *map_gamemesh_to_sumoshape.at(i);
570                 DT_DeleteShape(shape);
571         }
572         
573         map_gamemesh_to_sumoshape.clear();
574         
575         for (i=0; i < map_gamemesh_to_instance.size(); i++)
576                 delete *map_gamemesh_to_instance.at(i);
577         
578         map_gamemesh_to_instance.clear();
579 }
580
581
582
583
584
585 #endif //USE_SUMO_SOLID
586
587
588 #ifdef USE_ODE
589
590 void    KX_ConvertODEEngineObject(KX_GameObject* gameobj,
591                                                          RAS_MeshObject* meshobj,
592                                                          KX_Scene* kxscene,
593                                                         struct  PHY_ShapeProps* shapeprops,
594                                                         struct  PHY_MaterialProps*      smmaterial,
595                                                         struct  KX_ObjectProperties*    objprop)
596 {
597         
598         // not yet, future extension :)
599         bool dyna=objprop->m_dyna;
600         bool fullRigidBody= ( objprop->m_dyna && objprop->m_angular_rigidbody) != 0;
601         bool phantom = objprop->m_ghost;
602         class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
603
604         class ODEPhysicsEnvironment* odeEnv =
605                 (ODEPhysicsEnvironment*)kxscene->GetPhysicsEnvironment();
606
607         dxSpace* space = odeEnv->GetOdeSpace();
608         dxWorld* world = odeEnv->GetOdeWorld();
609
610         bool isSphere = false;
611
612         switch (objprop->m_boundclass)
613         {
614         case KX_BOUNDBOX:
615                 {
616
617                                 KX_OdePhysicsController* physicscontroller = 
618                                         new KX_OdePhysicsController(
619                                         dyna,
620                                         fullRigidBody,
621                                         phantom,
622                                         motionstate,
623                                         space,
624                                         world,
625                                         shapeprops->m_mass,
626                                         smmaterial->m_friction,
627                                         smmaterial->m_restitution,
628                                         isSphere,
629                                         objprop->m_boundobject.box.m_center,
630                                         objprop->m_boundobject.box.m_extends,
631                                         objprop->m_boundobject.c.m_radius
632                                         );
633
634                                 gameobj->SetPhysicsController(physicscontroller);
635                                 physicscontroller->setNewClientInfo(gameobj->getClientInfo());                                          
636                                 gameobj->GetSGNode()->AddSGController(physicscontroller);
637
638                                 bool isActor = objprop->m_isactor;
639                                 STR_String materialname;
640                                 if (meshobj)
641                                         materialname = meshobj->GetMaterialName(0);
642
643                                 const char* matname = materialname.ReadPtr();
644
645
646                                 physicscontroller->SetObject(gameobj->GetSGNode());
647
648                                 break;
649                         }
650         default:
651                 {
652                 }
653         };
654
655 }
656
657
658 #endif // USE_ODE
659
660
661 #ifdef USE_BULLET
662
663 #include "CcdPhysicsEnvironment.h"
664 #include "CcdPhysicsController.h"
665
666 #include "KX_BulletPhysicsController.h"
667 #include "CollisionShapes/BoxShape.h"
668 #include "CollisionShapes/SphereShape.h"
669 #include "CollisionShapes/ConeShape.h"
670 #include "CollisionShapes/ConvexShape.h"
671 #include "CollisionShapes/CylinderShape.h"
672 #include "CollisionShapes/MultiSphereShape.h"
673 #include "CollisionShapes/ConvexHullShape.h"
674 #include "CollisionShapes/TriangleMesh.h"
675 #include "CollisionShapes/TriangleMeshShape.h"
676 #include "CollisionShapes/BvhTriangleMeshShape.h"
677
678
679 static GEN_Map<GEN_HashedPtr,CollisionShape*>   map_gamemesh_to_bulletshape;
680
681 // forward declarations
682 static CollisionShape* CreateBulletShapeFromMesh(RAS_MeshObject* meshobj, bool polytope)
683 {
684         if (!meshobj)
685                 return 0;
686
687         CollisionShape* collisionMeshShape = 0;
688         ConvexHullShape* convexHullShape = 0;
689         TriangleMeshShape* concaveShape = 0;
690
691         TriangleMesh* collisionMeshData = 0;
692
693         //see if there is any polygons, if not, bail out.
694
695         int numUsedPolygons = 0;
696         int numPoints = 0;
697         SimdVector3* points = 0;
698
699         CollisionShape** shapeptr = map_gamemesh_to_bulletshape[GEN_HashedPtr(meshobj)];
700
701         // Mesh has already been converted: reuse
702         if (shapeptr)
703         {
704                 //return *shapeptr;
705         }
706
707         // Mesh has no polygons!
708         int numpolys = meshobj->NumPolygons();
709         if (!numpolys)
710         {
711                 return NULL;
712         }
713
714         // Count the number of collision polygons and check they all come from the same 
715         // vertex array
716         int numvalidpolys = 0;
717         int vtxarray = -1;
718         RAS_IPolyMaterial *poly_material = NULL;
719         bool reinstance = true;
720
721         for (int p=0; p<numpolys; p++)
722         {
723                 RAS_Polygon* poly = meshobj->GetPolygon(p);
724
725                 // only add polygons that have the collisionflag set
726                 if (poly->IsCollider())
727                 {
728                         // check polygon is from the same vertex array
729                         if (poly->GetVertexIndexBase().m_vtxarray != vtxarray)
730                         {
731                                 if (vtxarray < 0)
732                                         vtxarray = poly->GetVertexIndexBase().m_vtxarray;
733                                 else
734                                 {
735                                         reinstance = false;
736                                         vtxarray = -1;
737                                 }
738                         }
739
740                         // check poly is from the same material
741                         if (poly->GetMaterial()->GetPolyMaterial() != poly_material)
742                         {
743                                 if (poly_material)
744                                 {
745                                         reinstance = false;
746                                         poly_material = NULL;
747                                 }
748                                 else
749                                         poly_material = poly->GetMaterial()->GetPolyMaterial();
750                         }
751
752                         // count the number of collision polys
753                         numvalidpolys++;
754
755                         // We have one collision poly, and we can't reinstance, so we
756                         // might as well break here.
757                         if (!reinstance)
758                                 break;
759                 }
760         }
761
762         // No collision polygons
763         if (numvalidpolys < 1)
764                 return NULL;
765
766
767         if (polytope)
768         {
769                 convexHullShape = new ConvexHullShape(points,numPoints);
770                 collisionMeshShape = convexHullShape;
771         } else
772         {
773                 collisionMeshData = new TriangleMesh();
774 //              concaveShape = new TriangleMeshShape(collisionMeshData);
775                 //collisionMeshShape = concaveShape;
776
777         }
778
779
780         numvalidpolys = 0;
781
782         for (int p2=0; p2<numpolys; p2++)
783         {
784                 RAS_Polygon* poly = meshobj->GetPolygon(p2);
785
786                 // only add polygons that have the collisionflag set
787                 if (poly->IsCollider())
788                 {   
789                         //Bullet can raycast any shape, so
790                         if (polytope)
791                         {
792                                 for (int i=0;i<poly->VertexCount();i++)
793                                 {
794                                         const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
795                                                 poly->GetVertexIndexBase().m_indexarray[i],
796                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
797                                         SimdPoint3 point(vtx[0],vtx[1],vtx[2]);
798                                         convexHullShape->AddPoint(point);
799                                 }
800                                 if (poly->VertexCount())
801                                         numvalidpolys++;
802
803                         } else
804                         {
805                                 {
806                                         const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
807                                                 poly->GetVertexIndexBase().m_indexarray[2],
808                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
809                                         SimdPoint3 vertex0(vtx[0],vtx[1],vtx[2]);
810                                         vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
811                                                 poly->GetVertexIndexBase().m_indexarray[1],
812                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
813                                         SimdPoint3 vertex1(vtx[0],vtx[1],vtx[2]);
814                                         vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
815                                                 poly->GetVertexIndexBase().m_indexarray[0],
816                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
817                                         SimdPoint3 vertex2(vtx[0],vtx[1],vtx[2]);
818                                         collisionMeshData->AddTriangle(vertex0,vertex1,vertex2);
819                                         numvalidpolys++;
820                                 }
821                                 if (poly->VertexCount() == 4)
822                                 {
823                                         const float* vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
824                                                 poly->GetVertexIndexBase().m_indexarray[3],
825                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
826                                         SimdPoint3 vertex0(vtx[0],vtx[1],vtx[2]);
827                                         vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
828                                                 poly->GetVertexIndexBase().m_indexarray[2],
829                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
830                                         SimdPoint3 vertex1(vtx[0],vtx[1],vtx[2]);
831                                         vtx = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, 
832                                                 poly->GetVertexIndexBase().m_indexarray[0],
833                                                 poly->GetMaterial()->GetPolyMaterial())->getLocalXYZ();
834                                         SimdPoint3 vertex2(vtx[0],vtx[1],vtx[2]);
835                                         collisionMeshData->AddTriangle(vertex0,vertex1,vertex2);
836                                         numvalidpolys++;
837                                 }
838
839                         }               
840                 }
841         }
842
843
844
845         if (numvalidpolys > 0)
846         {
847                 
848                 //map_gamemesh_to_bulletshape.insert(GEN_HashedPtr(meshobj),collisionMeshShape);
849                 if (!polytope)
850                 {
851                         concaveShape = new BvhTriangleMeshShape( collisionMeshData );
852                         //concaveShape = new TriangleMeshShape( collisionMeshData );
853
854                         concaveShape->RecalcLocalAabb();
855                         collisionMeshShape = concaveShape;
856
857                 } 
858                 
859                 
860
861                 return collisionMeshShape;
862         }
863
864         delete collisionMeshShape;
865         return NULL;
866
867 }
868
869
870
871 void    KX_ConvertBulletObject( class   KX_GameObject* gameobj,
872         class   RAS_MeshObject* meshobj,
873         class   KX_Scene* kxscene,
874         struct  PHY_ShapeProps* shapeprops,
875         struct  PHY_MaterialProps*      smmaterial,
876         struct  KX_ObjectProperties*    objprop)
877 {
878
879                 CcdPhysicsEnvironment* env = (CcdPhysicsEnvironment*)kxscene->GetPhysicsEnvironment();
880         assert(env);
881         
882
883         bool isbulletdyna = false;
884         CcdConstructionInfo ci;
885         class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode());
886
887         ci.m_MotionState = motionstate;
888         ci.m_gravity = SimdVector3(0,0,0);
889         ci.m_localInertiaTensor =SimdVector3(0,0,0);
890         ci.m_mass = objprop->m_dyna ? shapeprops->m_mass : 0.f;
891         isbulletdyna = objprop->m_dyna;
892
893         ci.m_localInertiaTensor = SimdVector3(ci.m_mass/3.f,ci.m_mass/3.f,ci.m_mass/3.f);
894         
895         SimdTransform trans;
896         trans.setIdentity();
897         
898         CollisionShape* bm = 0;
899
900         switch (objprop->m_boundclass)
901         {
902         case KX_BOUNDSPHERE:
903                 {
904                         float radius = objprop->m_radius;
905                         SimdVector3 inertiaHalfExtents (
906                                 radius,
907                                 radius,
908                                 radius);
909                         
910                         //blender doesn't support multisphere, but for testing:
911
912                         //bm = new MultiSphereShape(inertiaHalfExtents,,&trans.getOrigin(),&radius,1);
913                         bm = new SphereShape(objprop->m_radius);
914                         bm->CalculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
915                         break;
916                 };
917         case KX_BOUNDBOX:
918                 {
919                         MT_Vector3 halfExtents (
920                                 objprop->m_boundobject.box.m_extends[0],
921                         objprop->m_boundobject.box.m_extends[1],
922                         objprop->m_boundobject.box.m_extends[2]);
923
924                         halfExtents /= 2.f;
925
926                         //SimdVector3 he (halfExtents[0]-CONVEX_DISTANCE_MARGIN ,halfExtents[1]-CONVEX_DISTANCE_MARGIN ,halfExtents[2]-CONVEX_DISTANCE_MARGIN );
927                         //he = he.absolute();
928
929                         SimdVector3 he (halfExtents[0],halfExtents[1],halfExtents[2]);
930                         he = he.absolute();
931
932
933                         bm = new BoxShape(he);
934                         bm->CalculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
935                         break;
936                 };
937         case KX_BOUNDCYLINDER:
938                 {
939                         SimdVector3 halfExtents (
940                                 objprop->m_boundobject.c.m_radius,
941                                 objprop->m_boundobject.c.m_radius,
942                                 objprop->m_boundobject.c.m_height * 0.5f
943                         );
944                         bm = new CylinderShapeZ(halfExtents);
945                         bm->CalculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
946
947                         break;
948                 }
949
950                 case KX_BOUNDCONE:
951                 {
952                                 SimdVector3 halfExtents (objprop->m_boundobject.box.m_extends[0],
953                                 objprop->m_boundobject.box.m_extends[1],
954                                 objprop->m_boundobject.box.m_extends[2]);
955
956
957                                 halfExtents /= 2.f;
958                                 SimdVector3&    he  = halfExtents;
959                                 SimdTransform& tr = trans;
960
961                                 bm = new ConeShape(objprop->m_boundobject.c.m_radius,objprop->m_boundobject.c.m_height);
962                                 bm->CalculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
963
964                         break;
965                 }
966                 case KX_BOUNDPOLYTOPE:
967                         {
968                                 bm = CreateBulletShapeFromMesh(meshobj,true);
969                                 if (bm)
970                                 {
971                                         bm->CalculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
972                                 }
973                                 break;
974                         }
975                 case KX_BOUNDMESH:
976                         {
977                                 if (!ci.m_mass)
978                                 {                               
979                                         bm = CreateBulletShapeFromMesh(meshobj,false);
980                                         ci.m_localInertiaTensor.setValue(0.f,0.f,0.f);
981                                         //no moving concave meshes, so don't bother calculating inertia
982                                         //bm->CalculateLocalInertia(ci.m_mass,ci.m_localInertiaTensor);
983                                 }
984
985                                 break;
986                         }
987
988         default:
989                 //interpret the shape as a concave triangle-mesh
990                 {
991                         if (meshobj)
992                         {
993                         //      assert(0);
994
995                                         /*
996                                 meshobj->ScheduleCollisionPolygons();
997
998                                 KX_DeformableMesh* gfxmesh = new KX_DeformableMesh(meshobj);
999                                 gfxmesh->sendFixedMapping();
1000                                 //trianglemesh
1001                                 bm = new TriangleMeshInterface(gfxmesh,trans);
1002                                 */
1003                         }
1004                 }
1005         }
1006
1007
1008 //      ci.m_localInertiaTensor.setValue(0.1f,0.1f,0.1f);
1009
1010         if (!bm)
1011                 return;
1012
1013         bm->SetMargin(0.06);
1014
1015         ci.m_collisionShape = bm;
1016         ci.m_broadphaseHandle = 0;
1017         ci.m_friction = smmaterial->m_friction;
1018         ci.m_restitution = smmaterial->m_restitution;
1019         ci.m_physicsEnv = env;
1020         // drag / damping is inverted
1021         ci.m_linearDamping = 1.f - shapeprops->m_lin_drag;
1022         ci.m_angularDamping = 1.f - shapeprops->m_ang_drag;
1023         //need a bit of damping, else system doesn't behave well
1024         
1025
1026         KX_BulletPhysicsController* physicscontroller = new KX_BulletPhysicsController(ci,isbulletdyna);
1027
1028         if (objprop->m_in_active_layer)
1029         {
1030                 env->addCcdPhysicsController( physicscontroller);
1031         }
1032
1033         
1034         gameobj->SetPhysicsController(physicscontroller,isbulletdyna);
1035         physicscontroller->setNewClientInfo(gameobj->getClientInfo());          
1036         bool isActor = objprop->m_isactor;
1037         gameobj->getClientInfo()->m_type = (isActor ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC);
1038         // store materialname in auxinfo, needed for touchsensors
1039         //gameobj->getClientInfo()->m_auxilary_info = 0;//(matname.Length() ? (void*)(matname.ReadPtr()+2) : NULL);
1040         //gameobj->getClientInfo()->m_auxilary_info = (matname.Length() ? (void*)(matname.ReadPtr()+2) : NULL);
1041
1042
1043         gameobj->GetSGNode()->AddSGController(physicscontroller);
1044
1045         STR_String materialname;
1046         if (meshobj)
1047                 materialname = meshobj->GetMaterialName(0);
1048
1049         const char* matname = materialname.ReadPtr();
1050
1051
1052         physicscontroller->SetObject(gameobj->GetSGNode());
1053                                 
1054
1055 }
1056         
1057 void    KX_ClearBulletSharedShapes()
1058 {
1059         int numshapes = map_gamemesh_to_bulletshape.size();
1060         int i;
1061         CollisionShape*shape=0;
1062         for (i=0;i<numshapes ;i++)
1063         {
1064                 shape = *map_gamemesh_to_bulletshape.at(i);
1065                 //delete shape;
1066         }
1067         
1068         map_gamemesh_to_bulletshape.clear();
1069         
1070 }
1071
1072
1073 #endif