own rna naming commits r31439 r31472 also renamed BGE vars unintentionally
[blender.git] / source / gameengine / Converter / BL_ArmatureChannel.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include "DNA_armature_types.h"
30 #include "BL_ArmatureChannel.h"
31 #include "BL_ArmatureObject.h"
32 #include "BL_ArmatureConstraint.h"
33 #include "BLI_math.h"
34 #include "BLI_string.h"
35
36 #ifndef DISABLE_PYTHON
37
38 PyTypeObject BL_ArmatureChannel::Type = {
39         PyVarObject_HEAD_INIT(NULL, 0)
40         "BL_ArmatureChannel",
41         sizeof(PyObjectPlus_Proxy),
42         0,
43         py_base_dealloc,
44         0,
45         0,
46         0,
47         0,
48         py_base_repr,
49         0,0,0,0,0,0,0,0,0,
50         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
51         0,0,0,0,0,0,0,
52         Methods,
53         0,
54         0,
55         &CValue::Type,
56         0,0,0,0,0,0,
57         py_base_new
58 };
59
60 PyObject* BL_ArmatureChannel::py_repr(void)
61 {
62         return PyUnicode_FromString(m_posechannel->name);
63 }
64
65 PyObject *BL_ArmatureChannel::GetProxy()
66 {
67         return GetProxyPlus_Ext(this, &Type, m_posechannel);
68 }
69
70 PyObject *BL_ArmatureChannel::NewProxy(bool py_owns)
71 {
72         return NewProxyPlus_Ext(this, &Type, m_posechannel, py_owns);
73 }
74
75 #endif // DISABLE_PYTHON
76
77 BL_ArmatureChannel::BL_ArmatureChannel(
78         BL_ArmatureObject *armature, 
79         bPoseChannel *posechannel)
80         : PyObjectPlus(), m_posechannel(posechannel), m_armature(armature)
81 {
82 }
83
84 BL_ArmatureChannel::~BL_ArmatureChannel()
85 {
86 }
87
88 #ifndef DISABLE_PYTHON
89
90 // PYTHON
91
92 PyMethodDef BL_ArmatureChannel::Methods[] = {
93   {NULL,NULL} //Sentinel
94 };
95
96 // order of definition of attributes, must match Attributes[] array
97 #define BCA_BONE                0
98 #define BCA_PARENT              1
99
100 PyAttributeDef BL_ArmatureChannel::Attributes[] = {
101         // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr
102         KX_PYATTRIBUTE_RO_FUNCTION("bone",BL_ArmatureChannel,py_attr_getattr),  
103         KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureChannel,py_attr_getattr),        
104         
105         { NULL }        //Sentinel
106 };
107
108 /* attributes directly taken from bPoseChannel */
109 PyAttributeDef BL_ArmatureChannel::AttributesPtr[] = {
110         KX_PYATTRIBUTE_CHAR_RO("name",bPoseChannel,name),
111         KX_PYATTRIBUTE_FLAG_RO("has_ik",bPoseChannel,flag, POSE_CHAIN),
112         KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_x",bPoseChannel,ikflag, BONE_IK_NO_XDOF),
113         KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_y",bPoseChannel,ikflag, BONE_IK_NO_YDOF),
114         KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_z",bPoseChannel,ikflag, BONE_IK_NO_ZDOF),
115         KX_PYATTRIBUTE_FLAG_RO("ik_limit_x",bPoseChannel,ikflag, BONE_IK_XLIMIT),
116         KX_PYATTRIBUTE_FLAG_RO("ik_limit_y",bPoseChannel,ikflag, BONE_IK_YLIMIT),
117         KX_PYATTRIBUTE_FLAG_RO("ik_limit_z",bPoseChannel,ikflag, BONE_IK_ZLIMIT),
118         KX_PYATTRIBUTE_FLAG_RO("ik_rot_control",bPoseChannel,ikflag, BONE_IK_ROTCTL),
119         KX_PYATTRIBUTE_FLAG_RO("ik_lin_control",bPoseChannel,ikflag, BONE_IK_LINCTL),
120         KX_PYATTRIBUTE_FLOAT_VECTOR_RW("location",-FLT_MAX,FLT_MAX,bPoseChannel,loc,3),
121         KX_PYATTRIBUTE_FLOAT_VECTOR_RW("scale",-FLT_MAX,FLT_MAX,bPoseChannel,size,3),
122         KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotation_quaternion",-1.0f,1.0f,bPoseChannel,quat,4),
123         KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotation_euler",-10.f,10.f,bPoseChannel,eul,3),
124         KX_PYATTRIBUTE_SHORT_RW("rotation_mode",0,ROT_MODE_MAX-1,false,bPoseChannel,rotmode),
125         KX_PYATTRIBUTE_FLOAT_MATRIX_RO("channel_matrix",bPoseChannel,chan_mat,4),
126         KX_PYATTRIBUTE_FLOAT_MATRIX_RO("pose_matrix",bPoseChannel,pose_mat,4),
127         KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_head",bPoseChannel,pose_head,3),
128         KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_tail",bPoseChannel,pose_tail,3),
129         KX_PYATTRIBUTE_FLOAT_RO("ik_min_x",bPoseChannel,limitmin[0]),
130         KX_PYATTRIBUTE_FLOAT_RO("ik_max_x",bPoseChannel,limitmax[0]),
131         KX_PYATTRIBUTE_FLOAT_RO("ik_min_y",bPoseChannel,limitmin[1]),
132         KX_PYATTRIBUTE_FLOAT_RO("ik_max_y",bPoseChannel,limitmax[1]),
133         KX_PYATTRIBUTE_FLOAT_RO("ik_min_z",bPoseChannel,limitmin[2]),
134         KX_PYATTRIBUTE_FLOAT_RO("ik_max_z",bPoseChannel,limitmax[2]),
135         KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_x",bPoseChannel,stiffness[0]),
136         KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_y",bPoseChannel,stiffness[1]),
137         KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_z",bPoseChannel,stiffness[2]),
138         KX_PYATTRIBUTE_FLOAT_RO("ik_stretch",bPoseChannel,ikstretch),
139         KX_PYATTRIBUTE_FLOAT_RW("ik_rot_weight",0,1.0f,bPoseChannel,ikrotweight),
140         KX_PYATTRIBUTE_FLOAT_RW("ik_lin_weight",0,1.0f,bPoseChannel,iklinweight),
141         KX_PYATTRIBUTE_RW_FUNCTION("joint_rotation",BL_ArmatureChannel,py_attr_get_joint_rotation,py_attr_set_joint_rotation),
142         { NULL }        //Sentinel
143 };
144
145 PyObject* BL_ArmatureChannel::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
146 {
147         BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
148         bPoseChannel* channel = self->m_posechannel;
149         int attr_order = attrdef-Attributes;
150
151         if (!channel) {
152                 PyErr_SetString(PyExc_AttributeError, "channel is NULL");
153                 return NULL;
154         }
155
156         switch (attr_order) {
157         case BCA_BONE:
158                 // bones are standalone proxy
159                 return NewProxyPlus_Ext(NULL,&BL_ArmatureBone::Type,channel->bone,false);
160         case BCA_PARENT:
161                 {
162                         BL_ArmatureChannel* parent = self->m_armature->GetChannel(channel->parent);
163                         if (parent)
164                                 return parent->GetProxy();
165                         else
166                                 Py_RETURN_NONE;
167                 }
168         }
169         PyErr_SetString(PyExc_AttributeError, "channel unknown attribute");
170         return NULL;
171 }
172
173 int BL_ArmatureChannel::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
174 {
175         BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
176         bPoseChannel* channel = self->m_posechannel;
177         int attr_order = attrdef-Attributes;
178
179 //      int ival;
180 //      double dval;
181 //      char* sval;
182 //      KX_GameObject *oval;
183
184         if (!channel) {
185                 PyErr_SetString(PyExc_AttributeError, "channel is NULL");
186                 return PY_SET_ATTR_FAIL;
187         }
188         
189         switch (attr_order) {
190         default:
191                 break;
192         }
193
194         PyErr_SetString(PyExc_AttributeError, "channel unknown attribute");
195         return PY_SET_ATTR_FAIL;
196 }
197
198 PyObject* BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
199 {
200         bPoseChannel* pchan = static_cast<bPoseChannel*>(self_v);
201         // decompose the pose matrix in euler rotation
202         float rest_mat[3][3];
203         float pose_mat[3][3];
204         float joint_mat[3][3];
205         float joints[3];
206         float norm;
207         double sa, ca;
208         // get rotation in armature space
209         copy_m3_m4(pose_mat, pchan->pose_mat);
210         normalize_m3(pose_mat);
211         if (pchan->parent) {
212                 // bone has a parent, compute the rest pose of the bone taking actual pose of parent
213                 mul_m3_m3m4(rest_mat, pchan->bone->bone_mat, pchan->parent->pose_mat);
214                 normalize_m3(rest_mat);
215         } else {
216                 // otherwise, the bone matrix in armature space is the rest pose
217                 copy_m3_m4(rest_mat, pchan->bone->arm_mat);
218         }
219         // remove the rest pose to get the joint movement
220         transpose_m3(rest_mat);
221         mul_m3_m3m3(joint_mat, rest_mat, pose_mat);             
222         joints[0] = joints[1] = joints[2] = 0.f;
223         // returns a 3 element list that gives corresponding joint
224         int flag = 0;
225         if (!(pchan->ikflag & BONE_IK_NO_XDOF))
226                 flag |= 1;
227         if (!(pchan->ikflag & BONE_IK_NO_YDOF))
228                 flag |= 2;
229         if (!(pchan->ikflag & BONE_IK_NO_ZDOF))
230                 flag |= 4;
231         switch (flag) {
232         case 0: // fixed joint
233                 break;
234         case 1: // X only
235                 mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat);
236                 joints[1] = joints[2] = 0.f;
237                 break;
238         case 2: // Y only
239                 mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat);
240                 joints[0] = joints[2] = 0.f;
241                 break;
242         case 3: // X+Y
243                 mat3_to_eulO( joints, EULER_ORDER_ZYX,joint_mat);
244                 joints[2] = 0.f;
245                 break;
246         case 4: // Z only
247                 mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat);
248                 joints[0] = joints[1] = 0.f;
249                 break;
250         case 5: // X+Z
251                 // decompose this as an equivalent rotation vector in X/Z plane
252                 joints[0] = joint_mat[1][2];
253                 joints[2] = -joint_mat[1][0];
254                 norm = normalize_v3(joints);
255                 if (norm < FLT_EPSILON) {
256                         norm = (joint_mat[1][1] < 0.f) ? M_PI : 0.f;
257                 } else {
258                         norm = acos(joint_mat[1][1]);
259                 }
260                 mul_v3_fl(joints, norm);
261                 break;
262         case 6: // Y+Z
263                 mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat);
264                 joints[0] = 0.f;
265                 break;
266         case 7: // X+Y+Z
267                 // equivalent axis
268                 joints[0] = (joint_mat[1][2]-joint_mat[2][1])*0.5f;
269                 joints[1] = (joint_mat[2][0]-joint_mat[0][2])*0.5f;
270                 joints[2] = (joint_mat[0][1]-joint_mat[1][0])*0.5f;
271                 sa = len_v3(joints);
272                 ca = (joint_mat[0][0]+joint_mat[1][1]+joint_mat[1][1]-1.0f)*0.5f;
273                 if (sa > FLT_EPSILON) {
274                         norm = atan2(sa,ca)/sa;
275                 } else {
276                    if (ca < 0.0) {
277                            norm = M_PI;
278                            mul_v3_fl(joints,0.f);
279                            if (joint_mat[0][0] > 0.f) {
280                                    joints[0] = 1.0f;
281                            } else if (joint_mat[1][1] > 0.f) {
282                                    joints[1] = 1.0f;
283                            } else {
284                                    joints[2] = 1.0f;
285                            }
286                    } else {
287                            norm = 0.0;
288                    }
289                 }
290                 mul_v3_fl(joints,norm);
291                 break;
292         }
293         return newVectorObject(joints, 3, Py_NEW, NULL);
294 }
295
296 int BL_ArmatureChannel::py_attr_set_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
297 {
298         BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v);
299         bPoseChannel* pchan = self->m_posechannel;
300         PyObject *item;
301         float joints[3];
302         float quat[4];
303
304         if (!PySequence_Check(value) || PySequence_Size(value) != 3) {
305                 PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats");
306                 return PY_SET_ATTR_FAIL;
307         }
308         for (int i=0; i<3; i++) {
309                 item = PySequence_GetItem(value, i); /* new ref */
310                 joints[i] = PyFloat_AsDouble(item);
311                 Py_DECREF(item);
312                 if (joints[i] == -1.0f && PyErr_Occurred()) {
313                         PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats");
314                         return PY_SET_ATTR_FAIL;
315                 }
316         }
317
318         int flag = 0;
319         if (!(pchan->ikflag & BONE_IK_NO_XDOF))
320                 flag |= 1;
321         if (!(pchan->ikflag & BONE_IK_NO_YDOF))
322                 flag |= 2;
323         if (!(pchan->ikflag & BONE_IK_NO_ZDOF))
324                 flag |= 4;
325         unit_qt(quat);
326         switch (flag) {
327         case 0: // fixed joint
328                 break;
329         case 1: // X only
330                 joints[1] = joints[2] = 0.f;
331                 eulO_to_quat( quat,joints, EULER_ORDER_XYZ);
332                 break;
333         case 2: // Y only
334                 joints[0] = joints[2] = 0.f;
335                 eulO_to_quat( quat,joints, EULER_ORDER_XYZ);
336                 break;
337         case 3: // X+Y
338                 joints[2] = 0.f;
339                 eulO_to_quat( quat,joints, EULER_ORDER_ZYX);
340                 break;
341         case 4: // Z only
342                 joints[0] = joints[1] = 0.f;
343                 eulO_to_quat( quat,joints, EULER_ORDER_XYZ);
344                 break;
345         case 5: // X+Z
346                 // X and Z are components of an equivalent rotation axis
347                 joints[1] = 0;
348                 axis_angle_to_quat( quat,joints, len_v3(joints));
349                 break;
350         case 6: // Y+Z
351                 joints[0] = 0.f;
352                 eulO_to_quat( quat,joints, EULER_ORDER_XYZ);
353                 break;
354         case 7: // X+Y+Z
355                 // equivalent axis
356                 axis_angle_to_quat( quat,joints, len_v3(joints));
357                 break;
358         }
359         if (pchan->rotmode > 0) {
360                 quat_to_eulO( joints, pchan->rotmode,quat);
361                 copy_v3_v3(pchan->eul, joints);
362         } else
363                 copy_qt_qt(pchan->quat, quat);
364         return PY_SET_ATTR_SUCCESS;
365 }
366
367 // *************************
368 // BL_ArmatureBone
369 //
370 // Access to Bone structure
371 PyTypeObject BL_ArmatureBone::Type = {
372         PyVarObject_HEAD_INIT(NULL, 0)
373         "BL_ArmatureBone",
374         sizeof(PyObjectPlus_Proxy),
375         0,
376         py_base_dealloc,
377         0,
378         0,
379         0,
380         0,
381         py_bone_repr,
382         0,0,0,0,0,0,0,0,0,
383         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
384         0,0,0,0,0,0,0,
385         Methods,
386         0,
387         0,
388         &CValue::Type,
389         0,0,0,0,0,0,
390         py_base_new
391 };
392
393 // not used since this class is never instantiated
394 PyObject *BL_ArmatureBone::GetProxy() 
395
396         return NULL; 
397 }
398 PyObject *BL_ArmatureBone::NewProxy(bool py_owns) 
399
400         return NULL; 
401 }
402
403 PyObject *BL_ArmatureBone::py_bone_repr(PyObject *self)
404 {
405         Bone* bone = static_cast<Bone*>BGE_PROXY_PTR(self);
406         return PyUnicode_FromString(bone->name);
407 }
408
409 PyMethodDef BL_ArmatureBone::Methods[] = {
410         {NULL,NULL} //Sentinel
411 };
412
413 /* no attributes on C++ class since it is never instantiated */
414 PyAttributeDef BL_ArmatureBone::Attributes[] = {
415         { NULL }        //Sentinel
416 };
417
418 // attributes that work on proxy ptr (points to a Bone structure)
419 PyAttributeDef BL_ArmatureBone::AttributesPtr[] = {
420         KX_PYATTRIBUTE_CHAR_RO("name",Bone,name),
421         KX_PYATTRIBUTE_FLAG_RO("connected",Bone,flag, BONE_CONNECTED),
422         KX_PYATTRIBUTE_FLAG_RO("hinge",Bone,flag, BONE_HINGE),
423         KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("inherit_scale",Bone,flag, BONE_NO_SCALE),
424         KX_PYATTRIBUTE_SHORT_RO("bbone_segments",Bone,segments),
425         KX_PYATTRIBUTE_FLOAT_RO("roll",Bone,roll),
426         KX_PYATTRIBUTE_FLOAT_VECTOR_RO("head",Bone,head,3),
427         KX_PYATTRIBUTE_FLOAT_VECTOR_RO("tail",Bone,tail,3),
428         KX_PYATTRIBUTE_FLOAT_RO("length",Bone,length),
429         KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_head",Bone,arm_head,3),
430         KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_tail",Bone,arm_tail,3),
431         KX_PYATTRIBUTE_FLOAT_MATRIX_RO("arm_mat",Bone,arm_mat,4),
432         KX_PYATTRIBUTE_FLOAT_MATRIX_RO("bone_mat",Bone,bone_mat,4),
433         KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureBone,py_bone_get_parent),
434         KX_PYATTRIBUTE_RO_FUNCTION("children",BL_ArmatureBone,py_bone_get_children),
435         { NULL }        //Sentinel
436 };
437
438 PyObject *BL_ArmatureBone::py_bone_get_parent(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
439 {
440         Bone* bone = reinterpret_cast<Bone*>(self);
441         if (bone->parent) {
442                 // create a proxy unconnected to any GE object
443                 return NewProxyPlus_Ext(NULL,&Type,bone->parent,false);
444         }
445         Py_RETURN_NONE;
446 }
447
448 PyObject *BL_ArmatureBone::py_bone_get_children(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
449 {
450         Bone* bone = reinterpret_cast<Bone*>(self);
451         Bone* child;
452         int count = 0;
453         for (child=(Bone*)bone->childbase.first; child; child=(Bone*)child->next)
454                 count++;
455
456         PyObject* childrenlist = PyList_New(count);
457
458         for (count = 0, child=(Bone*)bone->childbase.first; child; child=(Bone*)child->next, ++count)
459                 PyList_SET_ITEM(childrenlist,count,NewProxyPlus_Ext(NULL,&Type,child,false));
460
461         return childrenlist;
462 }
463
464 #endif // DISABLE_PYTHON