diff options
Diffstat (limited to 'source/gameengine/Converter')
24 files changed, 2125 insertions, 61 deletions
diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index ca4290703e1..6f3036d8e09 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -432,6 +432,8 @@ bool BL_ActionActuator::Update(double curtime, bool frame) return keepgoing; }; +#ifndef DISABLE_PYTHON + /* ------------------------------------------------------------------------- */ /* Python functions */ /* ------------------------------------------------------------------------- */ @@ -526,12 +528,11 @@ KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel, mat.setValue((const float *)matrix); BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); - obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ if (!m_userpose) { if(!m_pose) obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ - game_copy_pose(&m_userpose, m_pose); + game_copy_pose(&m_userpose, m_pose, 0); } // pchan= verify_pose_channel(m_userpose, string); // adds the channel if its not there. pchan= get_pose_channel(m_userpose, string); // adds the channel if its not there. @@ -554,7 +555,7 @@ KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel, if (!m_userpose) { if(!m_pose) obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ - game_copy_pose(&m_userpose, m_pose); + game_copy_pose(&m_userpose, m_pose, 0); } // pchan= verify_pose_channel(m_userpose, string); pchan= get_pose_channel(m_userpose, string); // adds the channel if its not there. @@ -572,7 +573,6 @@ KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel, return NULL; } - pchan->flag |= POSE_ROT|POSE_LOC|POSE_SIZE; Py_RETURN_NONE; } @@ -677,3 +677,5 @@ PyObject* BL_ActionActuator::pyattr_get_channel_names(void *self_v, const KX_PYA return ret; } + +#endif // DISABLE_PYTHON diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h index a6b4c4a055d..3f3cd5f496d 100644 --- a/source/gameengine/Converter/BL_ActionActuator.h +++ b/source/gameengine/Converter/BL_ActionActuator.h @@ -50,7 +50,7 @@ public: short priority, short end_reset, float stride) - : SCA_IActuator(gameobj), + : SCA_IActuator(gameobj, KX_ACT_ACTION), m_lastpos(0, 0, 0), m_blendframe(0), @@ -84,6 +84,8 @@ public: bAction* GetAction() { return m_action; } void SetAction(bAction* act) { m_action= act; } +#ifndef DISABLE_PYTHON + KX_PYMETHOD_O(BL_ActionActuator,GetChannel); KX_PYMETHOD_DOC(BL_ActionActuator,setChannel); @@ -129,6 +131,7 @@ public: return 1; } } +#endif // DISABLE_PYTHON protected: diff --git a/source/gameengine/Converter/BL_ArmatureActuator.cpp b/source/gameengine/Converter/BL_ArmatureActuator.cpp new file mode 100644 index 00000000000..a018f0f938d --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureActuator.cpp @@ -0,0 +1,267 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "DNA_action_types.h" +#include "DNA_constraint_types.h" +#include "DNA_actuator_types.h" +#include "BKE_constraint.h" +#include "BLI_arithb.h" +#include "BL_ArmatureActuator.h" +#include "BL_ArmatureObject.h" + +/** + * This class is the conversion of the Pose channel constraint. + * It makes a link between the pose constraint and the KX scene. + * The main purpose is to give access to the constraint target + * to link it to a game object. + * It also allows to activate/deactivate constraints during the game. + * Later it will also be possible to create constraint on the fly + */ + +BL_ArmatureActuator::BL_ArmatureActuator(SCA_IObject* obj, + int type, + const char *posechannel, + const char *constraintname, + KX_GameObject* targetobj, + KX_GameObject* subtargetobj, + float weight) : + SCA_IActuator(obj, KX_ACT_ARMATURE), + m_constraint(NULL), + m_gametarget(targetobj), + m_gamesubtarget(subtargetobj), + m_posechannel(posechannel), + m_constraintname(constraintname), + m_weight(weight), + m_type(type) +{ + if (m_gametarget) + m_gametarget->RegisterActuator(this); + if (m_gamesubtarget) + m_gamesubtarget->RegisterActuator(this); + FindConstraint(); +} + +BL_ArmatureActuator::~BL_ArmatureActuator() +{ + if (m_gametarget) + m_gametarget->UnregisterActuator(this); + if (m_gamesubtarget) + m_gamesubtarget->UnregisterActuator(this); +} + +void BL_ArmatureActuator::ProcessReplica() +{ + // the replica is tracking the same object => register it (this may be changed in Relnk()) + if (m_gametarget) + m_gametarget->RegisterActuator(this); + if (m_gamesubtarget) + m_gamesubtarget->UnregisterActuator(this); + SCA_IActuator::ProcessReplica(); +} + +void BL_ArmatureActuator::ReParent(SCA_IObject* parent) +{ + SCA_IActuator::ReParent(parent); + // must remap the constraint + FindConstraint(); +} + +bool BL_ArmatureActuator::UnlinkObject(SCA_IObject* clientobj) +{ + bool res=false; + if (clientobj == m_gametarget) + { + // this object is being deleted, we cannot continue to track it. + m_gametarget = NULL; + res = true; + } + if (clientobj == m_gamesubtarget) + { + // this object is being deleted, we cannot continue to track it. + m_gamesubtarget = NULL; + res = true; + } + return res; +} + +void BL_ArmatureActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + void **h_obj = (*obj_map)[m_gametarget]; + if (h_obj) { + if (m_gametarget) + m_gametarget->UnregisterActuator(this); + m_gametarget = (KX_GameObject*)(*h_obj); + m_gametarget->RegisterActuator(this); + } + h_obj = (*obj_map)[m_gamesubtarget]; + if (h_obj) { + if (m_gamesubtarget) + m_gamesubtarget->UnregisterActuator(this); + m_gamesubtarget = (KX_GameObject*)(*h_obj); + m_gamesubtarget->RegisterActuator(this); + } +} + +void BL_ArmatureActuator::FindConstraint() +{ + m_constraint = NULL; + + if (m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { + BL_ArmatureObject* armobj = (BL_ArmatureObject*)m_gameobj; + m_constraint = armobj->GetConstraint(m_posechannel, m_constraintname); + } +} + +bool BL_ArmatureActuator::Update(double curtime, bool frame) +{ + // the only role of this actuator is to ensure that the armature pose will be evaluated + bool result = false; + bool bNegativeEvent = IsNegativeEvent(); + RemoveAllEvents(); + + if (!bNegativeEvent) { + BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); + switch (m_type) { + case ACT_ARM_RUN: + result = true; + obj->SetActiveAction(NULL, 0, curtime); + break; + case ACT_ARM_ENABLE: + if (m_constraint) + m_constraint->ClrConstraintFlag(CONSTRAINT_OFF); + break; + case ACT_ARM_DISABLE: + if (m_constraint) + m_constraint->SetConstraintFlag(CONSTRAINT_OFF); + break; + case ACT_ARM_SETTARGET: + if (m_constraint) { + m_constraint->SetTarget(m_gametarget); + m_constraint->SetSubtarget(m_gamesubtarget); + } + break; + case ACT_ARM_SETWEIGHT: + if (m_constraint) + m_constraint->SetWeight(m_weight); + break; + } + } + return result; +} + +#ifndef DISABLE_PYTHON + +/* ------------------------------------------------------------------------- */ +/* Python Integration Hooks */ +/* ------------------------------------------------------------------------- */ + +PyTypeObject BL_ArmatureActuator::Type = { +#if (PY_VERSION_HEX >= 0x02060000) + PyVarObject_HEAD_INIT(NULL, 0) +#else + /* python 2.5 and below */ + PyObject_HEAD_INIT( NULL ) /* required py macro */ + 0, /* ob_size */ +#endif + "BL_ArmatureActuator", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &SCA_IActuator::Type, + 0,0,0,0,0,0, + py_base_new +}; + + +PyMethodDef BL_ArmatureActuator::Methods[] = { + {NULL,NULL} //Sentinel +}; + +PyAttributeDef BL_ArmatureActuator::Attributes[] = { + KX_PYATTRIBUTE_RO_FUNCTION("constraint", BL_ArmatureActuator, pyattr_get_constraint), + KX_PYATTRIBUTE_RW_FUNCTION("target", BL_ArmatureActuator, pyattr_get_object, pyattr_set_object), + KX_PYATTRIBUTE_RW_FUNCTION("subtarget", BL_ArmatureActuator, pyattr_get_object, pyattr_set_object), + KX_PYATTRIBUTE_FLOAT_RW("weight",0.0f,1.0f,BL_ArmatureActuator,m_weight), + KX_PYATTRIBUTE_INT_RW("type",0,ACT_ARM_MAXTYPE,false,BL_ArmatureActuator,m_type), + { NULL } //Sentinel +}; + +PyObject* BL_ArmatureActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ArmatureActuator* actuator = static_cast<BL_ArmatureActuator*>(self); + KX_GameObject *target = (!strcmp(attrdef->m_name, "target")) ? actuator->m_gametarget : actuator->m_gamesubtarget; + if (!target) + Py_RETURN_NONE; + else + return target->GetProxy(); +} + +int BL_ArmatureActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_ArmatureActuator* actuator = static_cast<BL_ArmatureActuator*>(self); + KX_GameObject* &target = (!strcmp(attrdef->m_name, "target")) ? actuator->m_gametarget : actuator->m_gamesubtarget; + KX_GameObject *gameobj; + + if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: BL_ArmatureActuator")) + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + + if (target != NULL) + target->UnregisterActuator(actuator); + + target = gameobj; + + if (target) + target->RegisterActuator(actuator); + + return PY_SET_ATTR_SUCCESS; +} + +PyObject* BL_ArmatureActuator::pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ArmatureActuator* actuator = static_cast<BL_ArmatureActuator*>(self); + BL_ArmatureConstraint* constraint = actuator->m_constraint; + if (!constraint) + Py_RETURN_NONE; + else + return constraint->GetProxy(); +} + +#endif // DISABLE_PYTHON + diff --git a/source/gameengine/Converter/BL_ArmatureActuator.h b/source/gameengine/Converter/BL_ArmatureActuator.h new file mode 100644 index 00000000000..e7e12bc2e4e --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureActuator.h @@ -0,0 +1,93 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef BL_ARMATUREACTUATOR +#define BL_ARMATUREACTUATOR + +#include "SCA_IActuator.h" +#include "BL_ArmatureConstraint.h" + +/** + * This class is the conversion of the Pose channel constraint. + * It makes a link between the pose constraint and the KX scene. + * The main purpose is to give access to the constraint target + * to link it to a game object. + * It also allows to activate/deactivate constraints during the game. + * Later it will also be possible to create constraint on the fly + */ + +class BL_ArmatureActuator : public SCA_IActuator +{ + Py_Header; +public: + BL_ArmatureActuator(SCA_IObject* gameobj, + int type, + const char *posechannel, + const char *constraintname, + KX_GameObject* targetobj, + KX_GameObject* subtargetobj, + float weight); + + virtual ~BL_ArmatureActuator(); + + virtual CValue* GetReplica() { + BL_ArmatureActuator* replica = new BL_ArmatureActuator(*this); + replica->ProcessReplica(); + return replica; + }; + virtual void ProcessReplica(); + virtual bool UnlinkObject(SCA_IObject* clientobj); + virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map); + virtual bool Update(double curtime, bool frame); + virtual void ReParent(SCA_IObject* parent); + +#ifndef DISABLE_PYTHON + + /* These are used to get and set m_target */ + static PyObject* pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + +#endif // DISABLE_PYTHON + +private: + // identify the constraint that this actuator controls + void FindConstraint(); + + BL_ArmatureConstraint* m_constraint; + KX_GameObject* m_gametarget; + KX_GameObject* m_gamesubtarget; + STR_String m_posechannel; + STR_String m_constraintname; + float m_weight; + int m_type; +}; + +#endif //BL_ARMATUREACTUATOR + + diff --git a/source/gameengine/Converter/BL_ArmatureChannel.cpp b/source/gameengine/Converter/BL_ArmatureChannel.cpp new file mode 100644 index 00000000000..9a9161b080f --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureChannel.cpp @@ -0,0 +1,469 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "DNA_armature_types.h" +#include "BL_ArmatureChannel.h" +#include "BL_ArmatureObject.h" +#include "BL_ArmatureConstraint.h" +#include "BLI_arithb.h" +#include "BLI_string.h" + +#ifndef DISABLE_PYTHON + +PyTypeObject BL_ArmatureChannel::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "BL_ArmatureChannel", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &CValue::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyObject* BL_ArmatureChannel::py_repr(void) +{ + return PyUnicode_FromString(m_posechannel->name); +} + +PyObject *BL_ArmatureChannel::GetProxy() +{ + return GetProxyPlus_Ext(this, &Type, m_posechannel); +} + +PyObject *BL_ArmatureChannel::NewProxy(bool py_owns) +{ + return NewProxyPlus_Ext(this, &Type, m_posechannel, py_owns); +} + +#endif // DISABLE_PYTHON + +BL_ArmatureChannel::BL_ArmatureChannel( + BL_ArmatureObject *armature, + bPoseChannel *posechannel) + : PyObjectPlus(), m_posechannel(posechannel), m_armature(armature) +{ +} + +BL_ArmatureChannel::~BL_ArmatureChannel() +{ +} + +#ifndef DISABLE_PYTHON + +// PYTHON + +PyMethodDef BL_ArmatureChannel::Methods[] = { + {NULL,NULL} //Sentinel +}; + +// order of definition of attributes, must match Attributes[] array +#define BCA_BONE 0 +#define BCA_PARENT 1 + +PyAttributeDef BL_ArmatureChannel::Attributes[] = { + // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr + KX_PYATTRIBUTE_RO_FUNCTION("bone",BL_ArmatureChannel,py_attr_getattr), + KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureChannel,py_attr_getattr), + + { NULL } //Sentinel +}; + +/* attributes directly taken from bPoseChannel */ +PyAttributeDef BL_ArmatureChannel::AttributesPtr[] = { + KX_PYATTRIBUTE_CHAR_RO("name",bPoseChannel,name), + KX_PYATTRIBUTE_FLAG_RO("has_ik",bPoseChannel,flag, POSE_CHAIN), + KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_x",bPoseChannel,ikflag, BONE_IK_NO_XDOF), + KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_y",bPoseChannel,ikflag, BONE_IK_NO_YDOF), + KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_z",bPoseChannel,ikflag, BONE_IK_NO_ZDOF), + KX_PYATTRIBUTE_FLAG_RO("ik_limit_x",bPoseChannel,ikflag, BONE_IK_XLIMIT), + KX_PYATTRIBUTE_FLAG_RO("ik_limit_y",bPoseChannel,ikflag, BONE_IK_YLIMIT), + KX_PYATTRIBUTE_FLAG_RO("ik_limit_z",bPoseChannel,ikflag, BONE_IK_ZLIMIT), + KX_PYATTRIBUTE_FLAG_RO("ik_rot_control",bPoseChannel,ikflag, BONE_IK_ROTCTL), + KX_PYATTRIBUTE_FLAG_RO("ik_lin_control",bPoseChannel,ikflag, BONE_IK_LINCTL), + KX_PYATTRIBUTE_FLOAT_VECTOR_RW("location",-FLT_MAX,FLT_MAX,bPoseChannel,loc,3), + KX_PYATTRIBUTE_FLOAT_VECTOR_RW("scale",-FLT_MAX,FLT_MAX,bPoseChannel,size,3), + KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotation_quaternion",-1.0f,1.0f,bPoseChannel,quat,4), + KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotaion_euler",-10.f,10.f,bPoseChannel,eul,3), + KX_PYATTRIBUTE_SHORT_RW("rotation_mode",0,ROT_MODE_MAX-1,false,bPoseChannel,rotmode), + KX_PYATTRIBUTE_FLOAT_MATRIX_RO("channel_matrix",bPoseChannel,chan_mat,4), + KX_PYATTRIBUTE_FLOAT_MATRIX_RO("pose_matrix",bPoseChannel,pose_mat,4), + KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_head",bPoseChannel,pose_head,3), + KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_tail",bPoseChannel,pose_tail,3), + KX_PYATTRIBUTE_FLOAT_RO("ik_min_x",bPoseChannel,limitmin[0]), + KX_PYATTRIBUTE_FLOAT_RO("ik_max_x",bPoseChannel,limitmax[0]), + KX_PYATTRIBUTE_FLOAT_RO("ik_min_y",bPoseChannel,limitmin[1]), + KX_PYATTRIBUTE_FLOAT_RO("ik_max_y",bPoseChannel,limitmax[1]), + KX_PYATTRIBUTE_FLOAT_RO("ik_min_z",bPoseChannel,limitmin[2]), + KX_PYATTRIBUTE_FLOAT_RO("ik_max_z",bPoseChannel,limitmax[2]), + KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_x",bPoseChannel,stiffness[0]), + KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_y",bPoseChannel,stiffness[1]), + KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_z",bPoseChannel,stiffness[2]), + KX_PYATTRIBUTE_FLOAT_RO("ik_stretch",bPoseChannel,ikstretch), + KX_PYATTRIBUTE_FLOAT_RW("ik_rot_weight",0,1.0f,bPoseChannel,ikrotweight), + KX_PYATTRIBUTE_FLOAT_RW("ik_lin_weight",0,1.0f,bPoseChannel,iklinweight), + KX_PYATTRIBUTE_RW_FUNCTION("joint_rotation",BL_ArmatureChannel,py_attr_get_joint_rotation,py_attr_set_joint_rotation), + { NULL } //Sentinel +}; + +PyObject* BL_ArmatureChannel::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v); + bPoseChannel* channel = self->m_posechannel; + int attr_order = attrdef-Attributes; + + if (!channel) { + PyErr_SetString(PyExc_AttributeError, "channel is NULL"); + return NULL; + } + + switch (attr_order) { + case BCA_BONE: + // bones are standalone proxy + return NewProxyPlus_Ext(NULL,&BL_ArmatureBone::Type,channel->bone,false); + case BCA_PARENT: + { + BL_ArmatureChannel* parent = self->m_armature->GetChannel(channel->parent); + if (parent) + return parent->GetProxy(); + else + Py_RETURN_NONE; + } + } + PyErr_SetString(PyExc_AttributeError, "channel unknown attribute"); + return NULL; +} + +int BL_ArmatureChannel::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v); + bPoseChannel* channel = self->m_posechannel; + int attr_order = attrdef-Attributes; + + int ival; + double dval; + char* sval; + KX_GameObject *oval; + + if (!channel) { + PyErr_SetString(PyExc_AttributeError, "channel is NULL"); + return PY_SET_ATTR_FAIL; + } + + switch (attr_order) { + default: + break; + } + + PyErr_SetString(PyExc_AttributeError, "channel unknown attribute"); + return PY_SET_ATTR_FAIL; +} + +PyObject* BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v); + bPoseChannel* pchan = self->m_posechannel; + // decompose the pose matrix in euler rotation + float rest_mat[3][3]; + float pose_mat[3][3]; + float joint_mat[3][3]; + float joints[3]; + float norm; + double sa, ca; + // get rotation in armature space + Mat3CpyMat4(pose_mat, pchan->pose_mat); + Mat3Ortho(pose_mat); + if (pchan->parent) { + // bone has a parent, compute the rest pose of the bone taking actual pose of parent + Mat3IsMat3MulMat4(rest_mat, pchan->bone->bone_mat, pchan->parent->pose_mat); + Mat3Ortho(rest_mat); + } else { + // otherwise, the bone matrix in armature space is the rest pose + Mat3CpyMat4(rest_mat, pchan->bone->arm_mat); + } + // remove the rest pose to get the joint movement + Mat3Transp(rest_mat); + Mat3MulMat3(joint_mat, rest_mat, pose_mat); + joints[0] = joints[1] = joints[2] = 0.f; + // returns a 3 element list that gives corresponding joint + int flag = 0; + if (!(pchan->ikflag & BONE_IK_NO_XDOF)) + flag |= 1; + if (!(pchan->ikflag & BONE_IK_NO_YDOF)) + flag |= 2; + if (!(pchan->ikflag & BONE_IK_NO_ZDOF)) + flag |= 4; + switch (flag) { + case 0: // fixed joint + break; + case 1: // X only + Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ); + joints[1] = joints[2] = 0.f; + break; + case 2: // Y only + Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ); + joints[0] = joints[2] = 0.f; + break; + case 3: // X+Y + Mat3ToEulO(joint_mat, joints, EULER_ORDER_ZYX); + joints[2] = 0.f; + break; + case 4: // Z only + Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ); + joints[0] = joints[1] = 0.f; + break; + case 5: // X+Z + // decompose this as an equivalent rotation vector in X/Z plane + joints[0] = joint_mat[1][2]; + joints[2] = -joint_mat[1][0]; + norm = Normalize(joints); + if (norm < FLT_EPSILON) { + norm = (joint_mat[1][1] < 0.f) ? M_PI : 0.f; + } else { + norm = acos(joint_mat[1][1]); + } + VecMulf(joints, norm); + break; + case 6: // Y+Z + Mat3ToEulO(joint_mat, joints, EULER_ORDER_XYZ); + joints[0] = 0.f; + break; + case 7: // X+Y+Z + // equivalent axis + joints[0] = (joint_mat[1][2]-joint_mat[2][1])*0.5f; + joints[1] = (joint_mat[2][0]-joint_mat[0][2])*0.5f; + joints[2] = (joint_mat[0][1]-joint_mat[1][0])*0.5f; + sa = VecLength(joints); + ca = (joint_mat[0][0]+joint_mat[1][1]+joint_mat[1][1]-1.0f)*0.5f; + if (sa > FLT_EPSILON) { + norm = atan2(sa,ca)/sa; + } else { + if (ca < 0.0) { + norm = M_PI; + VecMulf(joints,0.f); + if (joint_mat[0][0] > 0.f) { + joints[0] = 1.0f; + } else if (joint_mat[1][1] > 0.f) { + joints[1] = 1.0f; + } else { + joints[2] = 1.0f; + } + } else { + norm = 0.0; + } + } + VecMulf(joints,norm); + break; + } + return newVectorObject(joints, 3, Py_NEW, NULL); +} + +int BL_ArmatureChannel::py_attr_set_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v); + bPoseChannel* pchan = self->m_posechannel; + PyObject *item; + float joints[3]; + float quat[4]; + + if (!PySequence_Check(value) || PySequence_Size(value) != 3) { + PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats"); + return PY_SET_ATTR_FAIL; + } + for (int i=0; i<3; i++) { + item = PySequence_GetItem(value, i); /* new ref */ + joints[i] = PyFloat_AsDouble(item); + Py_DECREF(item); + if (joints[i] == -1.0f && PyErr_Occurred()) { + PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats"); + return PY_SET_ATTR_FAIL; + } + } + + int flag = 0; + if (!(pchan->ikflag & BONE_IK_NO_XDOF)) + flag |= 1; + if (!(pchan->ikflag & BONE_IK_NO_YDOF)) + flag |= 2; + if (!(pchan->ikflag & BONE_IK_NO_ZDOF)) + flag |= 4; + QuatOne(quat); + switch (flag) { + case 0: // fixed joint + break; + case 1: // X only + joints[1] = joints[2] = 0.f; + EulOToQuat(joints, EULER_ORDER_XYZ, quat); + break; + case 2: // Y only + joints[0] = joints[2] = 0.f; + EulOToQuat(joints, EULER_ORDER_XYZ, quat); + break; + case 3: // X+Y + joints[2] = 0.f; + EulOToQuat(joints, EULER_ORDER_ZYX, quat); + break; + case 4: // Z only + joints[0] = joints[1] = 0.f; + EulOToQuat(joints, EULER_ORDER_XYZ, quat); + break; + case 5: // X+Z + // X and Z are components of an equivalent rotation axis + joints[1] = 0; + VecRotToQuat(joints, VecLength(joints), quat); + break; + case 6: // Y+Z + joints[0] = 0.f; + EulOToQuat(joints, EULER_ORDER_XYZ, quat); + break; + case 7: // X+Y+Z + // equivalent axis + VecRotToQuat(joints, VecLength(joints), quat); + break; + } + if (pchan->rotmode > 0) { + QuatToEulO(quat, joints, pchan->rotmode); + VecCopyf(pchan->eul, joints); + } else + QuatCopy(pchan->quat, quat); + return PY_SET_ATTR_SUCCESS; +} + +// ************************* +// BL_ArmatureBone +// +// Access to Bone structure +PyTypeObject BL_ArmatureBone::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "BL_ArmatureBone", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_bone_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &CValue::Type, + 0,0,0,0,0,0, + py_base_new +}; + +// not used since this class is never instantiated +PyObject *BL_ArmatureBone::GetProxy() +{ + return NULL; +} +PyObject *BL_ArmatureBone::NewProxy(bool py_owns) +{ + return NULL; +} + +PyObject *BL_ArmatureBone::py_bone_repr(PyObject *self) +{ + Bone* bone = static_cast<Bone*>BGE_PROXY_PTR(self); + return PyUnicode_FromString(bone->name); +} + +PyMethodDef BL_ArmatureBone::Methods[] = { + {NULL,NULL} //Sentinel +}; + +/* no attributes on C++ class since it is never instantiated */ +PyAttributeDef BL_ArmatureBone::Attributes[] = { + { NULL } //Sentinel +}; + +// attributes that work on proxy ptr (points to a Bone structure) +PyAttributeDef BL_ArmatureBone::AttributesPtr[] = { + KX_PYATTRIBUTE_CHAR_RO("name",Bone,name), + KX_PYATTRIBUTE_FLAG_RO("connected",Bone,flag, BONE_CONNECTED), + KX_PYATTRIBUTE_FLAG_RO("hinge",Bone,flag, BONE_HINGE), + KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("inherit_scale",Bone,flag, BONE_NO_SCALE), + KX_PYATTRIBUTE_SHORT_RO("bbone_segments",Bone,segments), + KX_PYATTRIBUTE_FLOAT_RO("roll",Bone,roll), + KX_PYATTRIBUTE_FLOAT_VECTOR_RO("head",Bone,head,3), + KX_PYATTRIBUTE_FLOAT_VECTOR_RO("tail",Bone,tail,3), + KX_PYATTRIBUTE_FLOAT_RO("length",Bone,length), + KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_head",Bone,arm_head,3), + KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_tail",Bone,arm_tail,3), + KX_PYATTRIBUTE_FLOAT_MATRIX_RO("arm_mat",Bone,arm_mat,4), + KX_PYATTRIBUTE_FLOAT_MATRIX_RO("bone_mat",Bone,bone_mat,4), + KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureBone,py_bone_get_parent), + KX_PYATTRIBUTE_RO_FUNCTION("children",BL_ArmatureBone,py_bone_get_parent), + { NULL } //Sentinel +}; + +PyObject *BL_ArmatureBone::py_bone_get_parent(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + Bone* bone = reinterpret_cast<Bone*>BGE_PROXY_PTR(self); + if (bone->parent) { + // create a proxy unconnected to any GE object + return NewProxyPlus_Ext(NULL,&Type,bone->parent,false); + } + Py_RETURN_NONE; +} + +PyObject *BL_ArmatureBone::py_bone_get_children(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + Bone* bone = reinterpret_cast<Bone*>BGE_PROXY_PTR(self); + Bone* child; + int count = 0; + for (child=(Bone*)bone->childbase.first; child; child=(Bone*)child->next) + count++; + + PyObject* childrenlist = PyList_New(count); + + for (count = 0, child=(Bone*)bone->childbase.first; child; child=(Bone*)child->next, ++count) + PyList_SET_ITEM(childrenlist,count,NewProxyPlus_Ext(NULL,&Type,child,false)); + + return childrenlist; +} + +#endif // DISABLE_PYTHON diff --git a/source/gameengine/Converter/BL_ArmatureChannel.h b/source/gameengine/Converter/BL_ArmatureChannel.h new file mode 100644 index 00000000000..64b03835d83 --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureChannel.h @@ -0,0 +1,95 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BL_ARMATURECHANNEL +#define __BL_ARMATURECHANNEL + +#include "DNA_action_types.h" +#include "GEN_HashedPtr.h" +#include "GEN_Map.h" +#include "PyObjectPlus.h" + +class SCA_IObject; +class KX_GameObject; +class BL_ArmatureObject; +struct bConstraint; +struct bPoseChannel; +struct Object; +struct bPose; + +class BL_ArmatureChannel : public PyObjectPlus +{ + // use Py_HeaderPtr since we use generic pointer in proxy + Py_HeaderPtr; + +private: + friend class BL_ArmatureObject; + struct bPoseChannel* m_posechannel; + BL_ArmatureObject* m_armature; + +public: + BL_ArmatureChannel(class BL_ArmatureObject *armature, + struct bPoseChannel *posechannel); + virtual ~BL_ArmatureChannel(); + +#ifndef DISABLE_PYTHON + // Python access + virtual PyObject* py_repr(void); + + static PyObject* py_attr_getattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int py_attr_setattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* py_attr_get_joint_rotation(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int py_attr_set_joint_rotation(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); +#endif // DISABLE_PYTHON +}; + +/* this is a factory class to access bBone data field in the GE. + It's not supposed to be instantiated, we only need it for the Attributes and Method array. + The actual proxy object will be manually created using NewProxyPtr */ +class BL_ArmatureBone : public PyObjectPlus +{ + // use Py_HeaderPtr since we use generic pointer in proxy + Py_HeaderPtr; +private: + // make constructor private to make sure no one tries to instantiate this class + BL_ArmatureBone() {} + virtual ~BL_ArmatureBone() {} + +public: + +#ifndef DISABLE_PYTHON + static PyObject *py_bone_repr(PyObject *self); + static PyObject *py_bone_get_parent(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static PyObject *py_bone_get_children(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); +#endif + +}; + + +#endif //__BL_ARMATURECHANNEL + diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.cpp b/source/gameengine/Converter/BL_ArmatureConstraint.cpp new file mode 100644 index 00000000000..42581b63ec4 --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureConstraint.cpp @@ -0,0 +1,454 @@ +/** + * $Id$ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "DNA_constraint_types.h" +#include "DNA_action_types.h" +#include "BL_ArmatureConstraint.h" +#include "BL_ArmatureObject.h" +#include "BLI_arithb.h" +#include "BLI_string.h" + +#ifndef DISABLE_PYTHON + +PyTypeObject BL_ArmatureConstraint::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "BL_ArmatureConstraint", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0,0,0,0,0,0,0,0,0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &CValue::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyObject* BL_ArmatureConstraint::py_repr(void) +{ + return PyUnicode_FromString(m_name); +} + +#endif // DISABLE_PYTHON + +BL_ArmatureConstraint::BL_ArmatureConstraint( + BL_ArmatureObject *armature, + bPoseChannel *posechannel, + bConstraint *constraint, + KX_GameObject* target, + KX_GameObject* subtarget) + : PyObjectPlus(), m_armature(armature), m_constraint(constraint), m_posechannel(posechannel) +{ + m_target = target; + m_blendtarget = (target) ? target->GetBlenderObject() : NULL; + m_subtarget = subtarget; + m_blendsubtarget = (subtarget) ? subtarget->GetBlenderObject() : NULL; + m_pose = m_subpose = NULL; + if (m_blendtarget) { + Mat4CpyMat4(m_blendmat, m_blendtarget->obmat); + if (m_blendtarget->type == OB_ARMATURE) + m_pose = m_blendtarget->pose; + } + if (m_blendsubtarget) { + Mat4CpyMat4(m_blendsubmat, m_blendsubtarget->obmat); + if (m_blendsubtarget->type == OB_ARMATURE) + m_subpose = m_blendsubtarget->pose; + } + if (m_target) + m_target->RegisterObject(m_armature); + if (m_subtarget) + m_subtarget->RegisterObject(m_armature); + BLI_snprintf(m_name, sizeof(m_name), "%s:%s", m_posechannel->name, m_constraint->name); +} + +BL_ArmatureConstraint::~BL_ArmatureConstraint() +{ + if (m_target) + m_target->UnregisterObject(m_armature); + if (m_subtarget) + m_subtarget->UnregisterObject(m_armature); +} + +BL_ArmatureConstraint* BL_ArmatureConstraint::GetReplica() const +{ + BL_ArmatureConstraint* replica = new BL_ArmatureConstraint(*this); + replica->ProcessReplica(); + return replica; +} + +void BL_ArmatureConstraint::ReParent(BL_ArmatureObject* armature) +{ + m_armature = armature; + if (m_target) + m_target->RegisterObject(armature); + if (m_subtarget) + m_subtarget->RegisterObject(armature); + // find the corresponding constraint in the new armature object + if (m_constraint) { + bPose* newpose = armature->GetOrigPose(); + char* constraint = m_constraint->name; + char* posechannel = m_posechannel->name; + bPoseChannel* pchan; + bConstraint* pcon; + m_constraint = NULL; + m_posechannel = NULL; + // and locate the constraint + for (pchan = (bPoseChannel*)newpose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) { + if (!strcmp(pchan->name, posechannel)) { + // now locate the constraint + for (pcon = (bConstraint*)pchan->constraints.first; pcon; pcon=(bConstraint*)pcon->next) { + if (!strcmp(pcon->name, constraint)) { + m_constraint = pcon; + m_posechannel = pchan; + break; + } + } + break; + } + } + } +} + +void BL_ArmatureConstraint::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + void **h_obj = (*obj_map)[m_target]; + if (h_obj) { + m_target->UnregisterObject(m_armature); + m_target = (KX_GameObject*)(*h_obj); + m_target->RegisterObject(m_armature); + } + h_obj = (*obj_map)[m_subtarget]; + if (h_obj) { + m_subtarget->UnregisterObject(m_armature); + m_subtarget = (KX_GameObject*)(*h_obj); + m_subtarget->RegisterObject(m_armature); + } +} + +bool BL_ArmatureConstraint::UnlinkObject(SCA_IObject* clientobj) +{ + bool res=false; + if (clientobj == m_target) { + m_target = NULL; + res = true; + } + if (clientobj == m_subtarget) { + m_subtarget = NULL; + res = true; + } + return res; +} + +void BL_ArmatureConstraint::UpdateTarget() +{ + if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) { + if (m_blendtarget) { + // external target, must be updated + m_target->UpdateBlenderObjectMatrix(m_blendtarget); + if (m_pose && m_target->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) + // update the pose in case a bone is specified in the constraint target + m_blendtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose(); + } + if (m_blendsubtarget && m_subtarget) { + m_subtarget->UpdateBlenderObjectMatrix(m_blendsubtarget); + if (m_subpose && m_subtarget->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) + m_blendsubtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose(); + } + } +} + +void BL_ArmatureConstraint::RestoreTarget() +{ + if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) { + if (m_blendtarget) { + Mat4CpyMat4(m_blendtarget->obmat, m_blendmat); + if (m_pose) + m_blendtarget->pose = m_pose; + } + if (m_blendsubtarget && m_subtarget) { + Mat4CpyMat4(m_blendsubtarget->obmat, m_blendsubmat); + if (m_subpose) + m_blendsubtarget->pose = m_subpose; + } + } +} + +bool BL_ArmatureConstraint::Match(const char* posechannel, const char* constraint) +{ + return (!strcmp(m_posechannel->name, posechannel) && !strcmp(m_constraint->name, constraint)); +} + +void BL_ArmatureConstraint::SetTarget(KX_GameObject* target) +{ + if (m_blendtarget) { + if (target != m_target) { + m_target->UnregisterObject(m_armature); + m_target = target; + if (m_target) + m_target->RegisterObject(m_armature); + } + } + +} + +void BL_ArmatureConstraint::SetSubtarget(KX_GameObject* subtarget) +{ + if (m_blendsubtarget) { + if (subtarget != m_subtarget) { + m_subtarget->UnregisterObject(m_armature); + m_subtarget = subtarget; + if (m_subtarget) + m_subtarget->RegisterObject(m_armature); + } + } + +} + +#ifndef DISABLE_PYTHON + +// PYTHON + +PyMethodDef BL_ArmatureConstraint::Methods[] = { + {NULL,NULL} //Sentinel +}; + +// order of definition of attributes, must match Attributes[] array +#define BCA_TYPE 0 +#define BCA_NAME 1 +#define BCA_ENFORCE 2 +#define BCA_HEADTAIL 3 +#define BCA_LINERROR 4 +#define BCA_ROTERROR 5 +#define BCA_TARGET 6 +#define BCA_SUBTARGET 7 +#define BCA_ACTIVE 8 +#define BCA_IKWEIGHT 9 +#define BCA_IKTYPE 10 +#define BCA_IKFLAG 11 +#define BCA_IKDIST 12 +#define BCA_IKMODE 13 + +PyAttributeDef BL_ArmatureConstraint::Attributes[] = { + // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr + KX_PYATTRIBUTE_RO_FUNCTION("type",BL_ArmatureConstraint,py_attr_getattr), + KX_PYATTRIBUTE_RO_FUNCTION("name",BL_ArmatureConstraint,py_attr_getattr), + KX_PYATTRIBUTE_RW_FUNCTION("enforce",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RW_FUNCTION("headtail",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RO_FUNCTION("lin_error",BL_ArmatureConstraint,py_attr_getattr), + KX_PYATTRIBUTE_RO_FUNCTION("rot_error",BL_ArmatureConstraint,py_attr_getattr), + KX_PYATTRIBUTE_RW_FUNCTION("target",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RW_FUNCTION("subtarget",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RW_FUNCTION("active",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RW_FUNCTION("ik_weight",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RO_FUNCTION("ik_type",BL_ArmatureConstraint,py_attr_getattr), + KX_PYATTRIBUTE_RO_FUNCTION("ik_flag",BL_ArmatureConstraint,py_attr_getattr), + KX_PYATTRIBUTE_RW_FUNCTION("ik_dist",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + KX_PYATTRIBUTE_RW_FUNCTION("ik_mode",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), + + { NULL } //Sentinel +}; + + +PyObject* BL_ArmatureConstraint::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ArmatureConstraint* self= static_cast<BL_ArmatureConstraint*>(self_v); + bConstraint* constraint = self->m_constraint; + bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL; + int attr_order = attrdef-Attributes; + + if (!constraint) { + PyErr_SetString(PyExc_AttributeError, "constraint is NULL"); + return NULL; + } + + switch (attr_order) { + case BCA_TYPE: + return PyLong_FromLong(constraint->type); + case BCA_NAME: + return PyUnicode_FromString(constraint->name); + case BCA_ENFORCE: + return PyFloat_FromDouble(constraint->enforce); + case BCA_HEADTAIL: + return PyFloat_FromDouble(constraint->headtail); + case BCA_LINERROR: + return PyFloat_FromDouble(constraint->lin_error); + case BCA_ROTERROR: + return PyFloat_FromDouble(constraint->rot_error); + case BCA_TARGET: + if (!self->m_target) + Py_RETURN_NONE; + else + return self->m_target->GetProxy(); + case BCA_SUBTARGET: + if (!self->m_subtarget) + Py_RETURN_NONE; + else + return self->m_subtarget->GetProxy(); + case BCA_ACTIVE: + return PyBool_FromLong(constraint->flag & CONSTRAINT_OFF); + case BCA_IKWEIGHT: + case BCA_IKTYPE: + case BCA_IKFLAG: + case BCA_IKDIST: + case BCA_IKMODE: + if (!ikconstraint) { + PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type"); + return NULL; + } + switch (attr_order) { + case BCA_IKWEIGHT: + return PyFloat_FromDouble((ikconstraint)?ikconstraint->weight:0.0); + case BCA_IKTYPE: + return PyLong_FromLong(ikconstraint->type); + case BCA_IKFLAG: + return PyLong_FromLong(ikconstraint->flag); + case BCA_IKDIST: + return PyFloat_FromDouble(ikconstraint->dist); + case BCA_IKMODE: + return PyLong_FromLong(ikconstraint->mode); + } + // should not come here + break; + } + PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute"); + return NULL; +} + +int BL_ArmatureConstraint::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_ArmatureConstraint* self= static_cast<BL_ArmatureConstraint*>(self_v); + bConstraint* constraint = self->m_constraint; + bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL; + int attr_order = attrdef-Attributes; + int ival; + double dval; + char* sval; + KX_GameObject *oval; + + if (!constraint) { + PyErr_SetString(PyExc_AttributeError, "constraint is NULL"); + return PY_SET_ATTR_FAIL; + } + + switch (attr_order) { + case BCA_ENFORCE: + dval = PyFloat_AsDouble(value); + if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "constraint.enforce = float: BL_ArmatureConstraint, expected a float between 0 and 1"); + return PY_SET_ATTR_FAIL; + } + constraint->enforce = dval; + return PY_SET_ATTR_SUCCESS; + + case BCA_HEADTAIL: + dval = PyFloat_AsDouble(value); + if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "constraint.headtail = float: BL_ArmatureConstraint, expected a float between 0 and 1"); + return PY_SET_ATTR_FAIL; + } + constraint->headtail = dval; + return PY_SET_ATTR_SUCCESS; + + case BCA_TARGET: + if (!ConvertPythonToGameObject(value, &oval, true, "constraint.target = value: BL_ArmatureConstraint")) + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + self->SetTarget(oval); + return PY_SET_ATTR_SUCCESS; + + case BCA_SUBTARGET: + if (!ConvertPythonToGameObject(value, &oval, true, "constraint.subtarget = value: BL_ArmatureConstraint")) + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + self->SetSubtarget(oval); + return PY_SET_ATTR_SUCCESS; + + case BCA_ACTIVE: + ival = PyObject_IsTrue( value ); + if (ival == -1) { + PyErr_SetString(PyExc_AttributeError, "constraint.active = bool: BL_ArmatureConstraint, expected True or False"); + return PY_SET_ATTR_FAIL; + } + self->m_constraint->flag = (self->m_constraint->flag & ~CONSTRAINT_OFF) | ((ival)?0:CONSTRAINT_OFF); + return PY_SET_ATTR_SUCCESS; + + case BCA_IKWEIGHT: + case BCA_IKDIST: + case BCA_IKMODE: + if (!ikconstraint) { + PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type"); + return PY_SET_ATTR_FAIL; + } + switch (attr_order) { + case BCA_IKWEIGHT: + dval = PyFloat_AsDouble(value); + if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "constraint.weight = float: BL_ArmatureConstraint, expected a float between 0 and 1"); + return PY_SET_ATTR_FAIL; + } + ikconstraint->weight = dval; + return PY_SET_ATTR_SUCCESS; + + case BCA_IKDIST: + dval = PyFloat_AsDouble(value); + if (dval < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "constraint.ik_dist = float: BL_ArmatureConstraint, expected a positive float"); + return PY_SET_ATTR_FAIL; + } + ikconstraint->dist = dval; + return PY_SET_ATTR_SUCCESS; + + case BCA_IKMODE: + ival = PyLong_AsLong(value); + if (ival < 0) { + PyErr_SetString(PyExc_AttributeError, "constraint.ik_mode = integer: BL_ArmatureConstraint, expected a positive integer"); + return PY_SET_ATTR_FAIL; + } + ikconstraint->mode = ival; + return PY_SET_ATTR_SUCCESS; + } + // should not come here + break; + + } + + PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute"); + return PY_SET_ATTR_FAIL; +} + +#endif // DISABLE_PYTHON diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.h b/source/gameengine/Converter/BL_ArmatureConstraint.h new file mode 100644 index 00000000000..2a202dfe62e --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureConstraint.h @@ -0,0 +1,118 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BL_ARMATURECONSTRAINT +#define __BL_ARMATURECONSTRAINT + +#include "DNA_constraint_types.h" +#include "GEN_HashedPtr.h" +#include "GEN_Map.h" +#include "PyObjectPlus.h" + +class SCA_IObject; +class KX_GameObject; +class BL_ArmatureObject; +struct bConstraint; +struct bPoseChannel; +struct Object; +struct bPose; + +/** + * SG_DList : element of controlled constraint list + * head = BL_ArmatureObject::m_controlledConstraints + * SG_QList : not used + */ +class BL_ArmatureConstraint : public PyObjectPlus +{ + Py_Header; + +private: + struct bConstraint* m_constraint; + struct bPoseChannel* m_posechannel; + class BL_ArmatureObject* m_armature; + char m_name[64]; + KX_GameObject* m_target; + KX_GameObject* m_subtarget; + struct Object* m_blendtarget; + struct Object* m_blendsubtarget; + float m_blendmat[4][4]; + float m_blendsubmat[4][4]; + struct bPose* m_pose; + struct bPose* m_subpose; + +public: + BL_ArmatureConstraint(class BL_ArmatureObject *armature, + struct bPoseChannel *posechannel, + struct bConstraint *constraint, + KX_GameObject* target, + KX_GameObject* subtarget); + virtual ~BL_ArmatureConstraint(); + + BL_ArmatureConstraint* GetReplica() const; + void ReParent(BL_ArmatureObject* armature); + void Relink(GEN_Map<GEN_HashedPtr, void*> *map); + bool UnlinkObject(SCA_IObject* clientobj); + + void UpdateTarget(); + void RestoreTarget(); + + bool Match(const char* posechannel, const char* constraint); + const char* GetName() { return m_name; } + + void SetConstraintFlag(int flag) + { + if (m_constraint) + m_constraint->flag |= flag; + } + void ClrConstraintFlag(int flag) + { + if (m_constraint) + m_constraint->flag &= ~flag; + } + void SetWeight(float weight) + { + if (m_constraint && m_constraint->type == CONSTRAINT_TYPE_KINEMATIC && m_constraint->data) { + bKinematicConstraint* con = (bKinematicConstraint*)m_constraint->data; + con->weight = weight; + } + } + void SetTarget(KX_GameObject* target); + void SetSubtarget(KX_GameObject* subtarget); + +#ifndef DISABLE_PYTHON + + // Python access + virtual PyObject* py_repr(void); + + static PyObject* py_attr_getattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int py_attr_setattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); +#endif // DISABLE_PYTHON +}; + +#endif //__BL_ARMATURECONSTRAINT + diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index cfd90813a16..a6066adc03e 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -29,9 +29,15 @@ #include "BL_ArmatureObject.h" #include "BL_ActionActuator.h" +#include "KX_BlenderSceneConverter.h" #include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_arithb.h" +#include "BIK_api.h" #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_utildefines.h" +#include "BKE_constraint.h" #include "GEN_Map.h" #include "GEN_HashedPtr.h" #include "MEM_guardedalloc.h" @@ -39,6 +45,11 @@ #include "DNA_armature_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_nla_types.h" +#include "DNA_constraint_types.h" +#include "KX_PythonSeq.h" +#include "KX_PythonInit.h" +#include "KX_KetsjiEngine.h" #include "MT_Matrix4x4.h" @@ -46,6 +57,153 @@ #include <config.h> #endif +/** + * Move here pose function for game engine so that we can mix with GE objects + * Principle is as follow: + * Use Blender structures so that where_is_pose can be used unchanged + * Copy the constraint so that they can be enabled/disabled/added/removed at runtime + * Don't copy the constraints for the pose used by the Action actuator, it does not need them. + * Scan the constraint structures so that the KX equivalent of target objects are identified and + * stored in separate list. + * When it is about to evaluate the pose, set the KX object position in the obmat of the corresponding + * Blender objects and restore after the evaluation. + */ +void game_copy_pose(bPose **dst, bPose *src, int copy_constraint) +{ + bPose *out; + bPoseChannel *pchan, *outpchan; + GHash *ghash; + + /* the game engine copies the current armature pose and then swaps + * the object pose pointer. this makes it possible to change poses + * without affecting the original blender data. */ + + if (!src) { + *dst=NULL; + return; + } + else if (*dst==src) { + printf("copy_pose source and target are the same\n"); + *dst=NULL; + return; + } + + out= (bPose*)MEM_dupallocN(src); + out->agroups.first= out->agroups.last= NULL; + out->ikdata = NULL; + out->ikparam = MEM_dupallocN(out->ikparam); + out->flag |= POSE_GAME_ENGINE; + BLI_duplicatelist(&out->chanbase, &src->chanbase); + + /* remap pointers */ + ghash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp); + + pchan= (bPoseChannel*)src->chanbase.first; + outpchan= (bPoseChannel*)out->chanbase.first; + for (; pchan; pchan=pchan->next, outpchan=outpchan->next) + BLI_ghash_insert(ghash, pchan, outpchan); + + for (pchan=(bPoseChannel*)out->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) { + pchan->parent= (bPoseChannel*)BLI_ghash_lookup(ghash, pchan->parent); + pchan->child= (bPoseChannel*)BLI_ghash_lookup(ghash, pchan->child); + pchan->path= NULL; + + if (copy_constraint) { + ListBase listb; + // copy all constraint for backward compatibility + copy_constraints(&listb, &pchan->constraints); // copy_constraints NULLs listb + pchan->constraints= listb; + } else { + pchan->constraints.first = NULL; + pchan->constraints.last = NULL; + } + } + + BLI_ghash_free(ghash, NULL, NULL); + + *dst=out; +} + + + +/* Only allowed for Poses with identical channels */ +void game_blend_poses(bPose *dst, bPose *src, float srcweight/*, short mode*/) +{ + short mode= ACTSTRIPMODE_BLEND; + + bPoseChannel *dchan; + const bPoseChannel *schan; + bConstraint *dcon, *scon; + float dstweight; + int i; + + switch (mode){ + case ACTSTRIPMODE_BLEND: + dstweight = 1.0F - srcweight; + break; + case ACTSTRIPMODE_ADD: + dstweight = 1.0F; + break; + default : + dstweight = 1.0F; + } + + schan= (bPoseChannel*)src->chanbase.first; + for (dchan = (bPoseChannel*)dst->chanbase.first; dchan; dchan=(bPoseChannel*)dchan->next, schan= (bPoseChannel*)schan->next){ + // always blend on all channels since we don't know which one has been set + /* quat interpolation done separate */ + if (schan->rotmode == ROT_MODE_QUAT) { + float dquat[4], squat[4]; + + QUATCOPY(dquat, dchan->quat); + QUATCOPY(squat, schan->quat); + if (mode==ACTSTRIPMODE_BLEND) + QuatInterpol(dchan->quat, dquat, squat, srcweight); + else { + QuatMulFac(squat, srcweight); + QuatMul(dchan->quat, dquat, squat); + } + + NormalQuat(dchan->quat); + } + + for (i=0; i<3; i++) { + /* blending for loc and scale are pretty self-explanatory... */ + dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight); + dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight); + + /* euler-rotation interpolation done here instead... */ + // FIXME: are these results decent? + if (schan->rotmode) + dchan->eul[i] = (dchan->eul[i]*dstweight) + (schan->eul[i]*srcweight); + } + for(dcon= (bConstraint*)dchan->constraints.first, scon= (bConstraint*)schan->constraints.first; dcon && scon; dcon= (bConstraint*)dcon->next, scon= (bConstraint*)scon->next) { + /* no 'add' option for constraint blending */ + dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight; + } + } + + /* this pose is now in src time */ + dst->ctime= src->ctime; +} + +void game_free_pose(bPose *pose) +{ + if (pose) { + /* free pose-channels and constraints */ + free_pose_channels(pose); + + /* free IK solver state */ + BIK_clear_data(pose); + + /* free IK solver param */ + if (pose->ikparam) + MEM_freeN(pose->ikparam); + + MEM_freeN(pose); + } +} + BL_ArmatureObject::BL_ArmatureObject( void* sgReplicationInfo, SG_Callbacks callbacks, @@ -53,12 +211,17 @@ BL_ArmatureObject::BL_ArmatureObject( Scene *scene) : KX_GameObject(sgReplicationInfo,callbacks), + m_controlledConstraints(), + m_poseChannels(), m_objArma(armature), m_framePose(NULL), m_scene(scene), // maybe remove later. needed for where_is_pose m_lastframe(0.0), + m_timestep(0.040), m_activeAct(NULL), m_activePriority(999), + m_constraintNumber(0), + m_channelNumber(0), m_lastapplyframe(0.0) { m_armature = (bArmature *)armature->data; @@ -67,7 +230,177 @@ BL_ArmatureObject::BL_ArmatureObject( * the original pose before calling into blender functions, to deal with * replica's or other objects using the same blender object */ m_pose = NULL; - game_copy_pose(&m_pose, m_objArma->pose); + game_copy_pose(&m_pose, m_objArma->pose, 1); + // store the original armature object matrix + memcpy(m_obmat, m_objArma->obmat, sizeof(m_obmat)); +} + +BL_ArmatureObject::~BL_ArmatureObject() +{ + BL_ArmatureConstraint* constraint; + while ((constraint = m_controlledConstraints.Remove()) != NULL) { + delete constraint; + } + BL_ArmatureChannel* channel; + while ((channel = static_cast<BL_ArmatureChannel*>(m_poseChannels.Remove())) != NULL) { + delete channel; + } + if (m_pose) + game_free_pose(m_pose); + if (m_framePose) + game_free_pose(m_framePose); +} + + +void BL_ArmatureObject::LoadConstraints(KX_BlenderSceneConverter* converter) +{ + // first delete any existing constraint (should not have any) + while (!m_controlledConstraints.Empty()) { + BL_ArmatureConstraint* constraint = m_controlledConstraints.Remove(); + delete constraint; + } + m_constraintNumber = 0; + + // list all the constraint and convert them to BL_ArmatureConstraint + // get the persistent pose structure + bPoseChannel* pchan; + bConstraint* pcon; + bConstraintTypeInfo* cti; + Object* blendtarget; + KX_GameObject* gametarget; + KX_GameObject* gamesubtarget; + + // and locate the constraint + for (pchan = (bPoseChannel*)m_pose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) { + for (pcon = (bConstraint*)pchan->constraints.first; pcon; pcon=(bConstraint*)pcon->next) { + if (pcon->flag & CONSTRAINT_DISABLE) + continue; + // which constraint should we support? + switch (pcon->type) { + case CONSTRAINT_TYPE_TRACKTO: + case CONSTRAINT_TYPE_KINEMATIC: + case CONSTRAINT_TYPE_ROTLIKE: + case CONSTRAINT_TYPE_LOCLIKE: + case CONSTRAINT_TYPE_MINMAX: + case CONSTRAINT_TYPE_SIZELIKE: + case CONSTRAINT_TYPE_LOCKTRACK: + case CONSTRAINT_TYPE_STRETCHTO: + case CONSTRAINT_TYPE_CLAMPTO: + case CONSTRAINT_TYPE_TRANSFORM: + case CONSTRAINT_TYPE_DISTLIMIT: + cti = constraint_get_typeinfo(pcon); + gametarget = gamesubtarget = NULL; + if (cti && cti->get_constraint_targets) { + ListBase listb = { NULL, NULL }; + cti->get_constraint_targets(pcon, &listb); + if (listb.first) { + bConstraintTarget* target = (bConstraintTarget*)listb.first; + if (target->tar && target->tar != m_objArma) { + // only remember external objects, self target is handled automatically + blendtarget = target->tar; + gametarget = converter->FindGameObject(blendtarget); + } + if (target->next != NULL) { + // secondary target + target = (bConstraintTarget*)target->next; + if (target->tar && target->tar != m_objArma) { + // only track external object + blendtarget = target->tar; + gamesubtarget = converter->FindGameObject(blendtarget); + } + } + } + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(pcon, &listb, 1); + } + BL_ArmatureConstraint* constraint = new BL_ArmatureConstraint(this, pchan, pcon, gametarget, gamesubtarget); + m_controlledConstraints.AddBack(constraint); + m_constraintNumber++; + } + } + } +} + +BL_ArmatureConstraint* BL_ArmatureObject::GetConstraint(const char* posechannel, const char* constraintname) +{ + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end(); ++cit) { + BL_ArmatureConstraint* constraint = *cit; + if (constraint->Match(posechannel, constraintname)) + return constraint; + } + return NULL; +} + +BL_ArmatureConstraint* BL_ArmatureObject::GetConstraint(const char* posechannelconstraint) +{ + // performance: use hash string instead of plain string compare + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end(); ++cit) { + BL_ArmatureConstraint* constraint = *cit; + if (!strcmp(constraint->GetName(), posechannelconstraint)) + return constraint; + } + return NULL; +} + +BL_ArmatureConstraint* BL_ArmatureObject::GetConstraint(int index) +{ + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end() && index; ++cit, --index); + return (cit.end()) ? NULL : *cit; +} + +/* this function is called to populate the m_poseChannels list */ +void BL_ArmatureObject::LoadChannels() +{ + if (m_poseChannels.Empty()) { + bPoseChannel* pchan; + BL_ArmatureChannel* proxy; + + m_channelNumber = 0; + for (pchan = (bPoseChannel*)m_pose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) { + proxy = new BL_ArmatureChannel(this, pchan); + m_poseChannels.AddBack(proxy); + m_channelNumber++; + } + } +} + +BL_ArmatureChannel* BL_ArmatureObject::GetChannel(bPoseChannel* pchan) +{ + LoadChannels(); + SG_DList::iterator<BL_ArmatureChannel> cit(m_poseChannels); + for (cit.begin(); !cit.end(); ++cit) + { + BL_ArmatureChannel* channel = *cit; + if (channel->m_posechannel == pchan) + return channel; + } + return NULL; +} + +BL_ArmatureChannel* BL_ArmatureObject::GetChannel(const char* str) +{ + LoadChannels(); + SG_DList::iterator<BL_ArmatureChannel> cit(m_poseChannels); + for (cit.begin(); !cit.end(); ++cit) + { + BL_ArmatureChannel* channel = *cit; + if (!strcmp(channel->m_posechannel->name, str)) + return channel; + } + return NULL; +} + +BL_ArmatureChannel* BL_ArmatureObject::GetChannel(int index) +{ + LoadChannels(); + if (index < 0 || index >= m_channelNumber) + return NULL; + SG_DList::iterator<BL_ArmatureChannel> cit(m_poseChannels); + for (cit.begin(); !cit.end() && index; ++cit, --index); + return (cit.end()) ? NULL : *cit; } CValue* BL_ArmatureObject::GetReplica() @@ -83,22 +416,61 @@ void BL_ArmatureObject::ProcessReplica() KX_GameObject::ProcessReplica(); m_pose = NULL; - game_copy_pose(&m_pose, pose); + m_framePose = NULL; + game_copy_pose(&m_pose, pose, 1); } -BL_ArmatureObject::~BL_ArmatureObject() +void BL_ArmatureObject::ReParentLogic() { - if (m_pose) - game_free_pose(m_pose); + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end(); ++cit) { + (*cit)->ReParent(this); + } + KX_GameObject::ReParentLogic(); +} + +void BL_ArmatureObject::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map) +{ + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end(); ++cit) { + (*cit)->Relink(obj_map); + } + KX_GameObject::Relink(obj_map); +} + +bool BL_ArmatureObject::UnlinkObject(SCA_IObject* clientobj) +{ + // clientobj is being deleted, make sure we don't hold any reference to it + bool res = false; + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end(); ++cit) { + res |= (*cit)->UnlinkObject(clientobj); + } + return res; } void BL_ArmatureObject::ApplyPose() { m_armpose = m_objArma->pose; m_objArma->pose = m_pose; + // in the GE, we use ctime to store the timestep + m_pose->ctime = (float)m_timestep; //m_scene->r.cfra++; if(m_lastapplyframe != m_lastframe) { + // update the constraint if any, first put them all off so that only the active ones will be updated + SG_DList::iterator<BL_ArmatureConstraint> cit(m_controlledConstraints); + for (cit.begin(); !cit.end(); ++cit) { + (*cit)->UpdateTarget(); + } + // update ourself + UpdateBlenderObjectMatrix(m_objArma); where_is_pose(m_scene, m_objArma); // XXX + // restore ourself + memcpy(m_objArma->obmat, m_obmat, sizeof(m_obmat)); + // restore active targets + for (cit.begin(); !cit.end(); ++cit) { + (*cit)->RestoreTarget(); + } m_lastapplyframe = m_lastframe; } } @@ -119,30 +491,37 @@ bool BL_ArmatureObject::SetActiveAction(BL_ActionActuator *act, short priority, { if (curtime != m_lastframe){ m_activePriority = 9999; + // compute the timestep for the underlying IK algorithm + m_timestep = curtime-m_lastframe; m_lastframe= curtime; m_activeAct = NULL; // remember the pose at the start of the frame - m_framePose = m_pose; + GetPose(&m_framePose); } - if (priority<=m_activePriority) + if (act) { - if (priority<m_activePriority) - // this action overwrites the previous ones, start from initial pose to cancel their effects - m_pose = m_framePose; - if (m_activeAct && (m_activeAct!=act)) - m_activeAct->SetBlendTime(0.0); /* Reset the blend timer */ - m_activeAct = act; - m_activePriority = priority; - m_lastframe = curtime; - - return true; - } - else{ - act->SetBlendTime(0.0); - return false; + if (priority<=m_activePriority) + { + if (priority<m_activePriority) { + // this action overwrites the previous ones, start from initial pose to cancel their effects + SetPose(m_framePose); + if (m_activeAct && (m_activeAct!=act)) + /* Reset the blend timer since this new action cancels the old one */ + m_activeAct->SetBlendTime(0.0); + } + m_activeAct = act; + m_activePriority = priority; + m_lastframe = curtime; + + return true; + } + else{ + act->SetBlendTime(0.0); + return false; + } } - + return false; } BL_ActionActuator * BL_ArmatureObject::GetActiveAction() @@ -161,7 +540,7 @@ void BL_ArmatureObject::GetPose(bPose **pose) a crash and memory leakage when &BL_ActionActuator::m_pose is freed */ - game_copy_pose(pose, m_pose); + game_copy_pose(pose, m_pose, 0); } else { if (*pose == m_pose) @@ -178,7 +557,7 @@ void BL_ArmatureObject::GetMRDPose(bPose **pose) /* Otherwise, copy the armature's pose channels into the caller-supplied pose */ if (!*pose) - game_copy_pose(pose, m_pose); + game_copy_pose(pose, m_pose, 0); else extract_pose_from_pose(*pose, m_pose); } @@ -210,3 +589,72 @@ float BL_ArmatureObject::GetBoneLength(Bone* bone) const { return (float)(MT_Point3(bone->head) - MT_Point3(bone->tail)).length(); } + +#ifndef DISABLE_PYTHON + +// PYTHON + +PyTypeObject BL_ArmatureObject::Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "BL_ArmatureObject", + sizeof(PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, + &KX_GameObject::Sequence, + &KX_GameObject::Mapping, + 0,0,0, + NULL, + NULL, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + &KX_GameObject::Type, + 0,0,0,0,0,0, + py_base_new +}; + +PyMethodDef BL_ArmatureObject::Methods[] = { + + KX_PYMETHODTABLE_NOARGS(BL_ArmatureObject, update), + {NULL,NULL} //Sentinel +}; + +PyAttributeDef BL_ArmatureObject::Attributes[] = { + + KX_PYATTRIBUTE_RO_FUNCTION("constraints", BL_ArmatureObject, pyattr_get_constraints), + KX_PYATTRIBUTE_RO_FUNCTION("channels", BL_ArmatureObject, pyattr_get_channels), + {NULL} //Sentinel +}; + +PyObject* BL_ArmatureObject::pyattr_get_constraints(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + return KX_PythonSeq_CreatePyObject((static_cast<BL_ArmatureObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CONSTRAINTS); +} + +PyObject* BL_ArmatureObject::pyattr_get_channels(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + BL_ArmatureObject* self = static_cast<BL_ArmatureObject*>(self_v); + self->LoadChannels(); // make sure we have the channels + return KX_PythonSeq_CreatePyObject((static_cast<BL_ArmatureObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CHANNELS); +} + +KX_PYMETHODDEF_DOC_NOARGS(BL_ArmatureObject, update, + "update()\n" + "Make sure that the armature will be updated on next graphic frame.\n" + "This is automatically done if a KX_ArmatureActuator with mode run is active\n" + "or if an action is playing. This function is usefull in other cases.\n") +{ + SetActiveAction(NULL, 0, KX_GetActiveEngine()->GetFrameTime()); + Py_RETURN_NONE; +} + +#endif // DISABLE_PYTHON diff --git a/source/gameengine/Converter/BL_ArmatureObject.h b/source/gameengine/Converter/BL_ArmatureObject.h index af0b7dc201c..b7ef38468bb 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.h +++ b/source/gameengine/Converter/BL_ArmatureObject.h @@ -31,21 +31,34 @@ #define BL_ARMATUREOBJECT #include "KX_GameObject.h" +#include "BL_ArmatureConstraint.h" +#include "BL_ArmatureChannel.h" #include "SG_IObject.h" +#include <vector> +#include <algorithm> struct bArmature; struct Bone; +struct bConstraint; class BL_ActionActuator; +class BL_ArmatureActuator; class MT_Matrix4x4; struct Object; +class KX_BlenderSceneConverter; class BL_ArmatureObject : public KX_GameObject { + Py_Header; public: + double GetLastFrame (); short GetActivePriority(); virtual void ProcessReplica(); + virtual void ReParentLogic(); + virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map); + virtual bool UnlinkObject(SCA_IObject* clientobj); + class BL_ActionActuator * GetActiveAction(); BL_ArmatureObject( @@ -73,6 +86,19 @@ public: Object* GetArmatureObject() {return m_objArma;} + // for constraint python API + void LoadConstraints(KX_BlenderSceneConverter* converter); + size_t GetConstraintNumber() const { return m_constraintNumber; } + BL_ArmatureConstraint* GetConstraint(const char* posechannel, const char* constraint); + BL_ArmatureConstraint* GetConstraint(const char* posechannelconstraint); + BL_ArmatureConstraint* GetConstraint(int index); + // for pose channel python API + void LoadChannels(); + size_t GetChannelNumber() const { return m_constraintNumber; } + BL_ArmatureChannel* GetChannel(bPoseChannel* channel); + BL_ArmatureChannel* GetChannel(const char* channel); + BL_ArmatureChannel* GetChannel(int index); + /// Retrieve the pose matrix for the specified bone. /// Returns true on success. bool GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix); @@ -81,7 +107,21 @@ public: float GetBoneLength(Bone* bone) const; virtual int GetGameObjectType() { return OBJ_ARMATURE; } + +#ifndef DISABLE_PYTHON + + // PYTHON + static PyObject* pyattr_get_constraints(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_channels(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + KX_PYMETHOD_DOC_NOARGS(BL_ArmatureObject, update); + +#endif // DISABLE_PYTHON + protected: + /* list element: BL_ArmatureConstraint. Use SG_DListHead to have automatic list replication */ + SG_DListHead<BL_ArmatureConstraint> m_controlledConstraints; + /* list element: BL_ArmatureChannel. Use SG_DList to avoid list replication */ + SG_DList m_poseChannels; Object *m_objArma; struct bArmature *m_armature; struct bPose *m_pose; @@ -89,18 +129,23 @@ protected: struct bPose *m_framePose; struct Scene *m_scene; // need for where_is_pose double m_lastframe; + double m_timestep; // delta since last pose evaluation. class BL_ActionActuator *m_activeAct; short m_activePriority; + size_t m_constraintNumber; + size_t m_channelNumber; + // store the original armature object matrix + float m_obmat[4][4]; double m_lastapplyframe; +}; +/* Pose function specific to the game engine */ +void game_blend_poses(struct bPose *dst, struct bPose *src, float srcweight/*, short mode*/); /* was blend_poses */ +//void extract_pose_from_pose(struct bPose *pose, const struct bPose *src); +void game_copy_pose(struct bPose **dst, struct bPose *src, int copy_con); +void game_free_pose(struct bPose *pose); -#ifdef WITH_CXX_GUARDEDALLOC -public: - void *operator new( unsigned int num_bytes) { return MEM_mallocN(num_bytes, "GE:BL_ArmatureObject"); } - void operator delete( void *mem ) { MEM_freeN(mem); } -#endif -}; #endif diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 230820719aa..db32f18f63b 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -838,8 +838,10 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene, if (mface->v4) tan3 = tangent[f*4 + 3]; } - - ma = give_current_material(blenderobj, mface->mat_nr+1); + if(blenderobj) + ma = give_current_material(blenderobj, mface->mat_nr+1); + else + ma = mesh->mat ? mesh->mat[mface->mat_nr]:NULL; { bool visible = true; @@ -1895,7 +1897,6 @@ void BL_ConvertBlenderObjects(struct Main* maggie, KX_Scene* kxscene, KX_KetsjiEngine* ketsjiEngine, e_PhysicsEngine physics_engine, - PyObject* pythondictionary, RAS_IRenderTools* rendertools, RAS_ICanvas* canvas, KX_BlenderSceneConverter* converter, @@ -2501,6 +2502,14 @@ void BL_ConvertBlenderObjects(struct Main* maggie, gameobj->GetDeformer()->UpdateBuckets(); } + // Set up armature constraints + for (i=0;i<sumolist->GetCount();++i) + { + KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); + if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) + ((BL_ArmatureObject*)gameobj)->LoadConstraints(converter); + } + bool processCompoundChildren = false; // create physics information @@ -2643,7 +2652,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, struct Object* blenderobj = gameobj->GetBlenderObject(); int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; - BL_ConvertControllers(blenderobj,gameobj,logicmgr,pythondictionary,layerMask,isInActiveLayer,converter); + BL_ConvertControllers(blenderobj,gameobj,logicmgr, layerMask,isInActiveLayer,converter); } for ( i=0;i<logicbrick_conversionlist->GetCount();i++) { diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.h b/source/gameengine/Converter/BL_BlenderDataConversion.h index b8f9d1ec4e6..218b296b47b 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.h +++ b/source/gameengine/Converter/BL_BlenderDataConversion.h @@ -40,7 +40,6 @@ void BL_ConvertBlenderObjects(struct Main* maggie, class KX_Scene* kxscene, class KX_KetsjiEngine* ketsjiEngine, e_PhysicsEngine physics_engine, - PyObject* pythondictionary, class RAS_IRenderTools* rendertools, class RAS_ICanvas* canvas, class KX_BlenderSceneConverter* sceneconverter, diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.cpp b/source/gameengine/Converter/BL_ShapeActionActuator.cpp index 81ce9ff6154..0af6556f285 100644 --- a/source/gameengine/Converter/BL_ShapeActionActuator.cpp +++ b/source/gameengine/Converter/BL_ShapeActionActuator.cpp @@ -412,6 +412,8 @@ bool BL_ShapeActionActuator::Update(double curtime, bool frame) return keepgoing; }; +#ifndef DISABLE_PYTHON + /* ------------------------------------------------------------------------- */ /* Python functions */ /* ------------------------------------------------------------------------- */ @@ -492,3 +494,5 @@ int BL_ShapeActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE return PY_SET_ATTR_SUCCESS; } + +#endif // DISABLE_PYTHON diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.h b/source/gameengine/Converter/BL_ShapeActionActuator.h index 28a6d90abdf..efb1293a5eb 100644 --- a/source/gameengine/Converter/BL_ShapeActionActuator.h +++ b/source/gameengine/Converter/BL_ShapeActionActuator.h @@ -51,7 +51,7 @@ public: short blendin, short priority, float stride) - : SCA_IActuator(gameobj), + : SCA_IActuator(gameobj, KX_ACT_SHAPEACTION), m_lastpos(0, 0, 0), m_blendframe(0), @@ -82,6 +82,8 @@ public: bAction* GetAction() { return m_action; } void SetAction(bAction* act) { m_action= act; } +#ifndef DISABLE_PYTHON + static PyObject* pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); @@ -123,6 +125,8 @@ public: } +#endif // DISABLE_PYTHON + protected: void SetStartTime(float curtime); diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt index 257ca856b2c..f9af2c23629 100644 --- a/source/gameengine/Converter/CMakeLists.txt +++ b/source/gameengine/Converter/CMakeLists.txt @@ -59,9 +59,15 @@ SET(INC ../../../source/blender/misc ../../../source/blender/blenloader ../../../source/blender/gpu + ../../../source/blender/ikplugin ../../../extern/bullet2/src - ${PYTHON_INC} ) +IF(WITH_PYTHON) + SET(INC ${INC} ${PYTHON_INC}) +ELSE(WITH_PYTHON) + ADD_DEFINITIONS(-DDISABLE_PYTHON) +ENDIF(WITH_PYTHON) + BLENDERLIB(bf_converter "${SRC}" "${INC}") #env.BlenderLib ( 'bf_converter', sources, Split(incs), [], libtype=['game','player'], priority=[5,70] ) diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index 151564391f3..26b4514061c 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -243,7 +243,6 @@ struct BlenderDebugDraw : public btIDebugDraw #endif void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene, - PyObject* dictobj, class RAS_IRenderTools* rendertools, class RAS_ICanvas* canvas) { @@ -328,7 +327,6 @@ void KX_BlenderSceneConverter::ConvertScene(class KX_Scene* destinationscene, destinationscene, m_ketsjiEngine, physics_engine, - dictobj, rendertools, canvas, this, @@ -920,3 +918,10 @@ void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo() } + +#ifndef DISABLE_PYTHON +PyObject *KX_BlenderSceneConverter::GetPyNamespace() +{ + return m_ketsjiEngine->GetPyNamespace(); +} +#endif diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.h b/source/gameengine/Converter/KX_BlenderSceneConverter.h index bb87a21a683..f74944d3552 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.h +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.h @@ -89,7 +89,6 @@ public: */ virtual void ConvertScene( class KX_Scene* destinationscene, - PyObject* dictobj, class RAS_IRenderTools* rendertools, class RAS_ICanvas* canvas ); @@ -143,6 +142,9 @@ public: struct Main* GetMain() { return m_maggie; }; +#ifndef DISABLE_PYTHON + PyObject *GetPyNamespace(); +#endif #ifdef WITH_CXX_GUARDEDALLOC public: diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 91a39bd7686..1cb16acf148 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -88,6 +88,7 @@ #include "DNA_packedFile_types.h" #include "BL_ActionActuator.h" #include "BL_ShapeActionActuator.h" +#include "BL_ArmatureActuator.h" /* end of blender include block */ #include "BL_BlenderDataConversion.h" @@ -1021,6 +1022,15 @@ void BL_ConvertActuators(char* maggiename, break; } + case ACT_ARMATURE: + { + bArmatureActuator* armAct = (bArmatureActuator*) bact->data; + KX_GameObject *tmpgob = converter->FindGameObject(armAct->target); + KX_GameObject *subgob = converter->FindGameObject(armAct->subtarget); + BL_ArmatureActuator* tmparmact = new BL_ArmatureActuator(gameobj, armAct->type, armAct->posechannel, armAct->constraint, tmpgob, subgob, armAct->weight); + baseact = tmparmact; + break; + } default: ; /* generate some error */ } diff --git a/source/gameengine/Converter/KX_ConvertControllers.cpp b/source/gameengine/Converter/KX_ConvertControllers.cpp index 85ab8e4f8b8..faef0feaf48 100644 --- a/source/gameengine/Converter/KX_ConvertControllers.cpp +++ b/source/gameengine/Converter/KX_ConvertControllers.cpp @@ -91,8 +91,7 @@ LinkControllerToActuators( void BL_ConvertControllers( struct Object* blenderobject, class KX_GameObject* gameobj, - SCA_LogicManager* logicmgr, - PyObject* pythondictionary, + SCA_LogicManager* logicmgr, int activeLayerBitInfo, bool isInActiveLayer, KX_BlenderSceneConverter* converter @@ -158,8 +157,9 @@ void BL_ConvertControllers( bPythonCont* pycont = (bPythonCont*) bcontr->data; SCA_PythonController* pyctrl = new SCA_PythonController(gameobj, pycont->mode); gamecontroller = pyctrl; - - pyctrl->SetDictionary(pythondictionary); +#ifndef DISABLE_PYTHON + + pyctrl->SetNamespace(converter->GetPyNamespace()); if(pycont->mode==SCA_PythonController::SCA_PYEXEC_SCRIPT) { if (pycont->text) @@ -187,6 +187,8 @@ void BL_ConvertControllers( pyctrl->SetDebug(true); } +#endif // DISABLE_PYTHON + break; } default: @@ -211,7 +213,8 @@ void BL_ConvertControllers( gameobj->AddController(gamecontroller); converter->RegisterGameController(gamecontroller, bcontr); - + +#ifndef DISABLE_PYTHON if (bcontr->type==CONT_PYTHON) { SCA_PythonController *pyctrl= static_cast<SCA_PythonController*>(gamecontroller); /* not strictly needed but gives syntax errors early on and @@ -226,7 +229,8 @@ void BL_ConvertControllers( // pyctrl->Import(); } } - +#endif // DISABLE_PYTHON + //done with gamecontroller gamecontroller->Release(); } diff --git a/source/gameengine/Converter/KX_ConvertControllers.h b/source/gameengine/Converter/KX_ConvertControllers.h index d340778290c..2689ad446bd 100644 --- a/source/gameengine/Converter/KX_ConvertControllers.h +++ b/source/gameengine/Converter/KX_ConvertControllers.h @@ -34,8 +34,7 @@ void BL_ConvertControllers( struct Object* blenderobject, class KX_GameObject* gameobj, - class SCA_LogicManager* logicmgr, - PyObject* pythondictionary, + class SCA_LogicManager* logicmgr, int activeLayerBitInfo, bool isInActiveLayer, class KX_BlenderSceneConverter* converter diff --git a/source/gameengine/Converter/KX_ConvertProperties.cpp b/source/gameengine/Converter/KX_ConvertProperties.cpp index 1c22d2a0600..7ecdb6c5db6 100644 --- a/source/gameengine/Converter/KX_ConvertProperties.cpp +++ b/source/gameengine/Converter/KX_ConvertProperties.cpp @@ -130,7 +130,7 @@ void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventMan propval->Release(); } - +#ifndef DISABLE_PYTHON /* Warn if we double up on attributes, this isnt quite right since it wont find inherited attributes however there arnt many */ for(PyAttributeDef *attrdef = KX_GameObject::Attributes; attrdef->m_name; attrdef++) { if(strcmp(prop->name, attrdef->m_name)==0) { @@ -145,6 +145,7 @@ void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventMan } } /* end warning check */ +#endif // DISABLE_PYTHON prop = prop->next; } diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp index 09027f18844..692cc91f340 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.cpp +++ b/source/gameengine/Converter/KX_ConvertSensors.cpp @@ -28,6 +28,7 @@ * Conversion of Blender data blocks to KX sensor system */ +#include <stdio.h> #ifdef HAVE_CONFIG_H #include <config.h> @@ -64,6 +65,7 @@ probably misplaced */ #include "KX_NearSensor.h" #include "KX_RadarSensor.h" #include "KX_MouseFocusSensor.h" +#include "KX_ArmatureSensor.h" #include "SCA_JoystickSensor.h" #include "KX_NetworkMessageSensor.h" #include "SCA_ActuatorSensor.h" @@ -302,7 +304,7 @@ void BL_ConvertSensors(struct Object* blenderobject, case SENS_ALWAYS: { - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::ALWAYS_EVENTMGR); + SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); if (eventmgr) { gamesensor = new SCA_AlwaysSensor(eventmgr, gameobj); @@ -314,7 +316,7 @@ void BL_ConvertSensors(struct Object* blenderobject, case SENS_DELAY: { // we can reuse the Always event manager for the delay sensor - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::ALWAYS_EVENTMGR); + SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); if (eventmgr) { bDelaySensor* delaysensor = (bDelaySensor*)sens->data; @@ -550,7 +552,7 @@ void BL_ConvertSensors(struct Object* blenderobject, { bPropertySensor* blenderpropsensor = (bPropertySensor*) sens->data; SCA_EventManager* eventmgr - = logicmgr->FindEventManager(SCA_EventManager::PROPERTY_EVENTMGR); + = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); if (eventmgr) { STR_String propname=blenderpropsensor->name; @@ -601,6 +603,21 @@ void BL_ConvertSensors(struct Object* blenderobject, break; } + case SENS_ARMATURE: + { + bArmatureSensor* blenderarmsensor = (bArmatureSensor*) sens->data; + // we will reuse the property event manager, there is nothing special with this sensor + SCA_EventManager* eventmgr + = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); + if (eventmgr) + { + STR_String bonename=blenderarmsensor->posechannel; + STR_String constraintname=blenderarmsensor->constraint; + gamesensor = new KX_ArmatureSensor(eventmgr,gameobj,bonename,constraintname, blenderarmsensor->type, blenderarmsensor->value); + } + break; + } + case SENS_RADAR: { @@ -659,7 +676,7 @@ void BL_ConvertSensors(struct Object* blenderobject, bRaySensor* blenderraysensor = (bRaySensor*) sens->data; //blenderradarsensor->angle; - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::RAY_EVENTMGR); + SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); if (eventmgr) { bool bFindMaterial = (blenderraysensor->mode & SENS_COLLISION_MATERIAL); @@ -691,7 +708,7 @@ void BL_ConvertSensors(struct Object* blenderobject, // some files didn't write randomsensor, avoid crash now for NULL ptr's if (blenderrndsensor) { - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::RANDOM_EVENTMGR); + SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); if (eventmgr) { int randomSeed = blenderrndsensor->seed; diff --git a/source/gameengine/Converter/Makefile b/source/gameengine/Converter/Makefile index e261f9350e9..d41cc705087 100644 --- a/source/gameengine/Converter/Makefile +++ b/source/gameengine/Converter/Makefile @@ -53,6 +53,7 @@ CPPFLAGS += -I../../blender/blenlib CPPFLAGS += -I../../blender/blenkernel CPPFLAGS += -I../../blender/render/extern/include CPPFLAGS += -I../../blender/gpu +CPPFLAGS += -I../../blender/ikplugin CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include CPPFLAGS += -I../Expressions -I../Rasterizer -I../GameLogic CPPFLAGS += -I../Ketsji -I../BlenderRoutines -I../SceneGraph diff --git a/source/gameengine/Converter/SConscript b/source/gameengine/Converter/SConscript index 2d126310475..616c205732c 100644 --- a/source/gameengine/Converter/SConscript +++ b/source/gameengine/Converter/SConscript @@ -13,14 +13,23 @@ incs += ' #source/blender/blenlib #source/blender/blenkernel #source/blender' incs += ' #source/blender/editors/include #source/blender/makesdna #source/gameengine/Rasterizer' incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer #source/gameengine/GameLogic' incs += ' #source/gameengine/Expressions #source/gameengine/Network #source/gameengine/SceneGraph' -incs += ' #source/gameengine/Physics/common #source/gameengine/Physics/Bullet #source/gameengine/Physics/BlOde' +incs += ' #source/gameengine/Physics/common #source/gameengine/Physics/Bullet' incs += ' #source/gameengine/Physics/Dummy' incs += ' #source/gameengine/Network/LoopBackNetwork' incs += ' #source/blender/misc #source/blender/blenloader #source/blender/gpu' incs += ' #source/blender/windowmanager' incs += ' #source/blender/makesrna' +incs += ' #source/blender/ikplugin' -incs += ' ' + env['BF_PYTHON_INC'] incs += ' ' + env['BF_BULLET_INC'] +if env['BF_DEBUG']: + if env['OURPLATFORM'] in ('win32-mingw', 'win32-vc', 'win64-vc'): + defs.append('_DEBUG') + +if env['WITH_BF_PYTHON']: + incs += ' ' + env['BF_PYTHON_INC'] +else: + defs.append('DISABLE_PYTHON') + env.BlenderLib ( 'bf_converter', sources, Split(incs), defs, libtype=['core','player'], priority=[305,40], cxx_compileflags=env['BGE_CXXFLAGS']) |