2e9b988dff1f23fc287cdc0bd4d6d082724356de
[blender.git] / source / gameengine / Ketsji / KX_PyConstraintBinding.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file gameengine/Ketsji/KX_PyConstraintBinding.cpp
29  *  \ingroup ketsji
30  */
31
32 #include "KX_PyConstraintBinding.h"
33 #include "PHY_IPhysicsEnvironment.h"
34 #include "KX_ConstraintWrapper.h"
35 #include "KX_VehicleWrapper.h"
36 #include "KX_CharacterWrapper.h"
37 #include "PHY_IPhysicsController.h"
38 #include "PHY_IVehicle.h"
39 #include "PHY_DynamicTypes.h"
40 #include "MT_Matrix3x3.h"
41
42 #include "KX_GameObject.h" // ConvertPythonToGameObject()
43
44 #include "PyObjectPlus.h" 
45
46 #ifdef WITH_BULLET
47 #  include "LinearMath/btIDebugDraw.h"
48 #endif
49
50 #ifdef WITH_PYTHON
51
52 // macro copied from KX_PythonInit.cpp
53 #define KX_MACRO_addTypesToDict(dict, name, name2) PyDict_SetItemString(dict, #name, item=PyLong_FromLong(name2)); Py_DECREF(item)
54
55 // nasty glob variable to connect scripting language
56 // if there is a better way (without global), please do so!
57 static PHY_IPhysicsEnvironment* g_CurrentActivePhysicsEnvironment = NULL;
58
59 static char PhysicsConstraints_module_documentation[] =
60 "This is the Python API for the Physics Constraints";
61
62
63 static char gPySetGravity__doc__[] = "setGravity(float x,float y,float z)";
64 static char gPySetDebugMode__doc__[] = "setDebugMode(int mode)";
65
66 static char gPySetNumIterations__doc__[] = "setNumIterations(int numiter) This sets the number of iterations for an iterative constraint solver";
67 static char gPySetNumTimeSubSteps__doc__[] = "setNumTimeSubSteps(int numsubstep) This sets the number of substeps for each physics proceed. Tradeoff quality for performance.";
68
69
70 static char gPySetDeactivationTime__doc__[] = "setDeactivationTime(float time) This sets the time after which a resting rigidbody gets deactived";
71 static char gPySetDeactivationLinearTreshold__doc__[] = "setDeactivationLinearTreshold(float linearTreshold)";
72 static char gPySetDeactivationAngularTreshold__doc__[] = "setDeactivationAngularTreshold(float angularTreshold)";
73 static char gPySetContactBreakingTreshold__doc__[] = "setContactBreakingTreshold(float breakingTreshold) Reasonable default is 0.02 (if units are meters)";
74
75 static char gPySetCcdMode__doc__[] = "setCcdMode(int ccdMode) Very experimental, not recommended";
76 static char gPySetSorConstant__doc__[] = "setSorConstant(float sor) Very experimental, not recommended";
77 static char gPySetSolverTau__doc__[] = "setTau(float tau) Very experimental, not recommended";
78 static char gPySetSolverDamping__doc__[] = "setDamping(float damping) Very experimental, not recommended";
79 static char gPySetLinearAirDamping__doc__[] = "setLinearAirDamping(float damping) Very experimental, not recommended";
80 static char gPySetUseEpa__doc__[] = "setUseEpa(int epa) Very experimental, not recommended";
81 static char gPySetSolverType__doc__[] = "setSolverType(int solverType) Very experimental, not recommended";
82
83
84 static char gPyCreateConstraint__doc__[] = "createConstraint(ob1,ob2,float restLength,float restitution,float damping)";
85 static char gPyGetVehicleConstraint__doc__[] = "getVehicleConstraint(int constraintId)";
86 static char gPyGetCharacter__doc__[] = "getCharacter(KX_GameObject obj)";
87 static char gPyRemoveConstraint__doc__[] = "removeConstraint(int constraintId)";
88 static char gPyGetAppliedImpulse__doc__[] = "getAppliedImpulse(int constraintId)";
89
90
91
92
93
94
95 static PyObject *gPySetGravity(PyObject *self,
96                                PyObject *args,
97                                PyObject *kwds)
98 {
99         float x,y,z;
100         if (PyArg_ParseTuple(args,"fff",&x,&y,&z))
101         {
102                 if (PHY_GetActiveEnvironment())
103                         PHY_GetActiveEnvironment()->setGravity(x,y,z);
104         }
105         else {
106                 return NULL;
107         }
108         
109         Py_RETURN_NONE;
110 }
111
112 static PyObject *gPySetDebugMode(PyObject *self,
113                                  PyObject *args,
114                                  PyObject *kwds)
115 {
116         int mode;
117         if (PyArg_ParseTuple(args,"i",&mode))
118         {
119                 if (PHY_GetActiveEnvironment())
120                 {
121                         PHY_GetActiveEnvironment()->setDebugMode(mode);
122                         
123                 }
124                 
125         }
126         else {
127                 return NULL;
128         }
129         
130         Py_RETURN_NONE;
131 }
132
133
134
135 static PyObject *gPySetNumTimeSubSteps(PyObject *self,
136                                        PyObject *args,
137                                        PyObject *kwds)
138 {
139         int substep;
140         if (PyArg_ParseTuple(args,"i",&substep))
141         {
142                 if (PHY_GetActiveEnvironment())
143                 {
144                         PHY_GetActiveEnvironment()->setNumTimeSubSteps(substep);
145                 }
146         }
147         else {
148                 return NULL;
149         }
150         Py_RETURN_NONE;
151 }
152
153
154 static PyObject *gPySetNumIterations(PyObject *self,
155                                      PyObject *args,
156                                      PyObject *kwds)
157 {
158         int iter;
159         if (PyArg_ParseTuple(args,"i",&iter))
160         {
161                 if (PHY_GetActiveEnvironment())
162                 {
163                         PHY_GetActiveEnvironment()->setNumIterations(iter);
164                 }
165         }
166         else {
167                 return NULL;
168         }
169         Py_RETURN_NONE;
170 }
171
172
173 static PyObject *gPySetDeactivationTime(PyObject *self,
174                                         PyObject *args,
175                                         PyObject *kwds)
176 {
177         float deactive_time;
178         if (PyArg_ParseTuple(args,"f",&deactive_time))
179         {
180                 if (PHY_GetActiveEnvironment())
181                 {
182                         PHY_GetActiveEnvironment()->setDeactivationTime(deactive_time);
183                 }
184         }
185         else {
186                 return NULL;
187         }
188         Py_RETURN_NONE;
189 }
190
191
192 static PyObject *gPySetDeactivationLinearTreshold(PyObject *self,
193                                                   PyObject *args,
194                                                   PyObject *kwds)
195 {
196         float linearDeactivationTreshold;
197         if (PyArg_ParseTuple(args,"f",&linearDeactivationTreshold))
198         {
199                 if (PHY_GetActiveEnvironment())
200                 {
201                         PHY_GetActiveEnvironment()->setDeactivationLinearTreshold( linearDeactivationTreshold);
202                 }
203         }
204         else {
205                 return NULL;
206         }
207         Py_RETURN_NONE;
208 }
209
210
211 static PyObject *gPySetDeactivationAngularTreshold(PyObject *self,
212                                                    PyObject *args,
213                                                    PyObject *kwds)
214 {
215         float angularDeactivationTreshold;
216         if (PyArg_ParseTuple(args,"f",&angularDeactivationTreshold))
217         {
218                 if (PHY_GetActiveEnvironment())
219                 {
220                         PHY_GetActiveEnvironment()->setDeactivationAngularTreshold( angularDeactivationTreshold);
221                 }
222         }
223         else {
224                 return NULL;
225         }
226         Py_RETURN_NONE;
227 }
228
229 static PyObject *gPySetContactBreakingTreshold(PyObject *self,
230                                                PyObject *args,
231                                                PyObject *kwds)
232 {
233         float contactBreakingTreshold;
234         if (PyArg_ParseTuple(args,"f",&contactBreakingTreshold))
235         {
236                 if (PHY_GetActiveEnvironment())
237                 {
238                         PHY_GetActiveEnvironment()->setContactBreakingTreshold( contactBreakingTreshold);
239                 }
240         }
241         else {
242                 return NULL;
243         }
244         Py_RETURN_NONE;
245 }
246
247
248 static PyObject *gPySetCcdMode(PyObject *self,
249                                PyObject *args,
250                                PyObject *kwds)
251 {
252         float ccdMode;
253         if (PyArg_ParseTuple(args,"f",&ccdMode))
254         {
255                 if (PHY_GetActiveEnvironment())
256                 {
257                         PHY_GetActiveEnvironment()->setCcdMode( ccdMode);
258                 }
259         }
260         else {
261                 return NULL;
262         }
263         Py_RETURN_NONE;
264 }
265
266 static PyObject *gPySetSorConstant(PyObject *self,
267                                    PyObject *args,
268                                    PyObject *kwds)
269 {
270         float sor;
271         if (PyArg_ParseTuple(args,"f",&sor))
272         {
273                 if (PHY_GetActiveEnvironment())
274                 {
275                         PHY_GetActiveEnvironment()->setSolverSorConstant( sor);
276                 }
277         }
278         else {
279                 return NULL;
280         }
281         Py_RETURN_NONE;
282 }
283
284 static PyObject *gPySetSolverTau(PyObject *self,
285                                  PyObject *args,
286                                  PyObject *kwds)
287 {
288         float tau;
289         if (PyArg_ParseTuple(args,"f",&tau))
290         {
291                 if (PHY_GetActiveEnvironment())
292                 {
293                         PHY_GetActiveEnvironment()->setSolverTau( tau);
294                 }
295         }
296         else {
297                 return NULL;
298         }
299         Py_RETURN_NONE;
300 }
301
302
303 static PyObject *gPySetSolverDamping(PyObject *self,
304                                      PyObject *args,
305                                      PyObject *kwds)
306 {
307         float damping;
308         if (PyArg_ParseTuple(args,"f",&damping))
309         {
310                 if (PHY_GetActiveEnvironment())
311                 {
312                         PHY_GetActiveEnvironment()->setSolverDamping( damping);
313                 }
314         }
315         else {
316                 return NULL;
317         }
318         Py_RETURN_NONE;
319 }
320
321 static PyObject *gPySetLinearAirDamping(PyObject *self,
322                                         PyObject *args,
323                                         PyObject *kwds)
324 {
325         float damping;
326         if (PyArg_ParseTuple(args,"f",&damping))
327         {
328                 if (PHY_GetActiveEnvironment())
329                 {
330                         PHY_GetActiveEnvironment()->setLinearAirDamping( damping);
331                 }
332         }
333         else {
334                 return NULL;
335         }
336         Py_RETURN_NONE;
337 }
338
339
340 static PyObject *gPySetUseEpa(PyObject *self,
341                               PyObject *args,
342                               PyObject *kwds)
343 {
344         int     epa;
345         if (PyArg_ParseTuple(args,"i",&epa))
346         {
347                 if (PHY_GetActiveEnvironment())
348                 {
349                         PHY_GetActiveEnvironment()->setUseEpa(epa);
350                 }
351         }
352         else {
353                 return NULL;
354         }
355         Py_RETURN_NONE;
356 }
357 static PyObject *gPySetSolverType(PyObject *self,
358                                   PyObject *args,
359                                   PyObject *kwds)
360 {
361         int     solverType;
362         if (PyArg_ParseTuple(args,"i",&solverType))
363         {
364                 if (PHY_GetActiveEnvironment())
365                 {
366                         PHY_GetActiveEnvironment()->setSolverType(solverType);
367                 }
368         }
369         else {
370                 return NULL;
371         }
372         Py_RETURN_NONE;
373 }
374
375
376
377 static PyObject *gPyGetVehicleConstraint(PyObject *self,
378                                          PyObject *args,
379                                          PyObject *kwds)
380 {
381 #if defined(_WIN64)
382         __int64 constraintid;
383         if (PyArg_ParseTuple(args,"L",&constraintid))
384 #else
385         long constraintid;
386         if (PyArg_ParseTuple(args,"l",&constraintid))
387 #endif
388         {
389                 if (PHY_GetActiveEnvironment())
390                 {
391                         
392                         PHY_IVehicle* vehicle = PHY_GetActiveEnvironment()->getVehicleConstraint(constraintid);
393                         if (vehicle)
394                         {
395                                 KX_VehicleWrapper* pyWrapper = new KX_VehicleWrapper(vehicle,PHY_GetActiveEnvironment());
396                                 return pyWrapper->NewProxy(true);
397                         }
398
399                 }
400         }
401         else {
402                 return NULL;
403         }
404
405         Py_RETURN_NONE;
406 }
407
408 static PyObject* gPyGetCharacter(PyObject* self,
409                                  PyObject* args,
410                                  PyObject* kwds)
411 {
412         PyObject* pyob;
413         KX_GameObject *ob;
414
415         if (!PyArg_ParseTuple(args,"O", &pyob))
416                 return NULL;
417
418         if (!ConvertPythonToGameObject(pyob, &ob, false, "bge.constraints.getCharacter(value)"))
419                 return NULL;
420
421         if (PHY_GetActiveEnvironment())
422         {
423                         
424                 PHY_ICharacter* character= PHY_GetActiveEnvironment()->getCharacterController(ob);
425                 if (character)
426                 {
427                         KX_CharacterWrapper* pyWrapper = new KX_CharacterWrapper(character);
428                         return pyWrapper->NewProxy(true);
429                 }
430
431         }
432
433         Py_RETURN_NONE;
434 }
435
436 static PyObject *gPyCreateConstraint(PyObject *self,
437                                      PyObject *args,
438                                      PyObject *kwds)
439 {
440         /* FIXME - physicsid is a long being cast to a pointer, should at least use PyCapsule */
441 #if defined(_WIN64)
442         __int64 physicsid=0,physicsid2 = 0;
443 #else
444         long physicsid=0,physicsid2 = 0;
445 #endif
446         int constrainttype=0, extrainfo=0;
447         int len = PyTuple_Size(args);
448         int success = 1;
449         int flag = 0;
450
451         float pivotX=1,pivotY=1,pivotZ=1,axisX=0,axisY=0,axisZ=1;
452         if (len == 3)
453         {
454 #if defined(_WIN64)
455                 success = PyArg_ParseTuple(args,"LLi",&physicsid,&physicsid2,&constrainttype);
456 #else
457                 success = PyArg_ParseTuple(args,"lli",&physicsid,&physicsid2,&constrainttype);
458 #endif
459         }
460         else if (len == 6)
461         {
462 #if defined(_WIN64)
463                 success = PyArg_ParseTuple(args,"LLifff",&physicsid,&physicsid2,&constrainttype,
464                                            &pivotX,&pivotY,&pivotZ);
465 #else
466                 success = PyArg_ParseTuple(args,"llifff",&physicsid,&physicsid2,&constrainttype,
467                                            &pivotX,&pivotY,&pivotZ);
468 #endif
469         }
470         else if (len == 9)
471         {
472 #if defined(_WIN64)
473                 success = PyArg_ParseTuple(args,"LLiffffff",&physicsid,&physicsid2,&constrainttype,
474                                            &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ);
475 #else
476                 success = PyArg_ParseTuple(args,"lliffffff",&physicsid,&physicsid2,&constrainttype,
477                                            &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ);
478 #endif
479         }
480         else if (len == 10)
481         {
482 #if defined(_WIN64)
483                 success = PyArg_ParseTuple(args,"LLiffffffi",&physicsid,&physicsid2,&constrainttype,
484                                            &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ,&flag);
485 #else
486                 success = PyArg_ParseTuple(args,"lliffffffi",&physicsid,&physicsid2,&constrainttype,
487                                            &pivotX,&pivotY,&pivotZ,&axisX,&axisY,&axisZ,&flag);
488 #endif
489         }
490
491         /* XXX extrainfo seems to be nothing implemented. right now it works as a pivot with [X,0,0] */
492         else if (len == 4)
493         {
494 #if defined(_WIN64)
495                 success = PyArg_ParseTuple(args,"LLii",&physicsid,&physicsid2,&constrainttype,&extrainfo);
496 #else
497                 success = PyArg_ParseTuple(args,"llii",&physicsid,&physicsid2,&constrainttype,&extrainfo);
498 #endif
499                 pivotX=extrainfo;
500         }
501
502         if (success)
503         {
504                 if (PHY_GetActiveEnvironment())
505                 {
506                         
507                         PHY_IPhysicsController* physctrl = (PHY_IPhysicsController*) physicsid;
508                         PHY_IPhysicsController* physctrl2 = (PHY_IPhysicsController*) physicsid2;
509                         if (physctrl) //TODO:check for existence of this pointer!
510                         {
511                                 PHY_ConstraintType ct = (PHY_ConstraintType) constrainttype;
512                                 int constraintid =0;
513
514                                 if (ct == PHY_GENERIC_6DOF_CONSTRAINT)
515                                 {
516                                         //convert from euler angle into axis
517                                         float radsPerDeg = 6.283185307179586232f / 360.f;
518
519                                         //we need to pass a full constraint frame, not just axis
520                                         //localConstraintFrameBasis
521                                         MT_Matrix3x3 localCFrame(MT_Vector3(radsPerDeg*axisX,radsPerDeg*axisY,radsPerDeg*axisZ));
522                                         MT_Vector3 axis0 = localCFrame.getColumn(0);
523                                         MT_Vector3 axis1 = localCFrame.getColumn(1);
524                                         MT_Vector3 axis2 = localCFrame.getColumn(2);
525
526                                         constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,
527                                                                                                     pivotX,pivotY,pivotZ,
528                                                                                                     (float)axis0.x(),(float)axis0.y(),(float)axis0.z(),
529                                                                                                     (float)axis1.x(),(float)axis1.y(),(float)axis1.z(),
530                                                                                                     (float)axis2.x(),(float)axis2.y(),(float)axis2.z(),flag);
531                                 }
532                                 else {
533                                         constraintid = PHY_GetActiveEnvironment()->createConstraint(physctrl,physctrl2,(enum PHY_ConstraintType)constrainttype,pivotX,pivotY,pivotZ,axisX,axisY,axisZ,0);
534                                 }
535                                 
536                                 KX_ConstraintWrapper* wrap = new KX_ConstraintWrapper((enum PHY_ConstraintType)constrainttype,constraintid,PHY_GetActiveEnvironment());
537
538                                 return wrap->NewProxy(true);
539                         }
540                         
541                         
542                 }
543         }
544         else {
545                 return NULL;
546         }
547
548         Py_RETURN_NONE;
549 }
550
551
552
553
554 static PyObject *gPyGetAppliedImpulse(PyObject *self,
555                                       PyObject *args,
556                                       PyObject *kwds)
557 {
558         float   appliedImpulse = 0.f;
559
560 #if defined(_WIN64)
561         __int64 constraintid;
562         if (PyArg_ParseTuple(args,"L",&constraintid))
563 #else
564         long constraintid;
565         if (PyArg_ParseTuple(args,"l",&constraintid))
566 #endif
567         {
568                 if (PHY_GetActiveEnvironment())
569                 {
570                         appliedImpulse = PHY_GetActiveEnvironment()->getAppliedImpulse(constraintid);
571                 }
572         }
573         else {
574                 return NULL;
575         }
576
577         return PyFloat_FromDouble(appliedImpulse);
578 }
579
580
581 static PyObject *gPyRemoveConstraint(PyObject *self,
582                                      PyObject *args,
583                                      PyObject *kwds)
584 {
585 #if defined(_WIN64)
586         __int64 constraintid;
587         if (PyArg_ParseTuple(args,"L",&constraintid))
588 #else
589         long constraintid;
590         if (PyArg_ParseTuple(args,"l",&constraintid))
591 #endif
592         {
593                 if (PHY_GetActiveEnvironment())
594                 {
595                         PHY_GetActiveEnvironment()->removeConstraint(constraintid);
596                 }
597         }
598         else {
599                 return NULL;
600         }
601         
602         Py_RETURN_NONE;
603 }
604
605 static PyObject *gPyExportBulletFile(PyObject *, PyObject *args)
606 {
607         char* filename;
608         if (!PyArg_ParseTuple(args,"s:exportBulletFile",&filename))
609                 return NULL;
610
611         if (PHY_GetActiveEnvironment())
612         {
613                 PHY_GetActiveEnvironment()->exportFile(filename);
614         }
615         Py_RETURN_NONE;
616 }
617
618 static struct PyMethodDef physicsconstraints_methods[] = {
619         {"setGravity",(PyCFunction) gPySetGravity,
620          METH_VARARGS, (const char*)gPySetGravity__doc__},
621         {"setDebugMode",(PyCFunction) gPySetDebugMode,
622          METH_VARARGS, (const char *)gPySetDebugMode__doc__},
623
624         /// settings that influence quality of the rigidbody dynamics
625         {"setNumIterations",(PyCFunction) gPySetNumIterations,
626          METH_VARARGS, (const char *)gPySetNumIterations__doc__},
627
628         {"setNumTimeSubSteps",(PyCFunction) gPySetNumTimeSubSteps,
629          METH_VARARGS, (const char *)gPySetNumTimeSubSteps__doc__},
630
631         {"setDeactivationTime",(PyCFunction) gPySetDeactivationTime,
632          METH_VARARGS, (const char *)gPySetDeactivationTime__doc__},
633
634         {"setDeactivationLinearTreshold",(PyCFunction) gPySetDeactivationLinearTreshold,
635          METH_VARARGS, (const char *)gPySetDeactivationLinearTreshold__doc__},
636         {"setDeactivationAngularTreshold",(PyCFunction) gPySetDeactivationAngularTreshold,
637          METH_VARARGS, (const char *)gPySetDeactivationAngularTreshold__doc__},
638
639         {"setContactBreakingTreshold",(PyCFunction) gPySetContactBreakingTreshold,
640          METH_VARARGS, (const char *)gPySetContactBreakingTreshold__doc__},
641         {"setCcdMode",(PyCFunction) gPySetCcdMode,
642          METH_VARARGS, (const char *)gPySetCcdMode__doc__},
643         {"setSorConstant",(PyCFunction) gPySetSorConstant,
644          METH_VARARGS, (const char *)gPySetSorConstant__doc__},
645         {"setSolverTau",(PyCFunction) gPySetSolverTau,
646          METH_VARARGS, (const char *)gPySetSolverTau__doc__},
647         {"setSolverDamping",(PyCFunction) gPySetSolverDamping,
648          METH_VARARGS, (const char *)gPySetSolverDamping__doc__},
649
650         {"setLinearAirDamping",(PyCFunction) gPySetLinearAirDamping,
651          METH_VARARGS, (const char *)gPySetLinearAirDamping__doc__},
652
653         {"setUseEpa",(PyCFunction) gPySetUseEpa,
654          METH_VARARGS, (const char *)gPySetUseEpa__doc__},
655         {"setSolverType",(PyCFunction) gPySetSolverType,
656          METH_VARARGS, (const char *)gPySetSolverType__doc__},
657
658
659         {"createConstraint",(PyCFunction) gPyCreateConstraint,
660          METH_VARARGS, (const char *)gPyCreateConstraint__doc__},
661         {"getVehicleConstraint",(PyCFunction) gPyGetVehicleConstraint,
662          METH_VARARGS, (const char *)gPyGetVehicleConstraint__doc__},
663
664         {"getCharacter",(PyCFunction) gPyGetCharacter,
665          METH_VARARGS, (const char *)gPyGetCharacter__doc__},
666
667         {"removeConstraint",(PyCFunction) gPyRemoveConstraint,
668          METH_VARARGS, (const char *)gPyRemoveConstraint__doc__},
669         {"getAppliedImpulse",(PyCFunction) gPyGetAppliedImpulse,
670          METH_VARARGS, (const char *)gPyGetAppliedImpulse__doc__},
671
672         {"exportBulletFile",(PyCFunction)gPyExportBulletFile,
673          METH_VARARGS, "export a .bullet file"},
674
675         //sentinel
676         { NULL, (PyCFunction) NULL, 0, NULL }
677 };
678
679 static struct PyModuleDef PhysicsConstraints_module_def = {
680         {}, /* m_base */
681         "PhysicsConstraints",  /* m_name */
682         PhysicsConstraints_module_documentation,  /* m_doc */
683         0,  /* m_size */
684         physicsconstraints_methods,  /* m_methods */
685         0,  /* m_reload */
686         0,  /* m_traverse */
687         0,  /* m_clear */
688         0,  /* m_free */
689 };
690
691 PyObject *initPythonConstraintBinding()
692 {
693
694         PyObject *ErrorObject;
695         PyObject *m;
696         PyObject *d;
697         PyObject *item;
698
699         /* Use existing module where possible
700          * be careful not to init any runtime vars after this */
701         m = PyImport_ImportModule( "PhysicsConstraints" );
702         if (m) {
703                 Py_DECREF(m);
704                 return m;
705         }
706         else {
707                 PyErr_Clear();
708                 
709                 m = PyModule_Create(&PhysicsConstraints_module_def);
710                 PyDict_SetItemString(PySys_GetObject("modules"), PhysicsConstraints_module_def.m_name, m);
711         }
712
713         // Add some symbolic constants to the module
714         d = PyModule_GetDict(m);
715         ErrorObject = PyUnicode_FromString("PhysicsConstraints.error");
716         PyDict_SetItemString(d, "error", ErrorObject);
717         Py_DECREF(ErrorObject);
718
719 #ifdef WITH_BULLET
720         //Debug Modes constants to be used with setDebugMode() python function
721         KX_MACRO_addTypesToDict(d, DBG_NODEBUG, btIDebugDraw::DBG_NoDebug);
722         KX_MACRO_addTypesToDict(d, DBG_DRAWWIREFRAME, btIDebugDraw::DBG_DrawWireframe);
723         KX_MACRO_addTypesToDict(d, DBG_DRAWAABB, btIDebugDraw::DBG_DrawAabb);
724         KX_MACRO_addTypesToDict(d, DBG_DRAWFREATURESTEXT, btIDebugDraw::DBG_DrawFeaturesText);
725         KX_MACRO_addTypesToDict(d, DBG_DRAWCONTACTPOINTS, btIDebugDraw::DBG_DrawContactPoints);
726         KX_MACRO_addTypesToDict(d, DBG_NOHELPTEXT, btIDebugDraw::DBG_NoHelpText);
727         KX_MACRO_addTypesToDict(d, DBG_DRAWTEXT, btIDebugDraw::DBG_DrawText);
728         KX_MACRO_addTypesToDict(d, DBG_PROFILETIMINGS, btIDebugDraw::DBG_ProfileTimings);
729         KX_MACRO_addTypesToDict(d, DBG_ENABLESATCOMPARISION, btIDebugDraw::DBG_EnableSatComparison);
730         KX_MACRO_addTypesToDict(d, DBG_DISABLEBULLETLCP, btIDebugDraw::DBG_DisableBulletLCP);
731         KX_MACRO_addTypesToDict(d, DBG_ENABLECCD, btIDebugDraw::DBG_EnableCCD);
732         KX_MACRO_addTypesToDict(d, DBG_DRAWCONSTRAINTS, btIDebugDraw::DBG_DrawConstraints);
733         KX_MACRO_addTypesToDict(d, DBG_DRAWCONSTRAINTLIMITS, btIDebugDraw::DBG_DrawConstraintLimits);
734         KX_MACRO_addTypesToDict(d, DBG_FASTWIREFRAME, btIDebugDraw::DBG_FastWireframe);
735 #endif // WITH_BULLET
736
737         //Constraint types to be used with createConstraint() python function
738         KX_MACRO_addTypesToDict(d, POINTTOPOINT_CONSTRAINT, PHY_POINT2POINT_CONSTRAINT);
739         KX_MACRO_addTypesToDict(d, LINEHINGE_CONSTRAINT, PHY_LINEHINGE_CONSTRAINT);
740         KX_MACRO_addTypesToDict(d, ANGULAR_CONSTRAINT, PHY_ANGULAR_CONSTRAINT);
741         KX_MACRO_addTypesToDict(d, CONETWIST_CONSTRAINT, PHY_CONE_TWIST_CONSTRAINT);
742         KX_MACRO_addTypesToDict(d, VEHICLE_CONSTRAINT, PHY_VEHICLE_CONSTRAINT);
743
744         // Check for errors
745         if (PyErr_Occurred()) {
746                 Py_FatalError("can't initialize module PhysicsConstraints");
747         }
748
749         return d;
750 }
751
752 #if 0
753 static void KX_RemovePythonConstraintBinding()
754 {
755 }
756 #endif
757
758 void    PHY_SetActiveEnvironment(class  PHY_IPhysicsEnvironment* env)
759 {
760         g_CurrentActivePhysicsEnvironment = env;
761 }
762
763 PHY_IPhysicsEnvironment*        PHY_GetActiveEnvironment()
764 {
765         return g_CurrentActivePhysicsEnvironment;
766 }
767
768 #endif // WITH_PYTHON