Blender V2.61 - r43446

BL_ArmatureChannel.cpp

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include "DNA_armature_types.h"
00034 #include "BL_ArmatureChannel.h"
00035 #include "BL_ArmatureObject.h"
00036 #include "BL_ArmatureConstraint.h"
00037 #include "BLI_math.h"
00038 #include "BLI_string.h"
00039 #include <stddef.h>
00040 
00041 #ifdef WITH_PYTHON
00042 
00043 PyTypeObject BL_ArmatureChannel::Type = {
00044     PyVarObject_HEAD_INIT(NULL, 0)
00045     "BL_ArmatureChannel",
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_ArmatureChannel::py_repr(void)
00066 {
00067     return PyUnicode_FromString(m_posechannel->name);
00068 }
00069 
00070 PyObject *BL_ArmatureChannel::GetProxy()
00071 {
00072     return GetProxyPlus_Ext(this, &Type, m_posechannel);
00073 }
00074 
00075 PyObject *BL_ArmatureChannel::NewProxy(bool py_owns)
00076 {
00077     return NewProxyPlus_Ext(this, &Type, m_posechannel, py_owns);
00078 }
00079 
00080 #endif // WITH_PYTHON
00081 
00082 BL_ArmatureChannel::BL_ArmatureChannel(
00083     BL_ArmatureObject *armature, 
00084     bPoseChannel *posechannel)
00085     : PyObjectPlus(), m_posechannel(posechannel), m_armature(armature)
00086 {
00087 }
00088 
00089 BL_ArmatureChannel::~BL_ArmatureChannel()
00090 {
00091 }
00092 
00093 #ifdef WITH_PYTHON
00094 
00095 // PYTHON
00096 
00097 PyMethodDef BL_ArmatureChannel::Methods[] = {
00098   {NULL,NULL} //Sentinel
00099 };
00100 
00101 // order of definition of attributes, must match Attributes[] array
00102 #define BCA_BONE        0
00103 #define BCA_PARENT      1
00104 
00105 PyAttributeDef BL_ArmatureChannel::Attributes[] = {
00106     // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr
00107     KX_PYATTRIBUTE_RO_FUNCTION("bone",BL_ArmatureChannel,py_attr_getattr),  
00108     KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureChannel,py_attr_getattr),    
00109     
00110     { NULL }    //Sentinel
00111 };
00112 
00113 /* attributes directly taken from bPoseChannel */
00114 PyAttributeDef BL_ArmatureChannel::AttributesPtr[] = {
00115     KX_PYATTRIBUTE_CHAR_RO("name",bPoseChannel,name),
00116     KX_PYATTRIBUTE_FLAG_RO("has_ik",bPoseChannel,flag, POSE_CHAIN),
00117     KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_x",bPoseChannel,ikflag, BONE_IK_NO_XDOF),
00118     KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_y",bPoseChannel,ikflag, BONE_IK_NO_YDOF),
00119     KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_z",bPoseChannel,ikflag, BONE_IK_NO_ZDOF),
00120     KX_PYATTRIBUTE_FLAG_RO("ik_limit_x",bPoseChannel,ikflag, BONE_IK_XLIMIT),
00121     KX_PYATTRIBUTE_FLAG_RO("ik_limit_y",bPoseChannel,ikflag, BONE_IK_YLIMIT),
00122     KX_PYATTRIBUTE_FLAG_RO("ik_limit_z",bPoseChannel,ikflag, BONE_IK_ZLIMIT),
00123     KX_PYATTRIBUTE_FLAG_RO("ik_rot_control",bPoseChannel,ikflag, BONE_IK_ROTCTL),
00124     KX_PYATTRIBUTE_FLAG_RO("ik_lin_control",bPoseChannel,ikflag, BONE_IK_LINCTL),
00125     KX_PYATTRIBUTE_FLOAT_VECTOR_RW("location",-FLT_MAX,FLT_MAX,bPoseChannel,loc,3),
00126     KX_PYATTRIBUTE_FLOAT_VECTOR_RW("scale",-FLT_MAX,FLT_MAX,bPoseChannel,size,3),
00127     KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotation_quaternion",-1.0f,1.0f,bPoseChannel,quat,4),
00128     KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotation_euler",-10.f,10.f,bPoseChannel,eul,3),
00129     KX_PYATTRIBUTE_SHORT_RW("rotation_mode",ROT_MODE_MIN,ROT_MODE_MAX,false,bPoseChannel,rotmode),
00130     KX_PYATTRIBUTE_FLOAT_MATRIX_RO("channel_matrix",bPoseChannel,chan_mat,4),
00131     KX_PYATTRIBUTE_FLOAT_MATRIX_RO("pose_matrix",bPoseChannel,pose_mat,4),
00132     KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_head",bPoseChannel,pose_head,3),
00133     KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_tail",bPoseChannel,pose_tail,3),
00134     KX_PYATTRIBUTE_FLOAT_RO("ik_min_x",bPoseChannel,limitmin[0]),
00135     KX_PYATTRIBUTE_FLOAT_RO("ik_max_x",bPoseChannel,limitmax[0]),
00136     KX_PYATTRIBUTE_FLOAT_RO("ik_min_y",bPoseChannel,limitmin[1]),
00137     KX_PYATTRIBUTE_FLOAT_RO("ik_max_y",bPoseChannel,limitmax[1]),
00138     KX_PYATTRIBUTE_FLOAT_RO("ik_min_z",bPoseChannel,limitmin[2]),
00139     KX_PYATTRIBUTE_FLOAT_RO("ik_max_z",bPoseChannel,limitmax[2]),
00140     KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_x",bPoseChannel,stiffness[0]),
00141     KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_y",bPoseChannel,stiffness[1]),
00142     KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_z",bPoseChannel,stiffness[2]),
00143     KX_PYATTRIBUTE_FLOAT_RO("ik_stretch",bPoseChannel,ikstretch),
00144     KX_PYATTRIBUTE_FLOAT_RW("ik_rot_weight",0,1.0f,bPoseChannel,ikrotweight),
00145     KX_PYATTRIBUTE_FLOAT_RW("ik_lin_weight",0,1.0f,bPoseChannel,iklinweight),
00146     KX_PYATTRIBUTE_RW_FUNCTION("joint_rotation",BL_ArmatureChannel,py_attr_get_joint_rotation,py_attr_set_joint_rotation),
00147     { NULL }    //Sentinel
00148 };
00149 
00150 PyObject* BL_ArmatureChannel::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
00151 {
00152     BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
00153     bPoseChannel* channel = self->m_posechannel;
00154     int attr_order = attrdef-Attributes;
00155 
00156     if (!channel) {
00157         PyErr_SetString(PyExc_AttributeError, "channel is NULL");
00158         return NULL;
00159     }
00160 
00161     switch (attr_order) {
00162     case BCA_BONE:
00163         // bones are standalone proxy
00164         return NewProxyPlus_Ext(NULL,&BL_ArmatureBone::Type,channel->bone,false);
00165     case BCA_PARENT:
00166         {
00167             BL_ArmatureChannel* parent = self->m_armature->GetChannel(channel->parent);
00168             if (parent)
00169                 return parent->GetProxy();
00170             else
00171                 Py_RETURN_NONE;
00172         }
00173     }
00174     PyErr_SetString(PyExc_AttributeError, "channel unknown attribute");
00175     return NULL;
00176 }
00177 
00178 int BL_ArmatureChannel::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00179 {
00180     BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
00181     bPoseChannel* channel = self->m_posechannel;
00182     int attr_order = attrdef-Attributes;
00183 
00184 //  int ival;
00185 //  double dval;
00186 //  char* sval;
00187 //  KX_GameObject *oval;
00188 
00189     if (!channel) {
00190         PyErr_SetString(PyExc_AttributeError, "channel is NULL");
00191         return PY_SET_ATTR_FAIL;
00192     }
00193     
00194     switch (attr_order) {
00195     default:
00196         break;
00197     }
00198 
00199     PyErr_SetString(PyExc_AttributeError, "channel unknown attribute");
00200     return PY_SET_ATTR_FAIL;
00201 }
00202 
00203 PyObject* BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
00204 {
00205     bPoseChannel* pchan = static_cast<bPoseChannel*>(self_v);
00206     // decompose the pose matrix in euler rotation
00207     float rest_mat[3][3];
00208     float pose_mat[3][3];
00209     float joint_mat[3][3];
00210     float joints[3];
00211     float norm;
00212     double sa, ca;
00213     // get rotation in armature space
00214     copy_m3_m4(pose_mat, pchan->pose_mat);
00215     normalize_m3(pose_mat);
00216     if (pchan->parent) {
00217         // bone has a parent, compute the rest pose of the bone taking actual pose of parent
00218         mult_m3_m3m4(rest_mat, pchan->parent->pose_mat, pchan->bone->bone_mat);
00219         normalize_m3(rest_mat);
00220     } else {
00221         // otherwise, the bone matrix in armature space is the rest pose
00222         copy_m3_m4(rest_mat, pchan->bone->arm_mat);
00223     }
00224     // remove the rest pose to get the joint movement
00225     transpose_m3(rest_mat);
00226     mul_m3_m3m3(joint_mat, rest_mat, pose_mat);     
00227     joints[0] = joints[1] = joints[2] = 0.f;
00228     // returns a 3 element list that gives corresponding joint
00229     int flag = 0;
00230     if (!(pchan->ikflag & BONE_IK_NO_XDOF))
00231         flag |= 1;
00232     if (!(pchan->ikflag & BONE_IK_NO_YDOF))
00233         flag |= 2;
00234     if (!(pchan->ikflag & BONE_IK_NO_ZDOF))
00235         flag |= 4;
00236     switch (flag) {
00237     case 0: // fixed joint
00238         break;
00239     case 1: // X only
00240         mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat);
00241         joints[1] = joints[2] = 0.f;
00242         break;
00243     case 2: // Y only
00244         mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat);
00245         joints[0] = joints[2] = 0.f;
00246         break;
00247     case 3: // X+Y
00248         mat3_to_eulO( joints, EULER_ORDER_ZYX,joint_mat);
00249         joints[2] = 0.f;
00250         break;
00251     case 4: // Z only
00252         mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat);
00253         joints[0] = joints[1] = 0.f;
00254         break;
00255     case 5: // X+Z
00256         // decompose this as an equivalent rotation vector in X/Z plane
00257         joints[0] = joint_mat[1][2];
00258         joints[2] = -joint_mat[1][0];
00259         norm = normalize_v3(joints);
00260         if (norm < FLT_EPSILON) {
00261             norm = (joint_mat[1][1] < 0.f) ? M_PI : 0.f;
00262         } else {
00263             norm = acos(joint_mat[1][1]);
00264         }
00265         mul_v3_fl(joints, norm);
00266         break;
00267     case 6: // Y+Z
00268         mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat);
00269         joints[0] = 0.f;
00270         break;
00271     case 7: // X+Y+Z
00272         // equivalent axis
00273         joints[0] = (joint_mat[1][2]-joint_mat[2][1])*0.5f;
00274         joints[1] = (joint_mat[2][0]-joint_mat[0][2])*0.5f;
00275         joints[2] = (joint_mat[0][1]-joint_mat[1][0])*0.5f;
00276         sa = len_v3(joints);
00277         ca = (joint_mat[0][0]+joint_mat[1][1]+joint_mat[1][1]-1.0f)*0.5f;
00278         if (sa > FLT_EPSILON) {
00279             norm = atan2(sa,ca)/sa;
00280         } else {
00281             if (ca < 0.0) {
00282                 norm = M_PI;
00283                 mul_v3_fl(joints,0.f);
00284                 if (joint_mat[0][0] > 0.f) {
00285                     joints[0] = 1.0f;
00286                 } else if (joint_mat[1][1] > 0.f) {
00287                     joints[1] = 1.0f;
00288                 } else {
00289                     joints[2] = 1.0f;
00290                 }
00291             } else {
00292                 norm = 0.0;
00293             }
00294         }
00295         mul_v3_fl(joints,norm);
00296         break;
00297     }
00298     return Vector_CreatePyObject(joints, 3, Py_NEW, NULL);
00299 }
00300 
00301 int BL_ArmatureChannel::py_attr_set_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00302 {
00303     BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
00304     bPoseChannel* pchan = self->m_posechannel;
00305     PyObject *item;
00306     float joints[3];
00307     float quat[4];
00308 
00309     if (!PySequence_Check(value) || PySequence_Size(value) != 3) {
00310         PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats");
00311         return PY_SET_ATTR_FAIL;
00312     }
00313     for (int i=0; i<3; i++) {
00314         item = PySequence_GetItem(value, i); /* new ref */
00315         joints[i] = PyFloat_AsDouble(item);
00316         Py_DECREF(item);
00317         if (joints[i] == -1.0f && PyErr_Occurred()) {
00318             PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats");
00319             return PY_SET_ATTR_FAIL;
00320         }
00321     }
00322 
00323     int flag = 0;
00324     if (!(pchan->ikflag & BONE_IK_NO_XDOF))
00325         flag |= 1;
00326     if (!(pchan->ikflag & BONE_IK_NO_YDOF))
00327         flag |= 2;
00328     if (!(pchan->ikflag & BONE_IK_NO_ZDOF))
00329         flag |= 4;
00330     unit_qt(quat);
00331     switch (flag) {
00332     case 0: // fixed joint
00333         break;
00334     case 1: // X only
00335         joints[1] = joints[2] = 0.f;
00336         eulO_to_quat( quat,joints, EULER_ORDER_XYZ);
00337         break;
00338     case 2: // Y only
00339         joints[0] = joints[2] = 0.f;
00340         eulO_to_quat( quat,joints, EULER_ORDER_XYZ);
00341         break;
00342     case 3: // X+Y
00343         joints[2] = 0.f;
00344         eulO_to_quat( quat,joints, EULER_ORDER_ZYX);
00345         break;
00346     case 4: // Z only
00347         joints[0] = joints[1] = 0.f;
00348         eulO_to_quat( quat,joints, EULER_ORDER_XYZ);
00349         break;
00350     case 5: // X+Z
00351         // X and Z are components of an equivalent rotation axis
00352         joints[1] = 0;
00353         axis_angle_to_quat( quat,joints, len_v3(joints));
00354         break;
00355     case 6: // Y+Z
00356         joints[0] = 0.f;
00357         eulO_to_quat( quat,joints, EULER_ORDER_XYZ);
00358         break;
00359     case 7: // X+Y+Z
00360         // equivalent axis
00361         axis_angle_to_quat( quat,joints, len_v3(joints));
00362         break;
00363     }
00364     if (pchan->rotmode > 0) {
00365         quat_to_eulO( joints, pchan->rotmode,quat);
00366         copy_v3_v3(pchan->eul, joints);
00367     } else
00368         copy_qt_qt(pchan->quat, quat);
00369     return PY_SET_ATTR_SUCCESS;
00370 }
00371 
00372 // *************************
00373 // BL_ArmatureBone
00374 //
00375 // Access to Bone structure
00376 PyTypeObject BL_ArmatureBone::Type = {
00377     PyVarObject_HEAD_INIT(NULL, 0)
00378     "BL_ArmatureBone",
00379     sizeof(PyObjectPlus_Proxy),
00380     0,
00381     py_base_dealloc,
00382     0,
00383     0,
00384     0,
00385     0,
00386     py_bone_repr,
00387     0,0,0,0,0,0,0,0,0,
00388     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00389     0,0,0,0,0,0,0,
00390     Methods,
00391     0,
00392     0,
00393     &CValue::Type,
00394     0,0,0,0,0,0,
00395     py_base_new
00396 };
00397 
00398 // not used since this class is never instantiated
00399 PyObject *BL_ArmatureBone::GetProxy() 
00400 { 
00401     return NULL; 
00402 }
00403 PyObject *BL_ArmatureBone::NewProxy(bool py_owns) 
00404 { 
00405     return NULL; 
00406 }
00407 
00408 PyObject *BL_ArmatureBone::py_bone_repr(PyObject *self)
00409 {
00410     Bone* bone = static_cast<Bone*>BGE_PROXY_PTR(self);
00411     return PyUnicode_FromString(bone->name);
00412 }
00413 
00414 PyMethodDef BL_ArmatureBone::Methods[] = {
00415     {NULL,NULL} //Sentinel
00416 };
00417 
00418 /* no attributes on C++ class since it is never instantiated */
00419 PyAttributeDef BL_ArmatureBone::Attributes[] = {
00420     { NULL }    //Sentinel
00421 };
00422 
00423 // attributes that work on proxy ptr (points to a Bone structure)
00424 PyAttributeDef BL_ArmatureBone::AttributesPtr[] = {
00425     KX_PYATTRIBUTE_CHAR_RO("name",Bone,name),
00426     KX_PYATTRIBUTE_FLAG_RO("connected",Bone,flag, BONE_CONNECTED),
00427     KX_PYATTRIBUTE_FLAG_RO("hinge",Bone,flag, BONE_HINGE),
00428     KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("inherit_scale",Bone,flag, BONE_NO_SCALE),
00429     KX_PYATTRIBUTE_SHORT_RO("bbone_segments",Bone,segments),
00430     KX_PYATTRIBUTE_FLOAT_RO("roll",Bone,roll),
00431     KX_PYATTRIBUTE_FLOAT_VECTOR_RO("head",Bone,head,3),
00432     KX_PYATTRIBUTE_FLOAT_VECTOR_RO("tail",Bone,tail,3),
00433     KX_PYATTRIBUTE_FLOAT_RO("length",Bone,length),
00434     KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_head",Bone,arm_head,3),
00435     KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_tail",Bone,arm_tail,3),
00436     KX_PYATTRIBUTE_FLOAT_MATRIX_RO("arm_mat",Bone,arm_mat,4),
00437     KX_PYATTRIBUTE_FLOAT_MATRIX_RO("bone_mat",Bone,bone_mat,3),
00438     KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureBone,py_bone_get_parent),
00439     KX_PYATTRIBUTE_RO_FUNCTION("children",BL_ArmatureBone,py_bone_get_children),
00440     { NULL }    //Sentinel
00441 };
00442 
00443 PyObject *BL_ArmatureBone::py_bone_get_parent(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
00444 {
00445     Bone* bone = reinterpret_cast<Bone*>(self);
00446     if (bone->parent) {
00447         // create a proxy unconnected to any GE object
00448         return NewProxyPlus_Ext(NULL,&Type,bone->parent,false);
00449     }
00450     Py_RETURN_NONE;
00451 }
00452 
00453 PyObject *BL_ArmatureBone::py_bone_get_children(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
00454 {
00455     Bone* bone = reinterpret_cast<Bone*>(self);
00456     Bone* child;
00457     int count = 0;
00458     for (child=(Bone*)bone->childbase.first; child; child=(Bone*)child->next)
00459         count++;
00460 
00461     PyObject* childrenlist = PyList_New(count);
00462 
00463     for (count = 0, child=(Bone*)bone->childbase.first; child; child=(Bone*)child->next, ++count)
00464         PyList_SET_ITEM(childrenlist,count,NewProxyPlus_Ext(NULL,&Type,child,false));
00465 
00466     return childrenlist;
00467 }
00468 
00469 #endif // WITH_PYTHON