diff options
Diffstat (limited to 'source/gameengine/Converter/BL_ArmatureConstraint.cpp')
-rw-r--r-- | source/gameengine/Converter/BL_ArmatureConstraint.cpp | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.cpp b/source/gameengine/Converter/BL_ArmatureConstraint.cpp new file mode 100644 index 00000000000..15e12611483 --- /dev/null +++ b/source/gameengine/Converter/BL_ArmatureConstraint.cpp @@ -0,0 +1,447 @@ +/** + * $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" + +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); +} + +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); + } + } + +} + +// 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; +} + |