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