Index: doc/python_api/rst/bge.constraints.rst =================================================================== --- doc/python_api/rst/bge.constraints.rst (revision 59324) +++ doc/python_api/rst/bge.constraints.rst (working copy) @@ -28,6 +28,7 @@ - :class:`ANGULAR_CONSTRAINT` - :class:`CONETWIST_CONSTRAINT` - :class:`VEHICLE_CONSTRAINT` + - :class:`GENERIC_6DOF_CONSTRAINT` :type constrainttype: int @@ -63,6 +64,14 @@ :arg filename: File name :type filename: string +.. function:: getConstraint(gameobj) + + :arg gameobj: The game object with the constraint physics. + :type gameobj: :class:`bge.types.KX_GameObject` + + :return: constraint wrapper + :rtype: :class:`bge.types.KX_ConstraintWrapper` + .. function:: getAppliedImpulse(constraintId) :arg constraintId: The id of the constraint. Index: doc/python_api/rst/bge_types/bge.types.KX_ConstraintWrapper.rst =================================================================== --- doc/python_api/rst/bge_types/bge.types.KX_ConstraintWrapper.rst (revision 59324) +++ doc/python_api/rst/bge_types/bge.types.KX_ConstraintWrapper.rst (working copy) @@ -11,8 +11,153 @@ .. method:: getConstraintId(val) - Returns the contraint's ID + Returns the contraint ID - :return: the constraint's ID + :return: the constraint ID :rtype: integer + .. method:: setParam(dof, value0, value1) + + Set the contraint limits + + :arg dof: + :type dof: integer + + PHY_GENERIC_6DOF_CONSTRAINT: + param = 0..2 are constraint limits, with low/high limit value + + * 0: X axis position + * 1: Y axis position + * 2: Z axis position + + :arg value0: Set the minimum limit of the axis + :type value0: float + :arg value1: Set the maximum limit of the axis + :type value1: float + + param = 3..5 are relative constraint (Euler) angles in radians + + * 3: X axis angle + * 4: Y axis angle + * 5: Z axis angle + + :arg value0: Set the minimum limit of the axis + :type value0: float + :arg value1: Set the maximum limit of the axis + :type value1: float + + param = 6..8 are translational motors, with value0=target velocity, value1 = max motor force + + * 0: X axis position + * 1: Y axis position + * 2: Z axis position + + :arg value1: Set the linear velocity of the axis + :type value1: float Range: -10,000.00 to 10,000.00 + :arg value1: Set the maximum force limit of the axis + :type value1: float Range: -10,000.00 to 10,000.00 + + param = 9..11 are rotational motors, with value0=target velocity, value1 = max motor force + + * 0: X axis angle + * 1: Y axis angle + * 2: Z axis angle + + :arg value0: Set the linear velocity of the axis + :type value0: float Range: -10,000.00 to 10,000.00 + :arg value1: Set the maximum force limit of the axis + :type value1: float Range: -10,000.00 to 10,000.00 + + param 12..14 are for motorized springs on each of the degrees of freedom + + * 0: X axis position + * 1: Y axis position + * 2: Z axis position + + :arg value0: Set the stiffness of the spring + :type value0: float + :arg value1: Set the spring reset + :type value1: float + 1 = return to original position + 0 = don't return to original position + + param 14..17 are for motorized springs on each of the degrees of freedom + + * 0: X axis angle + * 1: Y axis angle + * 2: Z axis angle + + :arg value0: Set the stiffness of the spring + :type value0: float + :arg value1: Set the spring reset + :type value1: float + 1 = return to original position + 0 = don't return to original position + + + PHY_CONE_TWIST_CONSTRAINT: + param = 3..5 are constraint limits, high limit values + + * 3: X axis angle + * 4: Y axis angle + * 5: Z axis angle + + :arg value0: Set the minimum limit of the axis + :type value0: float + :arg value1: Set the maximum limit of the axis + :type value1: float + + + PHY_ANGULAR_CONSTRAINT or PHY_LINEHINGE_CONSTRAINT: + param = 3 is a constraint limit, with low/high limit value + + * 3: X axis angle + + :arg value0: Set the minimum limit of the axis + :type value0: float + :arg value1: Set the maximum limit of the axis + :type value1: float + + .. method:: getParam(dof) + + Get the contraint position or euler angle of a generic 6DOF constraint + + :arg dof: + :type dof: integer + PHY_GENERIC_6DOF_CONSTRAINT + param = 0..2 are linear constraint values + + * 0: X axis position + * 1: Y axis position + * 2: Z axis position + + :return: relative pivot position + :rtype: float + + param = 3..5 are relative constraint (Euler) angles in radians + + * 3: X axis angle + * 4: Y axis angle + * 5: Z axis angle + + :return: angle + :rtype: float + + .. attribute:: constraint_id + + Returns the contraint ID + + :type: integer + + .. attribute:: constraint_type + + Returns the contraint type + + :type: integer + + 1 = POINTTOPOINT_CONSTRAINT + 2 = LINEHINGE_CONSTRAINT + 3 = ANGULAR_CONSTRAINT + 4 = CONETWIST_CONSTRAINT + 11 = VEHICLE_CONSTRAINT + 12 = GENERIC_6DOF_CONSTRAINT Index: source/gameengine/Converter/BL_BlenderDataConversion.cpp =================================================================== --- source/gameengine/Converter/BL_BlenderDataConversion.cpp (revision 59324) +++ source/gameengine/Converter/BL_BlenderDataConversion.cpp (working copy) @@ -373,6 +373,110 @@ static std::map gReverseKeyTranslateTable = create_translate_table(); + +void setup_constraint4object(KX_GameObject* obj_src, KX_Scene* scene, bRigidBodyJointConstraint* dat, PHY_IPhysicsController* phy_src, PHY_IPhysicsController* phy_dest) +{ + /* we need to pass a full constraint frame, not just axis */ + MT_Vector3 scale = obj_src->NodeGetWorldScaling(); + + MT_Matrix3x3 localCFrame(MT_Vector3(dat->axX,dat->axY,dat->axZ)); + MT_Vector3 axis0 = localCFrame.getColumn(0); + MT_Vector3 axis1 = localCFrame.getColumn(1); + MT_Vector3 axis2 = localCFrame.getColumn(2); + + /* apply not only the pivot and axis values, but also take scale into count + * this is not working well, if only one or two axis are scaled, but works ok on + * homogeneous scaling */ + int constraintId = scene->GetPhysicsEnvironment()->createConstraint(phy_src, phy_dest, + (PHY_ConstraintType)dat->type, + (float)(dat->pivX*scale.x()), + (float)(dat->pivY*scale.y()), + (float)(dat->pivZ*scale.z()), + (float)(axis0.x()*scale.x()), + (float)(axis0.y()*scale.y()), + (float)(axis0.z()*scale.z()), + (float)(axis1.x()*scale.x()), + (float)(axis1.y()*scale.y()), + (float)(axis1.z()*scale.z()), + (float)(axis2.x()*scale.x()), + (float)(axis2.y()*scale.y()), + (float)(axis2.z()*scale.z()), + dat->flag); + /* PHY_POINT2POINT_CONSTRAINT=1, + * PHY_LINEHINGE_CONSTRAINT=2, + * PHY_ANGULAR_CONSTRAINT = 3, + * PHY_CONE_TWIST_CONSTRAINT = 4, + * PHY_VEHICLE_CONSTRAINT=11, + * PHY_GENERIC_6DOF_CONSTRAINT=12 */ + + if (constraintId) { + + switch(dat->type) { + case PHY_POINT2POINT_CONSTRAINT: + { + break; + } + + case PHY_GENERIC_6DOF_CONSTRAINT: + { + int dof; + int dofbit=1; + for (dof=0;dof<6;dof++) { + if (dat->flag & dofbit) { + scene->GetPhysicsEnvironment()->setConstraintParam(constraintId, dof, dat->minLimit[dof], dat->maxLimit[dof]); + } + else { + /* minLimit > maxLimit means free(disabled limit) for this degree of freedom */ + scene->GetPhysicsEnvironment()->setConstraintParam(constraintId, dof, 1 ,-1); + } + dofbit<<=1; + } + break; + } + + case PHY_CONE_TWIST_CONSTRAINT: + { + int dof; + int dofbit = 1<<3; /* bitflag use_angular_limit_x */ + for (dof=3;dof<6;dof++) { + if(dat->flag & dofbit) { + scene->GetPhysicsEnvironment()->setConstraintParam(constraintId, dof, dat->minLimit[dof], dat->maxLimit[dof]); + } + else { + /* maxLimit < 0 means free(disabled limit) for this degree of freedom */ + scene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,1,-1); + } + dofbit<<=1; + } + break; + } + + case PHY_LINEHINGE_CONSTRAINT: + { + int dof = 3; /* dof for angular x */ + int dofbit = 1<<3; /* bit flag use_angular_limit_x */ + + if (dat->flag & dofbit) { + scene->GetPhysicsEnvironment()->setConstraintParam(constraintId, dof, dat->minLimit[dof], dat->maxLimit[dof]); + } + else { + /* minLimit > maxLimit means free(disabled limit) for this degree of freedom */ + scene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,1,-1); + } + break; + } + + case PHY_ANGULAR_CONSTRAINT: + { + break; + } + } + + ConstraintData *constraint = new ConstraintData(dat->type, constraintId, scene->GetPhysicsEnvironment()); + obj_src->AddConstraintData(constraint); + } +} + static unsigned int KX_rgbaint2uint_new(unsigned int icol) { union @@ -2401,6 +2505,10 @@ // is not in a separate thread. BL_Texture::GetMaxUnits(); + /* we have to ensure that group definitions are only converted once + * push all converted group members to this set */ + set convertedlist; + if (alwaysUseExpandFraming) { frame_type = RAS_FrameSettings::e_frame_extend; aspect_width = canvas->GetWidth(); @@ -2539,6 +2647,11 @@ rendertools, converter, libloading); + + /* insert object to the constraint game object list + * so we can check later if there is a instance in the scene or + * an instance and its actual group definition */ + convertedlist.insert((KX_GameObject*)gameobj->AddRef()); // this code is copied from above except that // object from groups are never in active layer @@ -2796,96 +2909,40 @@ bConstraint *curcon; conlist = get_active_constraints2(blenderobject); - if ((gameobj->GetLayer()&activeLayerBitInfo)==0) - continue; - if (conlist) { for (curcon = (bConstraint *)conlist->first; curcon; curcon = (bConstraint *)curcon->next) { if (curcon->type==CONSTRAINT_TYPE_RIGIDBODYJOINT) { - bRigidBodyJointConstraint *dat=(bRigidBodyJointConstraint *)curcon->data; + bRigidBodyJointConstraint *dat = (bRigidBodyJointConstraint *)curcon->data; + /* to get grouped objects and instances in one active layer to work with constraints */ + if (dat->tar) + gameobj->AddConstraint(dat); + if (!dat->child && !(curcon->flag & CONSTRAINT_OFF)) { + /* prevents blender to crash, object was already converted or constraint + * is added to game object for later replication */ + set::iterator gobit; + bool skip = false; + for (gobit=convertedlist.begin(); gobit != convertedlist.end(); gobit++) { + if((*gobit)->GetName() == gameobj->GetName()) { + skip = true; + break; + } + } + + if(skip) + continue; - PHY_IPhysicsController* physctr2 = 0; - if (dat->tar) { - KX_GameObject *gotar=getGameOb(dat->tar->id.name+2,sumolist); - if (gotar && ((gotar->GetLayer()&activeLayerBitInfo)!=0) && gotar->GetPhysicsController()) - physctr2 = (PHY_IPhysicsController*) gotar->GetPhysicsController()->GetUserData(); - } - - if (gameobj->GetPhysicsController()) - { - PHY_IPhysicsController* physctrl = (PHY_IPhysicsController*) gameobj->GetPhysicsController()->GetUserData(); - //we need to pass a full constraint frame, not just axis - - //localConstraintFrameBasis - MT_Matrix3x3 localCFrame(MT_Vector3(dat->axX,dat->axY,dat->axZ)); - MT_Vector3 axis0 = localCFrame.getColumn(0); - MT_Vector3 axis1 = localCFrame.getColumn(1); - MT_Vector3 axis2 = localCFrame.getColumn(2); - - int constraintId = kxscene->GetPhysicsEnvironment()->createConstraint(physctrl,physctr2,(PHY_ConstraintType)dat->type,(float)dat->pivX, - (float)dat->pivY,(float)dat->pivZ, - (float)axis0.x(),(float)axis0.y(),(float)axis0.z(), - (float)axis1.x(),(float)axis1.y(),(float)axis1.z(), - (float)axis2.x(),(float)axis2.y(),(float)axis2.z(),dat->flag); - if (constraintId) + KX_GameObject *gotar = getGameOb(dat->tar->id.name+2,sumolist); + if (gotar && ((gotar->GetLayer()&activeLayerBitInfo) != 0) && gotar->GetPhysicsController() && + ((gameobj->GetLayer()&activeLayerBitInfo) != 0) && gameobj->GetPhysicsController()) { - //if it is a generic 6DOF constraint, set all the limits accordingly - if (dat->type == PHY_GENERIC_6DOF_CONSTRAINT) - { - int dof; - int dofbit=1; - for (dof=0;dof<6;dof++) - { - if (dat->flag & dofbit) - { - kxscene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,dat->minLimit[dof],dat->maxLimit[dof]); - } else - { - //minLimit > maxLimit means free(disabled limit) for this degree of freedom - kxscene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,1,-1); - } - dofbit<<=1; - } - } - else if (dat->type == PHY_CONE_TWIST_CONSTRAINT) - { - int dof; - int dofbit = 1<<3; // bitflag use_angular_limit_x - - for (dof=3;dof<6;dof++) - { - if (dat->flag & dofbit) - { - kxscene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,dat->minLimit[dof],dat->maxLimit[dof]); - } - else - { - //maxLimit < 0 means free(disabled limit) for this degree of freedom - kxscene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,1,-1); - } - dofbit<<=1; - } - } - else if (dat->type == PHY_LINEHINGE_CONSTRAINT) - { - int dof = 3; // dof for angular x - int dofbit = 1<<3; // bitflag use_angular_limit_x - - if (dat->flag & dofbit) - { - kxscene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof, - dat->minLimit[dof],dat->maxLimit[dof]); - } else - { - //minLimit > maxLimit means free(disabled limit) for this degree of freedom - kxscene->GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,1,-1); - } - } + PHY_IPhysicsController *physctrl = (PHY_IPhysicsController *)gameobj->GetPhysicsController()->GetUserData(); + PHY_IPhysicsController *physctr2 = (PHY_IPhysicsController *)gotar->GetPhysicsController()->GetUserData(); + setup_constraint4object(gameobj, kxscene, dat, physctrl, physctr2); } } } @@ -2894,6 +2951,12 @@ } } + /* cleanup converted set of group objects */ + set::iterator gobit; + for (gobit=convertedlist.begin(); gobit!=convertedlist.end(); gobit++) + (*gobit)->Release(); + + convertedlist.clear(); sumolist->Release(); // convert world Index: source/gameengine/Converter/BL_BlenderDataConversion.h =================================================================== --- source/gameengine/Converter/BL_BlenderDataConversion.h (revision 59324) +++ source/gameengine/Converter/BL_BlenderDataConversion.h (working copy) @@ -37,9 +37,13 @@ #include "KX_Python.h" #include "KX_PhysicsEngineEnums.h" #include "SCA_IInputDevice.h" +#include "KX_GameObject.h" +#include "PHY_IPhysicsController.h" class RAS_MeshObject* BL_ConvertMesh(struct Mesh* mesh,struct Object* lightobj,class KX_Scene* scene, class KX_BlenderSceneConverter *converter, bool libloading); +void setup_constraint4object(KX_GameObject* obj_src, KX_Scene* scene, bRigidBodyJointConstraint* dat, PHY_IPhysicsController* phy_src, PHY_IPhysicsController* phy_dest); + void BL_ConvertBlenderObjects(struct Main* maggie, class KX_Scene* kxscene, class KX_KetsjiEngine* ketsjiEngine, Index: source/gameengine/GamePlayer/ghost/CMakeLists.txt =================================================================== --- source/gameengine/GamePlayer/ghost/CMakeLists.txt (revision 59324) +++ source/gameengine/GamePlayer/ghost/CMakeLists.txt (working copy) @@ -34,6 +34,8 @@ ../../Network ../../Network/LoopBackNetwork ../../Physics/common + ../../Physics/Bullet + ../../Physics/Dummy ../../Rasterizer ../../Rasterizer/RAS_OpenGLRasterizer ../../SceneGraph Index: source/gameengine/GamePlayer/ghost/SConscript =================================================================== --- source/gameengine/GamePlayer/ghost/SConscript (revision 59324) +++ source/gameengine/GamePlayer/ghost/SConscript (working copy) @@ -64,10 +64,15 @@ '#source/gameengine/Physics/common', '#source/gameengine/Network/LoopBackNetwork', '#source/gameengine/GamePlayer/common', + '#source/gameengine/Physics/common', + '#source/gameengine/Physics/Bullet', + '#source/gameengine/Physics/Dummy', '#source/blender/misc', '#source/blender/blenloader', '#source/blender/gpu', '#extern/glew/include', + '#extern/glew/include', + '#extern/bullet2/src/', ] incs.append(env['BF_PTHREADS_INC']) Index: source/gameengine/Ketsji/KX_ConstraintWrapper.cpp =================================================================== --- source/gameengine/Ketsji/KX_ConstraintWrapper.cpp (revision 59324) +++ source/gameengine/Ketsji/KX_ConstraintWrapper.cpp (working copy) @@ -114,13 +114,20 @@ PyAttributeDef KX_ConstraintWrapper::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("constraint_id", KX_ConstraintWrapper, pyattr_get_constraintId), + KX_PYATTRIBUTE_RO_FUNCTION("constraint_type", KX_ConstraintWrapper, pyattr_get_constraintType), { NULL } //Sentinel }; PyObject *KX_ConstraintWrapper::pyattr_get_constraintId(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_ConstraintWrapper* self = static_cast(self_v); - return self->PyGetConstraintId(); + return PyLong_FromLong(self->m_constraintId); } +PyObject *KX_ConstraintWrapper::pyattr_get_constraintType(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_ConstraintWrapper* self = static_cast(self_v); + return PyLong_FromLong(self->m_constraintType); +} + #endif // WITH_PYTHON Index: source/gameengine/Ketsji/KX_ConstraintWrapper.h =================================================================== --- source/gameengine/Ketsji/KX_ConstraintWrapper.h (revision 59324) +++ source/gameengine/Ketsji/KX_ConstraintWrapper.h (working copy) @@ -49,6 +49,7 @@ KX_PYMETHOD(KX_ConstraintWrapper,GetParam); static PyObject *pyattr_get_constraintId(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_constraintType(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); #endif private: Index: source/gameengine/Ketsji/KX_GameObject.cpp =================================================================== --- source/gameengine/Ketsji/KX_GameObject.cpp (revision 59324) +++ source/gameengine/Ketsji/KX_GameObject.cpp (working copy) @@ -281,6 +281,30 @@ m_pDupliGroupObject = obj; } +void KX_GameObject::AddConstraint(bRigidBodyJointConstraint *cons) { + m_constraints.push_back(cons); +} + +std::vector KX_GameObject::GetConstraints() { + return m_constraints; +} + +void KX_GameObject::ClearConstraints() { + m_constraints.clear(); +} + +void KX_GameObject::AddConstraintData(ConstraintData *constData) { + m_constraintsData.push_back(constData); +} + +std::vector KX_GameObject::GetConstraintsData() { + return m_constraintsData; +} + +void KX_GameObject::ClearConstraintsData() { + m_constraintsData.clear(); +} + KX_GameObject* KX_GameObject::GetParent() { KX_GameObject* result = NULL; Index: source/gameengine/Ketsji/KX_GameObject.h =================================================================== --- source/gameengine/Ketsji/KX_GameObject.h (revision 59324) +++ source/gameengine/Ketsji/KX_GameObject.h (working copy) @@ -50,6 +50,7 @@ #include "KX_Scene.h" #include "KX_KetsjiEngine.h" /* for m_anim_framerate */ #include "KX_IPhysicsController.h" /* for suspend/resume */ +#include "DNA_constraint_types.h" /* for constraint replication */ #include "DNA_object_types.h" #include "SCA_LogicManager.h" /* for ConvertPythonToGameObject to search object names */ @@ -74,6 +75,14 @@ void KX_GameObject_Mathutils_Callback_Init(void); #endif +typedef struct ConstraintData { + int m_constraintType; + int m_constraintId; + PHY_IPhysicsEnvironment *m_physenv; + ConstraintData(int type, int id, PHY_IPhysicsEnvironment *env) : + m_constraintType(type), m_constraintId(id), m_physenv(env) {} +} ConstraintData; + /** * KX_GameObject is the main class for dynamic objects. */ @@ -116,6 +125,8 @@ SG_Node* m_pSGNode; MT_CmMatrix4x4 m_OpenGL_4x4Matrix; + std::vector m_constraints; + std::vector m_constraintsData; KX_ObstacleSimulation* m_pObstacleSimulation; @@ -190,6 +201,18 @@ void UpdateBlenderObjectMatrix(Object* blendobj=NULL); + /* used for constraint replication for group instances + * the list of constraints is filled during data conversion */ + void AddConstraint(bRigidBodyJointConstraint *cons); + std::vector GetConstraints(); + void ClearConstraints(); + + /* used for constraint deletion for group instances + * also used to store the values for the python constraint wrapper*/ + void AddConstraintData(ConstraintData *constData); + std::vector GetConstraintsData(); + void ClearConstraintsData(); + /** * Get a pointer to the game object that is the parent of * this object. Or NULL if there is no parent. The returned Index: source/gameengine/Ketsji/KX_PyConstraintBinding.cpp =================================================================== --- source/gameengine/Ketsji/KX_PyConstraintBinding.cpp (revision 59324) +++ source/gameengine/Ketsji/KX_PyConstraintBinding.cpp (working copy) @@ -82,6 +82,7 @@ static char gPyCreateConstraint__doc__[] = "createConstraint(ob1,ob2,float restLength,float restitution,float damping)"; +static char gPyGetConstraints__doc__[] = "getConstraints(KX_GameObject obj)"; static char gPyGetVehicleConstraint__doc__[] = "getVehicleConstraint(int constraintId)"; static char gPyGetCharacter__doc__[] = "getCharacter(KX_GameObject obj)"; static char gPyRemoveConstraint__doc__[] = "removeConstraint(int constraintId)"; @@ -549,8 +550,36 @@ } +static PyObject* gPyGetConstraints(PyObject* self, + PyObject* args, + PyObject* kwds) +{ + PyObject* pyob; + KX_GameObject *ob; + if (!PyArg_ParseTuple(args,"O", &pyob)) + return NULL; + if (!ConvertPythonToGameObject(pyob, &ob, false, "bge.constraints.getConstraints(value)")) + return NULL; + + if (PHY_GetActiveEnvironment()) { + int elemets = ob->GetConstraintsData().size(); + + if (elemets > 0) { + PyObject *pyWrapperList = PyList_New(elemets); + for (int i=0; i < elemets; i++) { + ConstraintData *tmp = ob->GetConstraintsData()[i]; + KX_ConstraintWrapper *wrapper = new KX_ConstraintWrapper((enum PHY_ConstraintType)tmp->m_constraintType, tmp->m_constraintId, tmp->m_physenv); + PyList_SET_ITEM(pyWrapperList, i, wrapper->NewProxy(true)); + } + return pyWrapperList; + } + } + Py_RETURN_NONE; +} + + static PyObject *gPyGetAppliedImpulse(PyObject *self, PyObject *args, PyObject *kwds) @@ -658,6 +687,8 @@ {"createConstraint",(PyCFunction) gPyCreateConstraint, METH_VARARGS, (const char *)gPyCreateConstraint__doc__}, + {"getConstraints",(PyCFunction) gPyGetConstraints, + METH_VARARGS, (const char *)gPyGetConstraints__doc__}, {"getVehicleConstraint",(PyCFunction) gPyGetVehicleConstraint, METH_VARARGS, (const char *)gPyGetVehicleConstraint__doc__}, @@ -740,6 +771,7 @@ KX_MACRO_addTypesToDict(d, ANGULAR_CONSTRAINT, PHY_ANGULAR_CONSTRAINT); KX_MACRO_addTypesToDict(d, CONETWIST_CONSTRAINT, PHY_CONE_TWIST_CONSTRAINT); KX_MACRO_addTypesToDict(d, VEHICLE_CONSTRAINT, PHY_VEHICLE_CONSTRAINT); + KX_MACRO_addTypesToDict(d, GENERIC_6DOF_CONSTRAINT, PHY_GENERIC_6DOF_CONSTRAINT); // Check for errors if (PyErr_Occurred()) { Index: source/gameengine/Ketsji/KX_Scene.cpp =================================================================== --- source/gameengine/Ketsji/KX_Scene.cpp (revision 59324) +++ source/gameengine/Ketsji/KX_Scene.cpp (working copy) @@ -89,6 +89,7 @@ #include "BL_ModifierDeformer.h" #include "BL_ShapeDeformer.h" #include "BL_DeformableGameObject.h" +#include "BL_BlenderDataConversion.h" #include "KX_ObstacleSimulation.h" #ifdef WITH_BULLET @@ -681,6 +682,59 @@ newobj->ResetState(); } +void KX_Scene::ReplicateConstraints(KX_GameObject* replica) +{ + if (replica->GetConstraints().size() > 0) { + /* make sure to return, because createConstraint() would crash */ + if (!replica->GetPhysicsController()) { + return; + } + + replica->ClearConstraintsData(); + + vector constraints = replica->GetConstraints(); + vector::iterator consit; + + /* object could have some constraints, iterate over all of theme to ensure + * that every constraint is recreated */ + for (consit = constraints.begin(); consit != constraints.end(); ++consit) { + /* try to find the constraint targets in the list of group objects */ + bRigidBodyJointConstraint* dat = (*consit); + vector::iterator memit; + for (memit = m_logicHierarchicalGameObjects.begin(); + memit != m_logicHierarchicalGameObjects.end(); ++memit) + { + KX_GameObject *member = (*memit); + /* if the group member is the actual target for the constraint */ + if (dat->tar->id.name+2 == member->GetName() && member->GetPhysicsController()) { + PHY_IPhysicsController *physctr_repl = (PHY_IPhysicsController *) replica->GetPhysicsController()->GetUserData(); + PHY_IPhysicsController *physctr_memb = (PHY_IPhysicsController *) member->GetPhysicsController()->GetUserData(); + setup_constraint4object(replica, this, dat, physctr_repl, physctr_memb); + } + } + } + } +} + + +void KX_Scene::RemoveConstraints(CValue* replica) +{ + KX_GameObject* newobj = (KX_GameObject*) replica; + + if (newobj->GetConstraintsData().size() > 0) { + if (m_physicsEnvironment) { + vector constList = newobj->GetConstraintsData(); + for (vector::iterator constID = constList.begin(); + constID != constList.end(); ++constID) + { + m_physicsEnvironment->removeConstraint((*constID)->m_constraintId); + delete (*constID); + } + newobj->ClearConstraintsData(); + } + } +} + void KX_Scene::DupliGroupRecurse(CValue* obj, int level) { KX_GameObject* groupobj = (KX_GameObject*) obj; @@ -835,6 +889,13 @@ duplilist.push_back((*git)); } + /* now replicate all constraints */ + for (git = m_logicHierarchicalGameObjects.begin(); !(git == m_logicHierarchicalGameObjects.end()); ++git) + { + ReplicateConstraints((*git)); + (*git)->ClearConstraints(); + } + for (git = duplilist.begin(); !(git == duplilist.end()); ++git) { DupliGroupRecurse((*git), level+1); @@ -977,15 +1038,15 @@ void KX_Scene::DelayedRemoveObject(class CValue* gameobj) { - //KX_GameObject* newobj = (KX_GameObject*) gameobj; + /* the constraints must be removed before the game object is removed */ + RemoveConstraints(gameobj); + if (!m_euthanasyobjects->SearchValue(gameobj)) { m_euthanasyobjects->Add(gameobj->AddRef()); - } + } } - - int KX_Scene::NewRemoveObject(class CValue* gameobj) { int ret; Index: source/gameengine/Ketsji/KX_Scene.h =================================================================== --- source/gameengine/Ketsji/KX_Scene.h (revision 59324) +++ source/gameengine/Ketsji/KX_Scene.h (working copy) @@ -333,6 +333,7 @@ void RemoveNodeDestructObject(SG_IObject* node, CValue* gameobj); void RemoveObject(CValue* gameobj); + void RemoveDupliGroup(CValue* gameobj); void DelayedRemoveObject(CValue* gameobj); int NewRemoveObject(CValue* gameobj); @@ -536,6 +537,8 @@ */ void ReplicateLogic(class KX_GameObject* newobj); + void ReplicateConstraints(class KX_GameObject* gameobj); + void RemoveConstraints(CValue* gameobj); static SG_Callbacks m_callbacks; const STR_String& GetName(); Index: source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp =================================================================== --- source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp (revision 59324) +++ source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp (working copy) @@ -2042,7 +2042,7 @@ case 12: case 13: case 14: case 15: case 16: case 17: { - //param 13-17 are for motorized springs on each of the degrees of freedom + //param 12-17 are for motorized springs on each of the degrees of freedom btGeneric6DofSpringConstraint* genCons = (btGeneric6DofSpringConstraint*)typedConstraint; int springIndex = param-12; if (value0!=0.f)