style cleanup: comment format
[blender.git] / source / gameengine / Converter / BL_ArmatureConstraint.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file gameengine/Converter/BL_ArmatureConstraint.cpp
29  *  \ingroup bgeconv
30  */
31
32
33 #include "DNA_constraint_types.h"
34 #include "DNA_action_types.h"
35 #include "BL_ArmatureConstraint.h"
36 #include "BL_ArmatureObject.h"
37 #include "BLI_math.h"
38 #include "BLI_string.h"
39
40 #ifdef WITH_PYTHON
41
42 PyTypeObject BL_ArmatureConstraint::Type = {
43         PyVarObject_HEAD_INIT(NULL, 0)
44         "BL_ArmatureConstraint",
45         sizeof(PyObjectPlus_Proxy),
46         0,
47         py_base_dealloc,
48         0,
49         0,
50         0,
51         0,
52         py_base_repr,
53         0,0,0,0,0,0,0,0,0,
54         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
55         0,0,0,0,0,0,0,
56         Methods,
57         0,
58         0,
59         &CValue::Type,
60         0,0,0,0,0,0,
61         py_base_new
62 };
63
64 PyObject *BL_ArmatureConstraint::py_repr(void)
65 {
66         return PyUnicode_FromString(m_name);
67 }
68
69 #endif // WITH_PYTHON
70
71 BL_ArmatureConstraint::BL_ArmatureConstraint(
72         BL_ArmatureObject *armature, 
73         bPoseChannel *posechannel,
74         bConstraint *constraint, 
75         KX_GameObject* target,
76         KX_GameObject* subtarget)
77         : PyObjectPlus(), m_constraint(constraint), m_posechannel(posechannel), m_armature(armature)
78 {
79         m_target = target;
80         m_blendtarget = (target) ? target->GetBlenderObject() : NULL;
81         m_subtarget = subtarget;
82         m_blendsubtarget = (subtarget) ? subtarget->GetBlenderObject() : NULL;
83         m_pose = m_subpose = NULL;
84         if (m_blendtarget) {
85                 copy_m4_m4(m_blendmat, m_blendtarget->obmat);
86                 if (m_blendtarget->type == OB_ARMATURE)
87                         m_pose = m_blendtarget->pose;
88         }
89         if (m_blendsubtarget) {
90                 copy_m4_m4(m_blendsubmat, m_blendsubtarget->obmat);
91                 if (m_blendsubtarget->type == OB_ARMATURE)
92                         m_subpose = m_blendsubtarget->pose;
93         }
94         if (m_target)
95                 m_target->RegisterObject(m_armature);
96         if (m_subtarget)
97                 m_subtarget->RegisterObject(m_armature);
98         BLI_snprintf(m_name, sizeof(m_name), "%s:%s", m_posechannel->name, m_constraint->name);
99 }
100
101 BL_ArmatureConstraint::~BL_ArmatureConstraint()
102 {
103         if (m_target)
104                 m_target->UnregisterObject(m_armature);
105         if (m_subtarget)
106                 m_subtarget->UnregisterObject(m_armature);
107 }
108
109 BL_ArmatureConstraint* BL_ArmatureConstraint::GetReplica() const
110 {
111         BL_ArmatureConstraint* replica = new BL_ArmatureConstraint(*this);
112         replica->ProcessReplica();
113         return replica;
114 }
115
116 void BL_ArmatureConstraint::ReParent(BL_ArmatureObject* armature)
117 {
118         m_armature = armature;
119         if (m_target)
120                 m_target->RegisterObject(armature);
121         if (m_subtarget)
122                 m_subtarget->RegisterObject(armature);
123         // find the corresponding constraint in the new armature object
124         if (m_constraint) {
125                 bPose* newpose = armature->GetOrigPose();
126                 char* constraint = m_constraint->name;
127                 char* posechannel = m_posechannel->name;
128                 bPoseChannel* pchan;
129                 bConstraint* pcon;
130                 m_constraint = NULL;
131                 m_posechannel = NULL;
132                 // and locate the constraint
133                 for (pchan = (bPoseChannel*)newpose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) {
134                         if (!strcmp(pchan->name, posechannel)) {
135                                 // now locate the constraint
136                                 for (pcon = (bConstraint*)pchan->constraints.first; pcon; pcon=(bConstraint*)pcon->next) {
137                                         if (!strcmp(pcon->name, constraint)) {
138                                                 m_constraint = pcon;
139                                                 m_posechannel = pchan;
140                                                 break;
141                                         }
142                                 }
143                                 break;
144                         }
145                 }
146         }
147 }
148
149 void BL_ArmatureConstraint::Relink(CTR_Map<CTR_HashedPtr, void*> *obj_map)
150 {
151         void **h_obj = (*obj_map)[m_target];
152         if (h_obj) {
153                 m_target->UnregisterObject(m_armature);
154                 m_target = (KX_GameObject*)(*h_obj);
155                 m_target->RegisterObject(m_armature);
156         }
157         h_obj = (*obj_map)[m_subtarget];
158         if (h_obj) {
159                 m_subtarget->UnregisterObject(m_armature);
160                 m_subtarget = (KX_GameObject*)(*h_obj);
161                 m_subtarget->RegisterObject(m_armature);
162         }
163 }
164
165 bool BL_ArmatureConstraint::UnlinkObject(SCA_IObject* clientobj)
166 {
167         bool res=false;
168         if (clientobj == m_target) {
169                 m_target = NULL;
170                 res = true;
171         }
172         if (clientobj == m_subtarget) {
173                 m_subtarget = NULL;
174                 res = true;
175         }
176         return res;
177 }
178
179 void BL_ArmatureConstraint::UpdateTarget()
180 {
181         if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) {
182                 if (m_blendtarget) {
183                         // external target, must be updated
184                         m_target->UpdateBlenderObjectMatrix(m_blendtarget);
185                         if (m_pose && m_target->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
186                                 // update the pose in case a bone is specified in the constraint target
187                                 m_blendtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose();
188                 }
189                 if (m_blendsubtarget && m_subtarget) {
190                         m_subtarget->UpdateBlenderObjectMatrix(m_blendsubtarget);
191                         if (m_subpose && m_subtarget->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
192                                 m_blendsubtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose();
193                 }
194         }
195 }
196
197 void BL_ArmatureConstraint::RestoreTarget()
198 {
199         if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) {
200                 if (m_blendtarget) {
201                         copy_m4_m4(m_blendtarget->obmat, m_blendmat);
202                         if (m_pose)
203                                 m_blendtarget->pose = m_pose;
204                 }
205                 if (m_blendsubtarget && m_subtarget) {
206                         copy_m4_m4(m_blendsubtarget->obmat, m_blendsubmat);
207                         if (m_subpose)
208                                 m_blendsubtarget->pose = m_subpose;
209                 }
210         }
211 }
212
213 bool BL_ArmatureConstraint::Match(const char* posechannel, const char* constraint)
214 {
215         return (!strcmp(m_posechannel->name, posechannel) && !strcmp(m_constraint->name, constraint));
216 }
217
218 void BL_ArmatureConstraint::SetTarget(KX_GameObject* target)
219 {
220         if (m_blendtarget) {
221                 if (target != m_target) {
222                         m_target->UnregisterObject(m_armature);
223                         m_target = target;
224                         if (m_target)
225                                 m_target->RegisterObject(m_armature);
226                 }
227         }
228
229 }
230
231 void BL_ArmatureConstraint::SetSubtarget(KX_GameObject* subtarget)
232 {
233         if (m_blendsubtarget) {
234                 if (subtarget != m_subtarget) {
235                         m_subtarget->UnregisterObject(m_armature);
236                         m_subtarget = subtarget;
237                         if (m_subtarget)
238                                 m_subtarget->RegisterObject(m_armature);
239                 }
240         }
241
242 }
243
244 #ifdef WITH_PYTHON
245
246 // PYTHON
247
248 PyMethodDef BL_ArmatureConstraint::Methods[] = {
249         {NULL,NULL} //Sentinel
250 };
251
252 // order of definition of attributes, must match Attributes[] array
253 #define BCA_TYPE                0
254 #define BCA_NAME                1
255 #define BCA_ENFORCE             2
256 #define BCA_HEADTAIL    3
257 #define BCA_LINERROR    4
258 #define BCA_ROTERROR    5
259 #define BCA_TARGET              6
260 #define BCA_SUBTARGET   7
261 #define BCA_ACTIVE              8
262 #define BCA_IKWEIGHT    9
263 #define BCA_IKTYPE              10
264 #define BCA_IKFLAG              11
265 #define BCA_IKDIST              12
266 #define BCA_IKMODE              13
267
268 PyAttributeDef BL_ArmatureConstraint::Attributes[] = {
269         // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr
270         KX_PYATTRIBUTE_RO_FUNCTION("type",BL_ArmatureConstraint,py_attr_getattr),
271         KX_PYATTRIBUTE_RO_FUNCTION("name",BL_ArmatureConstraint,py_attr_getattr),
272         KX_PYATTRIBUTE_RW_FUNCTION("enforce",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
273         KX_PYATTRIBUTE_RW_FUNCTION("headtail",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
274         KX_PYATTRIBUTE_RO_FUNCTION("lin_error",BL_ArmatureConstraint,py_attr_getattr),
275         KX_PYATTRIBUTE_RO_FUNCTION("rot_error",BL_ArmatureConstraint,py_attr_getattr),
276         KX_PYATTRIBUTE_RW_FUNCTION("target",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
277         KX_PYATTRIBUTE_RW_FUNCTION("subtarget",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
278         KX_PYATTRIBUTE_RW_FUNCTION("active",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
279         KX_PYATTRIBUTE_RW_FUNCTION("ik_weight",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
280         KX_PYATTRIBUTE_RO_FUNCTION("ik_type",BL_ArmatureConstraint,py_attr_getattr),
281         KX_PYATTRIBUTE_RO_FUNCTION("ik_flag",BL_ArmatureConstraint,py_attr_getattr),
282         KX_PYATTRIBUTE_RW_FUNCTION("ik_dist",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
283         KX_PYATTRIBUTE_RW_FUNCTION("ik_mode",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr),
284         
285         { NULL }        //Sentinel
286 };
287
288
289 PyObject *BL_ArmatureConstraint::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef)
290 {
291         BL_ArmatureConstraint* self = static_cast<BL_ArmatureConstraint*>(self_v);
292         bConstraint* constraint = self->m_constraint;
293         bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL;
294         int attr_order = attrdef-Attributes;
295
296         if (!constraint) {
297                 PyErr_SetString(PyExc_AttributeError, "constraint is NULL");
298                 return NULL;
299         }
300
301         switch (attr_order) {
302         case BCA_TYPE:
303                 return PyLong_FromLong(constraint->type);
304         case BCA_NAME:
305                 return PyUnicode_FromString(constraint->name);
306         case BCA_ENFORCE:
307                 return PyFloat_FromDouble(constraint->enforce);
308         case BCA_HEADTAIL:
309                 return PyFloat_FromDouble(constraint->headtail);
310         case BCA_LINERROR:
311                 return PyFloat_FromDouble(constraint->lin_error);
312         case BCA_ROTERROR:
313                 return PyFloat_FromDouble(constraint->rot_error);
314         case BCA_TARGET:
315                 if (!self->m_target)
316                         Py_RETURN_NONE;
317                 else
318                         return self->m_target->GetProxy();
319         case BCA_SUBTARGET:
320                 if (!self->m_subtarget)
321                         Py_RETURN_NONE;
322                 else
323                         return self->m_subtarget->GetProxy();
324         case BCA_ACTIVE:
325                 return PyBool_FromLong(constraint->flag & CONSTRAINT_OFF);
326         case BCA_IKWEIGHT:
327         case BCA_IKTYPE:
328         case BCA_IKFLAG:
329         case BCA_IKDIST:
330         case BCA_IKMODE:
331                 if (!ikconstraint) {
332                         PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type");
333                         return NULL;
334                 }
335                 switch (attr_order) {
336                 case BCA_IKWEIGHT:
337                         return PyFloat_FromDouble((ikconstraint)?ikconstraint->weight : 0.0f);
338                 case BCA_IKTYPE:
339                         return PyLong_FromLong(ikconstraint->type);
340                 case BCA_IKFLAG:
341                         return PyLong_FromLong(ikconstraint->flag);
342                 case BCA_IKDIST:
343                         return PyFloat_FromDouble(ikconstraint->dist);
344                 case BCA_IKMODE:
345                         return PyLong_FromLong(ikconstraint->mode);
346                 }
347                 // should not come here
348                 break;
349         }
350         PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute");
351         return NULL;
352 }
353
354 int BL_ArmatureConstraint::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
355 {
356         BL_ArmatureConstraint* self = static_cast<BL_ArmatureConstraint*>(self_v);
357         bConstraint* constraint = self->m_constraint;
358         bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL;
359         int attr_order = attrdef-Attributes;
360         int ival;
361         double dval;
362 //      char* sval;
363         KX_GameObject *oval;
364
365         if (!constraint) {
366                 PyErr_SetString(PyExc_AttributeError, "constraint is NULL");
367                 return PY_SET_ATTR_FAIL;
368         }
369         
370         switch (attr_order) {
371         case BCA_ENFORCE:
372                 dval = PyFloat_AsDouble(value);
373                 if (dval < 0.0 || dval > 1.0) { /* also accounts for non float */
374                         PyErr_SetString(PyExc_AttributeError, "constraint.enforce = float: BL_ArmatureConstraint, expected a float between 0 and 1");
375                         return PY_SET_ATTR_FAIL;
376                 }
377                 constraint->enforce = dval;
378                 return PY_SET_ATTR_SUCCESS;
379
380         case BCA_HEADTAIL:
381                 dval = PyFloat_AsDouble(value);
382                 if (dval < 0.0 || dval > 1.0) { /* also accounts for non float */
383                         PyErr_SetString(PyExc_AttributeError, "constraint.headtail = float: BL_ArmatureConstraint, expected a float between 0 and 1");
384                         return PY_SET_ATTR_FAIL;
385                 }
386                 constraint->headtail = dval;
387                 return PY_SET_ATTR_SUCCESS;
388
389         case BCA_TARGET:
390                 if (!ConvertPythonToGameObject(value, &oval, true, "constraint.target = value: BL_ArmatureConstraint"))
391                         return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
392                 self->SetTarget(oval);
393                 return PY_SET_ATTR_SUCCESS;
394
395         case BCA_SUBTARGET:
396                 if (!ConvertPythonToGameObject(value, &oval, true, "constraint.subtarget = value: BL_ArmatureConstraint"))
397                         return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
398                 self->SetSubtarget(oval);
399                 return PY_SET_ATTR_SUCCESS;
400
401         case BCA_ACTIVE:
402                 ival = PyObject_IsTrue( value );
403                 if (ival == -1) {
404                         PyErr_SetString(PyExc_AttributeError, "constraint.active = bool: BL_ArmatureConstraint, expected True or False");
405                         return PY_SET_ATTR_FAIL;
406                 }
407                 self->m_constraint->flag = (self->m_constraint->flag & ~CONSTRAINT_OFF) | ((ival)?0:CONSTRAINT_OFF);
408                 return PY_SET_ATTR_SUCCESS;
409
410         case BCA_IKWEIGHT:
411         case BCA_IKDIST:
412         case BCA_IKMODE:
413                 if (!ikconstraint) {
414                         PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type");
415                         return PY_SET_ATTR_FAIL;
416                 }
417                 switch (attr_order) {
418                 case BCA_IKWEIGHT:
419                         dval = PyFloat_AsDouble(value);
420                         if (dval < 0.0 || dval > 1.0) { /* also accounts for non float */
421                                 PyErr_SetString(PyExc_AttributeError, "constraint.weight = float: BL_ArmatureConstraint, expected a float between 0 and 1");
422                                 return PY_SET_ATTR_FAIL;
423                         }
424                         ikconstraint->weight = dval;
425                         return PY_SET_ATTR_SUCCESS;
426
427                 case BCA_IKDIST:
428                         dval = PyFloat_AsDouble(value);
429                         if (dval < 0.0) {  /* also accounts for non float */
430                                 PyErr_SetString(PyExc_AttributeError, "constraint.ik_dist = float: BL_ArmatureConstraint, expected a positive float");
431                                 return PY_SET_ATTR_FAIL;
432                         }
433                         ikconstraint->dist = dval;
434                         return PY_SET_ATTR_SUCCESS;
435
436                 case BCA_IKMODE:
437                         ival = PyLong_AsLong(value);
438                         if (ival < 0) {
439                                 PyErr_SetString(PyExc_AttributeError, "constraint.ik_mode = integer: BL_ArmatureConstraint, expected a positive integer");
440                                 return PY_SET_ATTR_FAIL;
441                         }
442                         ikconstraint->mode = ival;
443                         return PY_SET_ATTR_SUCCESS;
444                 }
445                 // should not come here
446                 break;
447
448         }
449
450         PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute");
451         return PY_SET_ATTR_FAIL;
452 }
453
454 #endif // WITH_PYTHON