Blender  V2.59
BL_ArmatureConstraint.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: BL_ArmatureConstraint.cpp 36523 2011-05-06 20:18:42Z blendix $
00003  * ***** BEGIN GPL LICENSE BLOCK *****
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00020  * All rights reserved.
00021  *
00022  * The Original Code is: all of this file.
00023  *
00024  * Contributor(s): none yet.
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #include "DNA_constraint_types.h"
00035 #include "DNA_action_types.h"
00036 #include "BL_ArmatureConstraint.h"
00037 #include "BL_ArmatureObject.h"
00038 #include "BLI_math.h"
00039 #include "BLI_string.h"
00040 
00041 #ifdef WITH_PYTHON
00042 
00043 PyTypeObject BL_ArmatureConstraint::Type = {
00044         PyVarObject_HEAD_INIT(NULL, 0)
00045         "BL_ArmatureConstraint",
00046         sizeof(PyObjectPlus_Proxy),
00047         0,
00048         py_base_dealloc,
00049         0,
00050         0,
00051         0,
00052         0,
00053         py_base_repr,
00054         0,0,0,0,0,0,0,0,0,
00055         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00056         0,0,0,0,0,0,0,
00057         Methods,
00058         0,
00059         0,
00060         &CValue::Type,
00061         0,0,0,0,0,0,
00062         py_base_new
00063 };
00064 
00065 PyObject* BL_ArmatureConstraint::py_repr(void)
00066 {
00067         return PyUnicode_FromString(m_name);
00068 }
00069 
00070 #endif // WITH_PYTHON
00071 
00072 BL_ArmatureConstraint::BL_ArmatureConstraint(
00073         BL_ArmatureObject *armature, 
00074         bPoseChannel *posechannel,
00075         bConstraint *constraint, 
00076         KX_GameObject* target,
00077         KX_GameObject* subtarget)
00078         : PyObjectPlus(), m_constraint(constraint), m_posechannel(posechannel), m_armature(armature)
00079 {
00080         m_target = target;
00081         m_blendtarget = (target) ? target->GetBlenderObject() : NULL;
00082         m_subtarget = subtarget;
00083         m_blendsubtarget = (subtarget) ? subtarget->GetBlenderObject() : NULL;
00084         m_pose = m_subpose = NULL;
00085         if (m_blendtarget) {
00086                 copy_m4_m4(m_blendmat, m_blendtarget->obmat);
00087                 if (m_blendtarget->type == OB_ARMATURE)
00088                         m_pose = m_blendtarget->pose;
00089         }
00090         if (m_blendsubtarget) {
00091                 copy_m4_m4(m_blendsubmat, m_blendsubtarget->obmat);
00092                 if (m_blendsubtarget->type == OB_ARMATURE)
00093                         m_subpose = m_blendsubtarget->pose;
00094         }
00095         if (m_target)
00096                 m_target->RegisterObject(m_armature);
00097         if (m_subtarget)
00098                 m_subtarget->RegisterObject(m_armature);
00099         BLI_snprintf(m_name, sizeof(m_name), "%s:%s", m_posechannel->name, m_constraint->name);
00100 }
00101 
00102 BL_ArmatureConstraint::~BL_ArmatureConstraint()
00103 {
00104         if (m_target)
00105                 m_target->UnregisterObject(m_armature);
00106         if (m_subtarget)
00107                 m_subtarget->UnregisterObject(m_armature);
00108 }
00109 
00110 BL_ArmatureConstraint* BL_ArmatureConstraint::GetReplica() const
00111 {
00112         BL_ArmatureConstraint* replica = new BL_ArmatureConstraint(*this);
00113         replica->ProcessReplica();
00114         return replica;
00115 }
00116 
00117 void BL_ArmatureConstraint::ReParent(BL_ArmatureObject* armature)
00118 {
00119         m_armature = armature;
00120         if (m_target)
00121                 m_target->RegisterObject(armature);
00122         if (m_subtarget)
00123                 m_subtarget->RegisterObject(armature);
00124         // find the corresponding constraint in the new armature object
00125         if (m_constraint) {
00126                 bPose* newpose = armature->GetOrigPose();
00127                 char* constraint = m_constraint->name;
00128                 char* posechannel = m_posechannel->name;
00129                 bPoseChannel* pchan;
00130                 bConstraint* pcon;
00131                 m_constraint = NULL;
00132                 m_posechannel = NULL;
00133                 // and locate the constraint
00134                 for (pchan = (bPoseChannel*)newpose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) {
00135                         if (!strcmp(pchan->name, posechannel)) {
00136                                 // now locate the constraint
00137                                 for (pcon = (bConstraint*)pchan->constraints.first; pcon; pcon=(bConstraint*)pcon->next) {
00138                                         if (!strcmp(pcon->name, constraint)) {
00139                                                 m_constraint = pcon;
00140                                                 m_posechannel = pchan;
00141                                                 break;
00142                                         }
00143                                 }
00144                                 break;
00145                         }
00146                 }
00147         }
00148 }
00149 
00150 void BL_ArmatureConstraint::Relink(CTR_Map<CTR_HashedPtr, void*> *obj_map)
00151 {
00152         void **h_obj = (*obj_map)[m_target];
00153         if (h_obj) {
00154                 m_target->UnregisterObject(m_armature);
00155                 m_target = (KX_GameObject*)(*h_obj);
00156                 m_target->RegisterObject(m_armature);
00157         }
00158         h_obj = (*obj_map)[m_subtarget];
00159         if (h_obj) {
00160                 m_subtarget->UnregisterObject(m_armature);
00161                 m_subtarget = (KX_GameObject*)(*h_obj);
00162                 m_subtarget->RegisterObject(m_armature);
00163         }
00164 }
00165 
00166 bool BL_ArmatureConstraint::UnlinkObject(SCA_IObject* clientobj)
00167 {
00168         bool res=false;
00169         if (clientobj == m_target) {
00170                 m_target = NULL;
00171                 res = true;
00172         }
00173         if (clientobj == m_subtarget) {
00174                 m_subtarget = NULL;
00175                 res = true;
00176         }
00177         return res;
00178 }
00179 
00180 void BL_ArmatureConstraint::UpdateTarget()
00181 {
00182         if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) {
00183                 if (m_blendtarget) {
00184                         // external target, must be updated
00185                         m_target->UpdateBlenderObjectMatrix(m_blendtarget);
00186                         if (m_pose && m_target->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
00187                                 // update the pose in case a bone is specified in the constraint target
00188                                 m_blendtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose();
00189                 }
00190                 if (m_blendsubtarget && m_subtarget) {
00191                         m_subtarget->UpdateBlenderObjectMatrix(m_blendsubtarget);
00192                         if (m_subpose && m_subtarget->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
00193                                 m_blendsubtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose();
00194                 }
00195         }
00196 }
00197 
00198 void BL_ArmatureConstraint::RestoreTarget()
00199 {
00200         if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) {
00201                 if (m_blendtarget) {
00202                         copy_m4_m4(m_blendtarget->obmat, m_blendmat);
00203                         if (m_pose)
00204                                 m_blendtarget->pose = m_pose;
00205                 }
00206                 if (m_blendsubtarget && m_subtarget) {
00207                         copy_m4_m4(m_blendsubtarget->obmat, m_blendsubmat);
00208                         if (m_subpose)
00209                                 m_blendsubtarget->pose = m_subpose;
00210                 }
00211         }
00212 }
00213 
00214 bool BL_ArmatureConstraint::Match(const char* posechannel, const char* constraint)
00215 {
00216         return (!strcmp(m_posechannel->name, posechannel) && !strcmp(m_constraint->name, constraint));
00217 }
00218 
00219 void BL_ArmatureConstraint::SetTarget(KX_GameObject* target)
00220 {
00221         if (m_blendtarget) {
00222                 if (target != m_target) {
00223                         m_target->UnregisterObject(m_armature);
00224                         m_target = target;
00225                         if (m_target)
00226                                 m_target->RegisterObject(m_armature);
00227                 }
00228         }
00229 
00230 }
00231 
00232 void BL_ArmatureConstraint::SetSubtarget(KX_GameObject* subtarget)
00233 {
00234         if (m_blendsubtarget) {
00235                 if (subtarget != m_subtarget) {
00236                         m_subtarget->UnregisterObject(m_armature);
00237                         m_subtarget = subtarget;
00238                         if (m_subtarget)
00239                                 m_subtarget->RegisterObject(m_armature);
00240                 }
00241         }
00242 
00243 }
00244 
00245 #ifdef WITH_PYTHON
00246 
00247 // PYTHON
00248 
00249 PyMethodDef BL_ArmatureConstraint::Methods[] = {
00250   {NULL,NULL} //Sentinel
00251 };
00252 
00253 // order of definition of attributes, must match Attributes[] array
00254 #define BCA_TYPE                0
00255 #define BCA_NAME                1
00256 #define BCA_ENFORCE             2
00257 #define BCA_HEADTAIL    3
00258 #define BCA_LINERROR    4
00259 #define BCA_ROTERROR    5
00260 #define BCA_TARGET              6
00261 #define BCA_SUBTARGET   7
00262 #define BCA_ACTIVE              8
00263 #define BCA_IKWEIGHT    9
00264 #define BCA_IKTYPE              10
00265 #define BCA_IKFLAG              11
00266 #define BCA_IKDIST              12
00267 #define BCA_IKMODE              13
00268 
00269 PyAttributeDef BL_ArmatureConstraint::Attributes[] = {
00270         // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr
00271         KX_PYATTRIBUTE_RO_FUNCTION("type",BL_ArmatureConstraint,py_attr_getattr),       
00272         KX_PYATTRIBUTE_RO_FUNCTION("name",BL_ArmatureConstraint,py_attr_getattr),       
00273         KX_PYATTRIBUTE_RW_FUNCTION("enforce",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
00274         KX_PYATTRIBUTE_RW_FUNCTION("headtail",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
00275         KX_PYATTRIBUTE_RO_FUNCTION("lin_error",BL_ArmatureConstraint,py_attr_getattr),
00276         KX_PYATTRIBUTE_RO_FUNCTION("rot_error",BL_ArmatureConstraint,py_attr_getattr),
00277         KX_PYATTRIBUTE_RW_FUNCTION("target",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
00278         KX_PYATTRIBUTE_RW_FUNCTION("subtarget",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
00279         KX_PYATTRIBUTE_RW_FUNCTION("active",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
00280         KX_PYATTRIBUTE_RW_FUNCTION("ik_weight",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
00281         KX_PYATTRIBUTE_RO_FUNCTION("ik_type",BL_ArmatureConstraint,py_attr_getattr),
00282         KX_PYATTRIBUTE_RO_FUNCTION("ik_flag",BL_ArmatureConstraint,py_attr_getattr),
00283         KX_PYATTRIBUTE_RW_FUNCTION("ik_dist",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
00284         KX_PYATTRIBUTE_RW_FUNCTION("ik_mode",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
00285         
00286         { NULL }        //Sentinel
00287 };
00288 
00289 
00290 PyObject* BL_ArmatureConstraint::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
00291 {
00292         BL_ArmatureConstraint* self= static_cast<BL_ArmatureConstraint*>(self_v);
00293         bConstraint* constraint = self->m_constraint;
00294         bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL;
00295         int attr_order = attrdef-Attributes;
00296 
00297         if (!constraint) {
00298                 PyErr_SetString(PyExc_AttributeError, "constraint is NULL");
00299                 return NULL;
00300         }
00301 
00302         switch (attr_order) {
00303         case BCA_TYPE:
00304                 return PyLong_FromLong(constraint->type);
00305         case BCA_NAME:
00306                 return PyUnicode_FromString(constraint->name);
00307         case BCA_ENFORCE:
00308                 return PyFloat_FromDouble(constraint->enforce);
00309         case BCA_HEADTAIL:
00310                 return PyFloat_FromDouble(constraint->headtail);
00311         case BCA_LINERROR:
00312                 return PyFloat_FromDouble(constraint->lin_error);
00313         case BCA_ROTERROR:
00314                 return PyFloat_FromDouble(constraint->rot_error);
00315         case BCA_TARGET:
00316                 if (!self->m_target)    
00317                         Py_RETURN_NONE;
00318                 else
00319                         return self->m_target->GetProxy();
00320         case BCA_SUBTARGET:
00321                 if (!self->m_subtarget) 
00322                         Py_RETURN_NONE;
00323                 else
00324                         return self->m_subtarget->GetProxy();
00325         case BCA_ACTIVE:
00326                 return PyBool_FromLong(constraint->flag & CONSTRAINT_OFF);
00327         case BCA_IKWEIGHT:
00328         case BCA_IKTYPE:
00329         case BCA_IKFLAG:
00330         case BCA_IKDIST:
00331         case BCA_IKMODE:
00332                 if (!ikconstraint) {
00333                         PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type");
00334                         return NULL;
00335                 }
00336                 switch (attr_order) {
00337                 case BCA_IKWEIGHT:
00338                         return PyFloat_FromDouble((ikconstraint)?ikconstraint->weight:0.0);
00339                 case BCA_IKTYPE:
00340                         return PyLong_FromLong(ikconstraint->type);
00341                 case BCA_IKFLAG:
00342                         return PyLong_FromLong(ikconstraint->flag);
00343                 case BCA_IKDIST:
00344                         return PyFloat_FromDouble(ikconstraint->dist);
00345                 case BCA_IKMODE:
00346                         return PyLong_FromLong(ikconstraint->mode);
00347                 }
00348                 // should not come here
00349                 break;
00350         }
00351         PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute");
00352         return NULL;
00353 }
00354 
00355 int BL_ArmatureConstraint::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00356 {
00357         BL_ArmatureConstraint* self= static_cast<BL_ArmatureConstraint*>(self_v);
00358         bConstraint* constraint = self->m_constraint;
00359         bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL;
00360         int attr_order = attrdef-Attributes;
00361         int ival;
00362         double dval;
00363 //      char* sval;
00364         KX_GameObject *oval;
00365 
00366         if (!constraint) {
00367                 PyErr_SetString(PyExc_AttributeError, "constraint is NULL");
00368                 return PY_SET_ATTR_FAIL;
00369         }
00370         
00371         switch (attr_order) {
00372         case BCA_ENFORCE:
00373                 dval = PyFloat_AsDouble(value);
00374                 if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */
00375                         PyErr_SetString(PyExc_AttributeError, "constraint.enforce = float: BL_ArmatureConstraint, expected a float between 0 and 1");
00376                         return PY_SET_ATTR_FAIL;
00377                 }
00378                 constraint->enforce = dval;
00379                 return PY_SET_ATTR_SUCCESS;
00380 
00381         case BCA_HEADTAIL:
00382                 dval = PyFloat_AsDouble(value);
00383                 if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */
00384                         PyErr_SetString(PyExc_AttributeError, "constraint.headtail = float: BL_ArmatureConstraint, expected a float between 0 and 1");
00385                         return PY_SET_ATTR_FAIL;
00386                 }
00387                 constraint->headtail = dval;
00388                 return PY_SET_ATTR_SUCCESS;
00389 
00390         case BCA_TARGET:
00391                 if (!ConvertPythonToGameObject(value, &oval, true, "constraint.target = value: BL_ArmatureConstraint"))
00392                         return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
00393                 self->SetTarget(oval);
00394                 return PY_SET_ATTR_SUCCESS;
00395 
00396         case BCA_SUBTARGET:
00397                 if (!ConvertPythonToGameObject(value, &oval, true, "constraint.subtarget = value: BL_ArmatureConstraint"))
00398                         return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
00399                 self->SetSubtarget(oval);
00400                 return PY_SET_ATTR_SUCCESS;
00401 
00402         case BCA_ACTIVE:
00403                 ival = PyObject_IsTrue( value );
00404                 if (ival == -1) {
00405                         PyErr_SetString(PyExc_AttributeError, "constraint.active = bool: BL_ArmatureConstraint, expected True or False");
00406                         return PY_SET_ATTR_FAIL;
00407                 }
00408                 self->m_constraint->flag = (self->m_constraint->flag & ~CONSTRAINT_OFF) | ((ival)?0:CONSTRAINT_OFF);
00409                 return PY_SET_ATTR_SUCCESS;
00410 
00411         case BCA_IKWEIGHT:
00412         case BCA_IKDIST:
00413         case BCA_IKMODE:
00414                 if (!ikconstraint) {
00415                         PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type");
00416                         return PY_SET_ATTR_FAIL;
00417                 }
00418                 switch (attr_order) {
00419                 case BCA_IKWEIGHT:
00420                         dval = PyFloat_AsDouble(value);
00421                         if (dval < 0.0f || dval > 1.0f) { /* also accounts for non float */
00422                                 PyErr_SetString(PyExc_AttributeError, "constraint.weight = float: BL_ArmatureConstraint, expected a float between 0 and 1");
00423                                 return PY_SET_ATTR_FAIL;
00424                         }
00425                         ikconstraint->weight = dval;
00426                         return PY_SET_ATTR_SUCCESS;
00427 
00428                 case BCA_IKDIST:
00429                         dval = PyFloat_AsDouble(value);
00430                         if (dval < 0.0f) { /* also accounts for non float */
00431                                 PyErr_SetString(PyExc_AttributeError, "constraint.ik_dist = float: BL_ArmatureConstraint, expected a positive float");
00432                                 return PY_SET_ATTR_FAIL;
00433                         }
00434                         ikconstraint->dist = dval;
00435                         return PY_SET_ATTR_SUCCESS;
00436 
00437                 case BCA_IKMODE:
00438                         ival = PyLong_AsLong(value);
00439                         if (ival < 0) {
00440                                 PyErr_SetString(PyExc_AttributeError, "constraint.ik_mode = integer: BL_ArmatureConstraint, expected a positive integer");
00441                                 return PY_SET_ATTR_FAIL;
00442                         }
00443                         ikconstraint->mode = ival;
00444                         return PY_SET_ATTR_SUCCESS;
00445                 }
00446                 // should not come here
00447                 break;
00448 
00449         }
00450 
00451         PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute");
00452         return PY_SET_ATTR_FAIL;
00453 }
00454 
00455 #endif // WITH_PYTHON