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