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