Index: source/gameengine/Converter/BL_BlenderDataConversion.cpp =================================================================== --- source/gameengine/Converter/BL_BlenderDataConversion.cpp (revision 55981) +++ source/gameengine/Converter/BL_BlenderDataConversion.cpp (working copy) @@ -372,6 +372,28 @@ static std::map gReverseKeyTranslateTable = create_translate_table(); +// deklaration, needed for add_constraint2object +ListBase *get_active_constraints2(Object *ob); + +// adds all constraints to the gameobject, so it can found them after +// replcation +static void add_constraints2object(Object* blenderobject, KX_GameObject* gameobj) +{ + ListBase *conlist; + bConstraint *curcon; + conlist = get_active_constraints2(blenderobject); + + if (conlist) { + for (curcon = (bConstraint *)conlist->first; curcon; curcon=(bConstraint *)curcon->next) { + if (curcon->type==CONSTRAINT_TYPE_RIGIDBODYJOINT) { + bRigidBodyJointConstraint *dat = (bRigidBodyJointConstraint *)curcon->data; + if (!dat->child && dat->tar) + gameobj->AddConstraint(dat); + } + } + } +} + static unsigned int KX_rgbaint2uint_new(unsigned int icol) { union @@ -2390,6 +2412,10 @@ set allblobj; // all objects converted set groupobj; // objects from groups (never in active layer) + // we have to ensure that group definitions are only converted once + // push all converted group members to this set + set convertedlist; + // This is bad, but we use this to make sure the first time this is called // is not in a separate thread. BL_Texture::GetMaxUnits(); @@ -2532,7 +2558,12 @@ rendertools, converter, libloading); - + + // insert object to the constraint gameobject 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 bool isInActiveLayer = false; @@ -2789,9 +2820,6 @@ 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) { @@ -2800,6 +2828,22 @@ if (!dat->child && !(curcon->flag & CONSTRAINT_OFF)) { + // experimentell, to get grouped objects and instaces in one active layer + // to work with constraints + add_constraints2object(blenderobject, gameobj); + + set::iterator gobit; + bool skip = false; + for (gobit=convertedlist.begin(); gobit!=convertedlist.end(); gobit++) { + if((*gobit)->GetName() == gameobj->GetName()) + skip = true; + } + + // prevents blender to crash, object was already + // converted or constraint is added to gameobject for later replication + if(skip) + continue; + PHY_IPhysicsController* physctr2 = 0; if (dat->tar) @@ -2887,6 +2931,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/Ketsji/KX_GameObject.h =================================================================== --- source/gameengine/Ketsji/KX_GameObject.h (revision 55981) +++ 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" /*constraint replication*/ #include "DNA_object_types.h" #include "SCA_LogicManager.h" /* for ConvertPythonToGameObject to search object names */ #define KX_OB_DYNAMIC 1 @@ -127,7 +128,9 @@ BL_ActionManager* m_actionManager; BL_ActionManager* GetActionManager(); - + + std::vector m_constraints; + public: bool m_isDeformable; @@ -191,6 +194,29 @@ 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 + ) { + m_constraints.push_back(cons); + } + + std::vector + GetConstraints( + ) { + return m_constraints; + } + + void + ClearConstraints( + ) { + m_constraints.clear(); + } + /** * 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_Scene.cpp =================================================================== --- source/gameengine/Ketsji/KX_Scene.cpp (revision 55981) +++ source/gameengine/Ketsji/KX_Scene.cpp (working copy) @@ -666,6 +666,152 @@ newobj->ResetState(); } +void KX_Scene::ReplicateConstraints(KX_GameObject* replica) +{ + if(replica->GetConstraints().size() > 0) + { + PHY_IPhysicsController* physctr_repl; + if(replica->GetPhysicsController()) + { + physctr_repl = (PHY_IPhysicsController*) replica->GetPhysicsController()->GetUserData(); + } + else + { + // make sure to return, because createConstraint() would crash + return; + } + + std::vector constraints = replica->GetConstraints(); + std::vector::iterator consit; + int number = 0; // just for debugging + + // 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 finde the constraint targes in the list of group objects + bRigidBodyJointConstraint* dat = (*consit); + vector::iterator memit; + for (memit = m_logicHierarchicalGameObjects.begin();!(memit==m_logicHierarchicalGameObjects.end());++memit) + { + // if the group member is the actual target to + // the constraint + KX_GameObject* member = (*memit); + if(dat->tar->id.name+2 == member->GetName()) + { + PHY_IPhysicsController* physctr_memb = NULL; + if(member->GetPhysicsController()) + physctr_memb = (PHY_IPhysicsController*) member->GetPhysicsController()->GetUserData(); + + MT_Vector3 scale = replica->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 + // homogenus scaling + int constraintId = GetPhysicsEnvironment()->createConstraint(physctr_repl, physctr_memb, + (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 + + // copied from Blender Data conversion, sorry for that, need to put it in + // a separate function + 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) + { + GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,dat->minLimit[dof],dat->maxLimit[dof]); + } else + { + //minLimit > maxLimit means free(disabled limit) for this degree of freedom + 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) + { + GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,dat->minLimit[dof],dat->maxLimit[dof]); + } + else + { + //maxLimit < 0 means free(disabled limit) for this degree of freedom + GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,1,-1); + } + dofbit<<=1; + } + + } break; + + case PHY_LINEHINGE_CONSTRAINT : + { + int dof = 3; // dof for angular x + int dofbit = 1<<3; // bitflag use_angular_limit_x + + if (dat->flag & dofbit) + { + GetPhysicsEnvironment()->setConstraintParam(constraintId,dof, dat->minLimit[dof],dat->maxLimit[dof]); + } else + { + //minLimit > maxLimit means free(disabled limit) for this degree of freedom + GetPhysicsEnvironment()->setConstraintParam(constraintId,dof,1,-1); + } + + } break; + + case PHY_ANGULAR_CONSTRAINT : + { + + } break; + + } + } + } + } + } +} + void KX_Scene::DupliGroupRecurse(CValue* obj, int level) { KX_GameObject* groupobj = (KX_GameObject*) obj; @@ -820,6 +966,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); Index: source/gameengine/Ketsji/KX_Scene.h =================================================================== --- source/gameengine/Ketsji/KX_Scene.h (revision 55981) +++ source/gameengine/Ketsji/KX_Scene.h (working copy) @@ -536,6 +536,7 @@ */ void ReplicateLogic(class KX_GameObject* newobj); + void ReplicateConstraints(class KX_GameObject* gameobj); static SG_Callbacks m_callbacks; const STR_String& GetName();