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