diff options
Diffstat (limited to 'source/gameengine/Converter')
-rw-r--r-- | source/gameengine/Converter/BL_ArmatureActuator.cpp | 267 | ||||
-rw-r--r-- | source/gameengine/Converter/BL_ArmatureActuator.h | 93 | ||||
-rw-r--r-- | source/gameengine/Converter/BL_ArmatureChannel.cpp | 469 | ||||
-rw-r--r-- | source/gameengine/Converter/BL_ArmatureChannel.h | 95 | ||||
-rw-r--r-- | source/gameengine/Converter/BL_ArmatureConstraint.cpp | 454 | ||||
-rw-r--r-- | source/gameengine/Converter/BL_ArmatureConstraint.h | 118 |
6 files changed, 1496 insertions, 0 deletions
diff --git a/source/gameengine/Converter/BL_ArmatureActuator.cpp b/source/gameengine/Converter/BL_ArmatureActuator.cpp new file mode 100644 index 00000000000..4105eb57d5f --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureActuator.cpp @@ -0,0 +1,267 @@ +/** + * $Id: BL_ArmatureActuator.cpp 23562 2009-09-29 21:42:40Z campbellbarton $ + * + * ***** 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..29b07b16d52 --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureActuator.h @@ -0,0 +1,93 @@ +/** + * $Id: BL_ArmatureActuator.h 23562 2009-09-29 21:42:40Z campbellbarton $ + * + * ***** 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..817049c6977 --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureChannel.cpp @@ -0,0 +1,469 @@ +/** + * $Id: BL_ArmatureChannel.cpp 23562 2009-09-29 21:42:40Z campbellbarton $ + * ***** 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..249fa4c8ac7 --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureChannel.h @@ -0,0 +1,95 @@ +/** + * $Id: BL_ArmatureChannel.h 23562 2009-09-29 21:42:40Z campbellbarton $ + * + * ***** 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..4c470b67387 --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureConstraint.cpp @@ -0,0 +1,454 @@ +/** + * $Id: BL_ArmatureConstraint.cpp 23562 2009-09-29 21:42:40Z campbellbarton $ + * ***** 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..c1510b3c56a --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureConstraint.h @@ -0,0 +1,118 @@ +/** + * $Id: BL_ArmatureConstraint.h 23562 2009-09-29 21:42:40Z campbellbarton $ + * + * ***** 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 + |