blender/source/gameengine/Converter/BL_ArmatureConstraint.cpp

451 lines
14 KiB
C++

/**
* $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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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_constraint_types.h"
#include "DNA_action_types.h"
#include "BL_ArmatureConstraint.h"
#include "BL_ArmatureObject.h"
#include "BLI_math.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_constraint(constraint), m_posechannel(posechannel), m_armature(armature)
{
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) {
copy_m4_m4(m_blendmat, m_blendtarget->obmat);
if (m_blendtarget->type == OB_ARMATURE)
m_pose = m_blendtarget->pose;
}
if (m_blendsubtarget) {
copy_m4_m4(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) {
copy_m4_m4(m_blendtarget->obmat, m_blendmat);
if (m_pose)
m_blendtarget->pose = m_pose;
}
if (m_blendsubtarget && m_subtarget) {
copy_m4_m4(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