2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): none yet.
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file gameengine/Ketsji/KX_PyConstraintBinding.cpp
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"
42 #include "KX_GameObject.h" // ConvertPythonToGameObject()
44 #include "PyObjectPlus.h"
47 # include "LinearMath/btIDebugDraw.h"
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)
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;
60 PyDoc_STRVAR(PhysicsConstraints_module_documentation,
61 "This is the Python API for the Physics Constraints"
64 PyDoc_STRVAR(gPySetGravity__doc__,
65 "setGravity(float x,float y,float z)\n"
68 PyDoc_STRVAR(gPySetDebugMode__doc__,
69 "setDebugMode(int mode)\n"
73 PyDoc_STRVAR(gPySetNumIterations__doc__,
74 "setNumIterations(int numiter)\n"
75 "This sets the number of iterations for an iterative constraint solver"
77 PyDoc_STRVAR(gPySetNumTimeSubSteps__doc__,
78 "setNumTimeSubSteps(int numsubstep)\n"
79 "This sets the number of substeps for each physics proceed. Tradeoff quality for performance."
82 PyDoc_STRVAR(gPySetDeactivationTime__doc__,
83 "setDeactivationTime(float time)\n"
84 "This sets the time after which a resting rigidbody gets deactived"
86 PyDoc_STRVAR(gPySetDeactivationLinearTreshold__doc__,
87 "setDeactivationLinearTreshold(float linearTreshold)\n"
90 PyDoc_STRVAR(gPySetDeactivationAngularTreshold__doc__,
91 "setDeactivationAngularTreshold(float angularTreshold)\n"
94 PyDoc_STRVAR(gPySetContactBreakingTreshold__doc__,
95 "setContactBreakingTreshold(float breakingTreshold)\n"
96 "Reasonable default is 0.02 (if units are meters)"
99 PyDoc_STRVAR(gPySetCcdMode__doc__,
100 "setCcdMode(int ccdMode)\n"
101 "Very experimental, not recommended"
103 PyDoc_STRVAR(gPySetSorConstant__doc__,
104 "setSorConstant(float sor)\n"
105 "Very experimental, not recommended"
107 PyDoc_STRVAR(gPySetSolverTau__doc__,
108 "setTau(float tau)\n"
109 "Very experimental, not recommended"
111 PyDoc_STRVAR(gPySetSolverDamping__doc__,
112 "setDamping(float damping)\n"
113 "Very experimental, not recommended"
115 PyDoc_STRVAR(gPySetLinearAirDamping__doc__,
116 "setLinearAirDamping(float damping)\n"
117 "Very experimental, not recommended"
119 PyDoc_STRVAR(gPySetUseEpa__doc__,
120 "setUseEpa(int epa)\n"
121 "Very experimental, not recommended"
123 PyDoc_STRVAR(gPySetSolverType__doc__,
124 "setSolverType(int solverType)\n"
125 "Very experimental, not recommended"
128 PyDoc_STRVAR(gPyCreateConstraint__doc__,
129 "createConstraint(ob1,ob2,float restLength,float restitution,float damping)\n"
132 PyDoc_STRVAR(gPyGetVehicleConstraint__doc__,
133 "getVehicleConstraint(int constraintId)\n"
136 PyDoc_STRVAR(gPyGetCharacter__doc__,
137 "getCharacter(KX_GameObject obj)\n"
140 PyDoc_STRVAR(gPyRemoveConstraint__doc__,
141 "removeConstraint(int constraintId)\n"
144 PyDoc_STRVAR(gPyGetAppliedImpulse__doc__,
145 "getAppliedImpulse(int constraintId)\n"
152 static PyObject *gPySetGravity(PyObject *self,
157 if (PyArg_ParseTuple(args,"fff",&x,&y,&z))
159 if (PHY_GetActiveEnvironment())
160 PHY_GetActiveEnvironment()->SetGravity(x,y,z);
169 static PyObject *gPySetDebugMode(PyObject *self,
174 if (PyArg_ParseTuple(args,"i",&mode))
176 if (PHY_GetActiveEnvironment())
178 PHY_GetActiveEnvironment()->SetDebugMode(mode);
192 static PyObject *gPySetNumTimeSubSteps(PyObject *self,
197 if (PyArg_ParseTuple(args,"i",&substep))
199 if (PHY_GetActiveEnvironment())
201 PHY_GetActiveEnvironment()->SetNumTimeSubSteps(substep);
211 static PyObject *gPySetNumIterations(PyObject *self,
216 if (PyArg_ParseTuple(args,"i",&iter))
218 if (PHY_GetActiveEnvironment())
220 PHY_GetActiveEnvironment()->SetNumIterations(iter);
230 static PyObject *gPySetDeactivationTime(PyObject *self,
235 if (PyArg_ParseTuple(args,"f",&deactive_time))
237 if (PHY_GetActiveEnvironment())
239 PHY_GetActiveEnvironment()->SetDeactivationTime(deactive_time);
249 static PyObject *gPySetDeactivationLinearTreshold(PyObject *self,
253 float linearDeactivationTreshold;
254 if (PyArg_ParseTuple(args,"f",&linearDeactivationTreshold))
256 if (PHY_GetActiveEnvironment())
258 PHY_GetActiveEnvironment()->SetDeactivationLinearTreshold( linearDeactivationTreshold);
268 static PyObject *gPySetDeactivationAngularTreshold(PyObject *self,
272 float angularDeactivationTreshold;
273 if (PyArg_ParseTuple(args,"f",&angularDeactivationTreshold))
275 if (PHY_GetActiveEnvironment())
277 PHY_GetActiveEnvironment()->SetDeactivationAngularTreshold( angularDeactivationTreshold);
286 static PyObject *gPySetContactBreakingTreshold(PyObject *self,
290 float contactBreakingTreshold;
291 if (PyArg_ParseTuple(args,"f",&contactBreakingTreshold))
293 if (PHY_GetActiveEnvironment())
295 PHY_GetActiveEnvironment()->SetContactBreakingTreshold( contactBreakingTreshold);
305 static PyObject *gPySetCcdMode(PyObject *self,
310 if (PyArg_ParseTuple(args,"f",&ccdMode))
312 if (PHY_GetActiveEnvironment())
314 PHY_GetActiveEnvironment()->SetCcdMode( ccdMode);
323 static PyObject *gPySetSorConstant(PyObject *self,
328 if (PyArg_ParseTuple(args,"f",&sor))
330 if (PHY_GetActiveEnvironment())
332 PHY_GetActiveEnvironment()->SetSolverSorConstant( sor);
341 static PyObject *gPySetSolverTau(PyObject *self,
346 if (PyArg_ParseTuple(args,"f",&tau))
348 if (PHY_GetActiveEnvironment())
350 PHY_GetActiveEnvironment()->SetSolverTau( tau);
360 static PyObject *gPySetSolverDamping(PyObject *self,
365 if (PyArg_ParseTuple(args,"f",&damping))
367 if (PHY_GetActiveEnvironment())
369 PHY_GetActiveEnvironment()->SetSolverDamping( damping);
378 static PyObject *gPySetLinearAirDamping(PyObject *self,
383 if (PyArg_ParseTuple(args,"f",&damping))
385 if (PHY_GetActiveEnvironment())
387 PHY_GetActiveEnvironment()->SetLinearAirDamping( damping);
397 static PyObject *gPySetUseEpa(PyObject *self,
402 if (PyArg_ParseTuple(args,"i",&epa))
404 if (PHY_GetActiveEnvironment())
406 PHY_GetActiveEnvironment()->SetUseEpa(epa);
414 static PyObject *gPySetSolverType(PyObject *self,
419 if (PyArg_ParseTuple(args,"i",&solverType))
421 if (PHY_GetActiveEnvironment())
423 PHY_GetActiveEnvironment()->SetSolverType(solverType);
434 static PyObject *gPyGetVehicleConstraint(PyObject *self,
439 __int64 constraintid;
440 if (PyArg_ParseTuple(args,"L",&constraintid))
443 if (PyArg_ParseTuple(args,"l",&constraintid))
446 if (PHY_GetActiveEnvironment())
449 PHY_IVehicle* vehicle = PHY_GetActiveEnvironment()->GetVehicleConstraint(constraintid);
452 KX_VehicleWrapper* pyWrapper = new KX_VehicleWrapper(vehicle,PHY_GetActiveEnvironment());
453 return pyWrapper->NewProxy(true);
465 static PyObject* gPyGetCharacter(PyObject* self,
472 if (!PyArg_ParseTuple(args,"O", &pyob))
475 if (!ConvertPythonToGameObject(pyob, &ob, false, "bge.constraints.getCharacter(value)"))
478 if (PHY_GetActiveEnvironment())
481 PHY_ICharacter* character= PHY_GetActiveEnvironment()->GetCharacterController(ob);
484 KX_CharacterWrapper* pyWrapper = new KX_CharacterWrapper(character);
485 return pyWrapper->NewProxy(true);
493 static PyObject *gPyCreateConstraint(PyObject *self,
497 /* FIXME - physicsid is a long being cast to a pointer, should at least use PyCapsule */
498 unsigned long long physicsid = 0, physicsid2 = 0;
499 int constrainttype = 0;
501 float pivotX = 0.0f, pivotY = 0.0f, pivotZ = 0.0f, axisX = 0.0f, axisY = 0.0f, axisZ = 0.0f;
503 static const char *kwlist[] = {"physicsid_1", "physicsid_2", "constraint_type", "pivot_x", "pivot_y", "pivot_z",
504 "axis_X", "axis_y", "axis_z", "flag", NULL};
506 if (!PyArg_ParseTupleAndKeywords(args, kwds, "KKi|ffffffi:createConstraint", (char **)kwlist,
507 &physicsid, &physicsid2, &constrainttype,
508 &pivotX, &pivotY, &pivotZ, &axisX, &axisY, &axisZ, &flag))
513 if (PHY_GetActiveEnvironment()) {
514 PHY_IPhysicsController *physctrl = (PHY_IPhysicsController*)physicsid;
515 PHY_IPhysicsController *physctrl2 = (PHY_IPhysicsController*)physicsid2;
516 if (physctrl) { //TODO:check for existence of this pointer!
517 //convert from euler angle into axis
518 const float deg2rad = 0.017453292f;
520 //we need to pass a full constraint frame, not just axis
521 //localConstraintFrameBasis
522 MT_Matrix3x3 localCFrame(MT_Vector3(deg2rad*axisX, deg2rad*axisY, deg2rad*axisZ));
523 MT_Vector3 axis0 = localCFrame.getColumn(0);
524 MT_Vector3 axis1 = localCFrame.getColumn(1);
525 MT_Vector3 axis2 = localCFrame.getColumn(2);
527 int constraintid = PHY_GetActiveEnvironment()->CreateConstraint(
528 physctrl, physctrl2, (enum PHY_ConstraintType)constrainttype, pivotX, pivotY, pivotZ,
529 (float)axis0.x(), (float)axis0.y(), (float)axis0.z(),
530 (float)axis1.x(), (float)axis1.y(), (float)axis1.z(),
531 (float)axis2.x(), (float)axis2.y(), (float)axis2.z(), flag);
533 KX_ConstraintWrapper *wrap = new KX_ConstraintWrapper(
534 (enum PHY_ConstraintType)constrainttype, constraintid, PHY_GetActiveEnvironment());
536 return wrap->NewProxy(true);
545 static PyObject *gPyGetAppliedImpulse(PyObject *self,
549 float appliedImpulse = 0.f;
552 __int64 constraintid;
553 if (PyArg_ParseTuple(args,"L",&constraintid))
556 if (PyArg_ParseTuple(args,"l",&constraintid))
559 if (PHY_GetActiveEnvironment())
561 appliedImpulse = PHY_GetActiveEnvironment()->GetAppliedImpulse(constraintid);
568 return PyFloat_FromDouble(appliedImpulse);
572 static PyObject *gPyRemoveConstraint(PyObject *self,
577 __int64 constraintid;
578 if (PyArg_ParseTuple(args,"L",&constraintid))
581 if (PyArg_ParseTuple(args,"l",&constraintid))
584 if (PHY_GetActiveEnvironment())
586 PHY_GetActiveEnvironment()->RemoveConstraint(constraintid);
596 static PyObject *gPyExportBulletFile(PyObject *, PyObject *args)
599 if (!PyArg_ParseTuple(args,"s:exportBulletFile",&filename))
602 if (PHY_GetActiveEnvironment())
604 PHY_GetActiveEnvironment()->ExportFile(filename);
609 static struct PyMethodDef physicsconstraints_methods[] = {
610 {"setGravity",(PyCFunction) gPySetGravity,
611 METH_VARARGS, (const char*)gPySetGravity__doc__},
612 {"setDebugMode",(PyCFunction) gPySetDebugMode,
613 METH_VARARGS, (const char *)gPySetDebugMode__doc__},
615 /// settings that influence quality of the rigidbody dynamics
616 {"setNumIterations",(PyCFunction) gPySetNumIterations,
617 METH_VARARGS, (const char *)gPySetNumIterations__doc__},
619 {"setNumTimeSubSteps",(PyCFunction) gPySetNumTimeSubSteps,
620 METH_VARARGS, (const char *)gPySetNumTimeSubSteps__doc__},
622 {"setDeactivationTime",(PyCFunction) gPySetDeactivationTime,
623 METH_VARARGS, (const char *)gPySetDeactivationTime__doc__},
625 {"setDeactivationLinearTreshold",(PyCFunction) gPySetDeactivationLinearTreshold,
626 METH_VARARGS, (const char *)gPySetDeactivationLinearTreshold__doc__},
627 {"setDeactivationAngularTreshold",(PyCFunction) gPySetDeactivationAngularTreshold,
628 METH_VARARGS, (const char *)gPySetDeactivationAngularTreshold__doc__},
630 {"setContactBreakingTreshold",(PyCFunction) gPySetContactBreakingTreshold,
631 METH_VARARGS, (const char *)gPySetContactBreakingTreshold__doc__},
632 {"setCcdMode",(PyCFunction) gPySetCcdMode,
633 METH_VARARGS, (const char *)gPySetCcdMode__doc__},
634 {"setSorConstant",(PyCFunction) gPySetSorConstant,
635 METH_VARARGS, (const char *)gPySetSorConstant__doc__},
636 {"setSolverTau",(PyCFunction) gPySetSolverTau,
637 METH_VARARGS, (const char *)gPySetSolverTau__doc__},
638 {"setSolverDamping",(PyCFunction) gPySetSolverDamping,
639 METH_VARARGS, (const char *)gPySetSolverDamping__doc__},
641 {"setLinearAirDamping",(PyCFunction) gPySetLinearAirDamping,
642 METH_VARARGS, (const char *)gPySetLinearAirDamping__doc__},
644 {"setUseEpa",(PyCFunction) gPySetUseEpa,
645 METH_VARARGS, (const char *)gPySetUseEpa__doc__},
646 {"setSolverType",(PyCFunction) gPySetSolverType,
647 METH_VARARGS, (const char *)gPySetSolverType__doc__},
650 {"createConstraint",(PyCFunction) gPyCreateConstraint,
651 METH_VARARGS|METH_KEYWORDS, (const char *)gPyCreateConstraint__doc__},
652 {"getVehicleConstraint",(PyCFunction) gPyGetVehicleConstraint,
653 METH_VARARGS, (const char *)gPyGetVehicleConstraint__doc__},
655 {"getCharacter",(PyCFunction) gPyGetCharacter,
656 METH_VARARGS, (const char *)gPyGetCharacter__doc__},
658 {"removeConstraint",(PyCFunction) gPyRemoveConstraint,
659 METH_VARARGS, (const char *)gPyRemoveConstraint__doc__},
660 {"getAppliedImpulse",(PyCFunction) gPyGetAppliedImpulse,
661 METH_VARARGS, (const char *)gPyGetAppliedImpulse__doc__},
663 {"exportBulletFile",(PyCFunction)gPyExportBulletFile,
664 METH_VARARGS, "export a .bullet file"},
667 { NULL, (PyCFunction) NULL, 0, NULL }
670 static struct PyModuleDef PhysicsConstraints_module_def = {
671 PyModuleDef_HEAD_INIT,
672 "PhysicsConstraints", /* m_name */
673 PhysicsConstraints_module_documentation, /* m_doc */
675 physicsconstraints_methods, /* m_methods */
682 PyMODINIT_FUNC initConstraintPythonBinding()
685 PyObject *ErrorObject;
690 m = PyModule_Create(&PhysicsConstraints_module_def);
691 PyDict_SetItemString(PySys_GetObject("modules"), PhysicsConstraints_module_def.m_name, m);
693 // Add some symbolic constants to the module
694 d = PyModule_GetDict(m);
695 ErrorObject = PyUnicode_FromString("PhysicsConstraints.error");
696 PyDict_SetItemString(d, "error", ErrorObject);
697 Py_DECREF(ErrorObject);
700 //Debug Modes constants to be used with setDebugMode() python function
701 KX_MACRO_addTypesToDict(d, DBG_NODEBUG, btIDebugDraw::DBG_NoDebug);
702 KX_MACRO_addTypesToDict(d, DBG_DRAWWIREFRAME, btIDebugDraw::DBG_DrawWireframe);
703 KX_MACRO_addTypesToDict(d, DBG_DRAWAABB, btIDebugDraw::DBG_DrawAabb);
704 KX_MACRO_addTypesToDict(d, DBG_DRAWFREATURESTEXT, btIDebugDraw::DBG_DrawFeaturesText);
705 KX_MACRO_addTypesToDict(d, DBG_DRAWCONTACTPOINTS, btIDebugDraw::DBG_DrawContactPoints);
706 KX_MACRO_addTypesToDict(d, DBG_NOHELPTEXT, btIDebugDraw::DBG_NoHelpText);
707 KX_MACRO_addTypesToDict(d, DBG_DRAWTEXT, btIDebugDraw::DBG_DrawText);
708 KX_MACRO_addTypesToDict(d, DBG_PROFILETIMINGS, btIDebugDraw::DBG_ProfileTimings);
709 KX_MACRO_addTypesToDict(d, DBG_ENABLESATCOMPARISION, btIDebugDraw::DBG_EnableSatComparison);
710 KX_MACRO_addTypesToDict(d, DBG_DISABLEBULLETLCP, btIDebugDraw::DBG_DisableBulletLCP);
711 KX_MACRO_addTypesToDict(d, DBG_ENABLECCD, btIDebugDraw::DBG_EnableCCD);
712 KX_MACRO_addTypesToDict(d, DBG_DRAWCONSTRAINTS, btIDebugDraw::DBG_DrawConstraints);
713 KX_MACRO_addTypesToDict(d, DBG_DRAWCONSTRAINTLIMITS, btIDebugDraw::DBG_DrawConstraintLimits);
714 KX_MACRO_addTypesToDict(d, DBG_FASTWIREFRAME, btIDebugDraw::DBG_FastWireframe);
715 #endif // WITH_BULLET
717 //Constraint types to be used with createConstraint() python function
718 KX_MACRO_addTypesToDict(d, POINTTOPOINT_CONSTRAINT, PHY_POINT2POINT_CONSTRAINT);
719 KX_MACRO_addTypesToDict(d, LINEHINGE_CONSTRAINT, PHY_LINEHINGE_CONSTRAINT);
720 KX_MACRO_addTypesToDict(d, ANGULAR_CONSTRAINT, PHY_ANGULAR_CONSTRAINT);
721 KX_MACRO_addTypesToDict(d, CONETWIST_CONSTRAINT, PHY_CONE_TWIST_CONSTRAINT);
722 KX_MACRO_addTypesToDict(d, VEHICLE_CONSTRAINT, PHY_VEHICLE_CONSTRAINT);
723 KX_MACRO_addTypesToDict(d, GENERIC_6DOF_CONSTRAINT, PHY_GENERIC_6DOF_CONSTRAINT);
726 if (PyErr_Occurred()) {
727 Py_FatalError("can't initialize module PhysicsConstraints");
734 static void KX_RemovePythonConstraintBinding()
739 void PHY_SetActiveEnvironment(class PHY_IPhysicsEnvironment* env)
741 g_CurrentActivePhysicsEnvironment = env;
744 PHY_IPhysicsEnvironment* PHY_GetActiveEnvironment()
746 return g_CurrentActivePhysicsEnvironment;
749 #endif // WITH_PYTHON