Cleanup & goodies for rigging geeks! :)
[blender.git] / source / blender / src / editconstraint.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <stdio.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39
40 #include "DNA_action_types.h"
41 #include "DNA_armature_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_constraint_types.h"
46 #include "DNA_curve_types.h"
47
48 #include "BKE_utildefines.h"
49 #include "BKE_action.h"
50 #include "BKE_armature.h"
51 #include "BKE_object.h"
52 #include "BKE_global.h"
53 #include "BKE_constraint.h"
54 #include "BKE_ipo.h"
55
56 #include "BIF_editaction.h"
57 #include "BIF_editarmature.h"
58 #include "BIF_editconstraint.h"
59 #include "BIF_interface.h"
60 #include "BIF_screen.h"
61 #include "BIF_toolbox.h"
62
63 #include "blendef.h"
64 #include "nla.h"
65
66
67 /* called by buttons to find a bone to display/edit values for */
68 static bPoseChannel *get_active_posechannel (void)
69 {
70         Object *ob= OBACT;
71         bPoseChannel *pchan;
72         bArmature *arm;
73         
74         arm = get_armature(OBACT);
75         if (!arm)
76                 return NULL;
77         
78         /* find for active */
79         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
80                 if(pchan->bone && (pchan->bone->flag & BONE_ACTIVE))
81                         return pchan;
82         }
83         
84         return NULL;
85 }
86
87
88 ListBase *get_constraint_client_channels (int forcevalid)
89 {
90         Object *ob;
91         char ipstr[64];
92
93         ob=OBACT;
94         
95         if (!ob)
96                 return NULL;
97         
98         /* See if we are a bone constraint */
99         if (ob->flag & OB_POSEMODE) {
100                 bActionChannel *achan;
101                 bPoseChannel *pchan;
102
103                 pchan = get_active_posechannel();
104                 if (pchan) {
105                         
106                         /* Make sure we have an action */
107                         if (!ob->action){
108                                 if (!forcevalid)
109                                         return NULL;
110                                 
111                                 ob->action=add_empty_action();
112                         }
113                         
114                         /* Make sure we have an actionchannel */
115                         achan = get_named_actionchannel(ob->action, pchan->name);
116                         if (!achan){
117                                 if (!forcevalid)
118                                         return NULL;
119                                 
120                                 achan = MEM_callocN (sizeof(bActionChannel), "actionChannel");
121
122                                 strcpy (achan->name, pchan->name);
123                                 sprintf (ipstr, "%s.%s", ob->action->id.name+2, achan->name);
124                                 ipstr[23]=0;
125                                 achan->ipo=     add_ipo(ipstr, ID_AC);  
126                                 
127                                 BLI_addtail (&ob->action->chanbase, achan);
128                         }
129                         
130                         return &achan->constraintChannels;
131                 }
132         }
133         /* else we return object constraints */
134         return &ob->constraintChannels;
135 }
136
137 ListBase *get_constraint_client(char *name, short *clientType, void **clientdata)
138 {
139         Object *ob;
140         ListBase *list;
141
142         ob=OBACT;
143         if (clientType)
144                 *clientType = -1;
145
146         if (!ob)
147                 return NULL;
148
149         list = &ob->constraints;
150
151         /* Prep the object's constraint channels */
152         if (clientType)
153                 *clientType = TARGET_OBJECT;
154         
155         if (name)
156                 strcpy (name, ob->id.name+2);
157
158         if (ob->flag & OB_POSEMODE) {
159                 bPoseChannel *pchan;
160
161                 pchan = get_active_posechannel();
162                 if (pchan) {
163
164                         /* Is the bone the client? */
165                         if (clientType)
166                                 *clientType = TARGET_BONE;
167                         if (clientdata)
168                                 *clientdata = pchan->bone;
169                         if (name)
170                                 sprintf (name, "%s>>%s", name, pchan->name);
171
172                         list = &pchan->constraints;
173                 }
174         }
175
176         return list;
177 }
178
179 bConstraint * add_new_constraint(char type)
180 {
181         bConstraint *con;
182
183         con = MEM_callocN(sizeof(bConstraint), "constraint");
184
185         /* Set up a generic constraint datablock */
186         con->type = type;
187         con->flag |= CONSTRAINT_EXPAND;
188         con->enforce=1.0F;
189         /* Load the data for it */
190         con->data = new_constraint_data(con->type);
191         strcpy (con->name, "Const");
192         return con;
193 }
194
195 void add_constraint_to_object(bConstraint *con, Object *ob)
196 {
197         ListBase *list;
198         list = &ob->constraints;
199         if (list)
200         {
201                 unique_constraint_name(con, list);
202                 BLI_addtail(list, con);
203         }
204 }
205
206 void add_constraint_to_client(bConstraint *con)
207 {
208         ListBase *list;
209         short type;
210         list = get_constraint_client(NULL, &type, NULL);
211         if (list)
212         {
213                 unique_constraint_name(con, list);
214                 BLI_addtail(list, con);
215         }
216 }
217
218 bConstraintChannel *add_new_constraint_channel(const char* name)
219 {
220         bConstraintChannel *chan = NULL;
221
222         chan = MEM_callocN(sizeof(bConstraintChannel), "constraintChannel");
223         strcpy(chan->name, name);
224         
225         return chan;
226 }
227
228 void add_influence_key_to_constraint (bConstraint *con){
229         printf("doesn't do anything yet\n");
230 }
231
232 char *get_con_subtarget_name(bConstraint *constraint, Object *target)
233 {
234         /*
235          * If the target for this constraint is target, return a pointer 
236          * to the name for this constraints subtarget ... NULL otherwise
237          */
238         switch (constraint->type) {
239
240                 case CONSTRAINT_TYPE_ACTION:
241                 {
242                         bActionConstraint *data = constraint->data;
243                         if (data->tar==target) return data->subtarget;
244                 }
245                 break;
246                 case CONSTRAINT_TYPE_LOCLIKE:
247                 {
248                         bLocateLikeConstraint *data = constraint->data;
249                         if (data->tar==target) return data->subtarget;
250                 }
251                 break;
252                 case CONSTRAINT_TYPE_ROTLIKE:
253                 {
254                         bRotateLikeConstraint *data = constraint->data;
255                         if (data->tar==target) return data->subtarget;
256                 }
257                 break;
258                 case CONSTRAINT_TYPE_KINEMATIC:
259                 {
260                         bKinematicConstraint *data = constraint->data;
261                         if (data->tar==target) return data->subtarget;
262                 }
263                 break;
264                 case CONSTRAINT_TYPE_TRACKTO:
265                 {
266                         bTrackToConstraint *data = constraint->data;
267                         if (data->tar==target) return data->subtarget;
268                 }
269                 break;
270                 case CONSTRAINT_TYPE_LOCKTRACK:
271                 {
272                         bLockTrackConstraint *data = constraint->data;
273                         if (data->tar==target) return data->subtarget;
274                 }
275                 break;
276                 case CONSTRAINT_TYPE_STRETCHTO:
277                 {
278                         bStretchToConstraint *data = constraint->data;
279                         if (data->tar==target) return data->subtarget;
280                 }
281                 break;
282                 case CONSTRAINT_TYPE_FOLLOWPATH: 
283                         /* wonder if this is relevent, since this constraint 
284                          * cannot have a subtarget - theeth 
285                          */
286                 {
287                         /*
288                          * bFollowPathConstraint *data = constraint->data;
289                          */
290                         return NULL;
291                 }
292                 break;
293         }
294         
295         return NULL;  
296 }
297
298 /* checks validity of object pointers, and NULLs,
299    if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag */
300 static void test_constraints (Object *owner, const char* substring)
301 {
302         
303         bConstraint *curcon;
304         ListBase *conlist= NULL;
305         int type;
306         
307         if (owner==NULL) return;
308         
309         /* Check parents */
310         /* Get the constraint list for this object */
311         
312         if (strlen (substring)){
313                 switch (owner->type){
314                         case OB_ARMATURE:
315                                 type = TARGET_BONE;
316                                 break;
317                         default:
318                                 type = TARGET_OBJECT;
319                                 break;
320                 }
321         }
322         else
323                 type = TARGET_OBJECT;
324         
325         
326         switch (type){
327                 case TARGET_OBJECT:
328                         conlist = &owner->constraints;
329                         break;
330                 case TARGET_BONE:
331                         {
332                                 Bone *bone;
333                                 bPoseChannel *chan;
334                                 
335                                 bone = get_named_bone(((bArmature*)owner->data), substring);
336                                 chan = get_pose_channel (owner->pose, substring);
337                                 if (bone && chan){
338                                         conlist = &chan->constraints;
339                                 }
340                         }
341                         break;
342         }
343         
344         /* Cycle constraints */
345         if (conlist){
346                 for (curcon = conlist->first; curcon; curcon=curcon->next){
347                         curcon->flag &= ~CONSTRAINT_DISABLE;
348                         
349                         switch (curcon->type){
350                                 case CONSTRAINT_TYPE_ACTION:
351                                 {
352                                         bActionConstraint *data = curcon->data;
353                                         
354                                         if (!exist_object(data->tar)){
355                                                 data->tar = NULL;
356                                                 break;
357                                         }
358                                         
359                                         if ( (data->tar == owner) &&
360                                                  (!get_named_bone(get_armature(owner), 
361                                                                                   data->subtarget))) {
362                                                 curcon->flag |= CONSTRAINT_DISABLE;
363                                                 break;
364                                         }
365                                 }
366                                         break;
367                                 case CONSTRAINT_TYPE_LOCLIKE:
368                                 {
369                                         bLocateLikeConstraint *data = curcon->data;
370                                         
371                                         if (!exist_object(data->tar)){
372                                                 data->tar = NULL;
373                                                 break;
374                                         }
375                                         
376                                         if ( (data->tar == owner) &&
377                                                  (!get_named_bone(get_armature(owner), 
378                                                                                   data->subtarget))) {
379                                                 curcon->flag |= CONSTRAINT_DISABLE;
380                                                 break;
381                                         }
382                                 }
383                                         break;
384                                 case CONSTRAINT_TYPE_ROTLIKE:
385                                 {
386                                         bRotateLikeConstraint *data = curcon->data;
387                                         
388                                         if (!exist_object(data->tar)){
389                                                 data->tar = NULL;
390                                                 break;
391                                         }
392                                         
393                                         if ( (data->tar == owner) &&
394                                                  (!get_named_bone(get_armature(owner), 
395                                                                                   data->subtarget))) {
396                                                 curcon->flag |= CONSTRAINT_DISABLE;
397                                                 break;
398                                         }
399                                 }
400                                         break;
401                                 case CONSTRAINT_TYPE_KINEMATIC:
402                                 {
403                                         bKinematicConstraint *data = curcon->data;
404                                         if (!exist_object(data->tar)){
405                                                 data->tar = NULL;
406                                                 break;
407                                         }
408                                         
409                                         if ( (data->tar == owner) &&
410                                                  (!get_named_bone(get_armature(owner), 
411                                                                                   data->subtarget))) {
412                                                 curcon->flag |= CONSTRAINT_DISABLE;
413                                                 break;
414                                         }
415                                 }
416                                         break;
417                                 case CONSTRAINT_TYPE_TRACKTO:
418                                 {
419                                         bTrackToConstraint *data = curcon->data;
420                                         if (!exist_object(data->tar)) {
421                                                 data->tar = NULL;
422                                                 break;
423                                         }
424                                         
425                                         if ( (data->tar == owner) &&
426                                                  (!get_named_bone(get_armature(owner), 
427                                                                                   data->subtarget))) {
428                                                 curcon->flag |= CONSTRAINT_DISABLE;
429                                                 break;
430                                         }
431                                         if (data->reserved2==data->reserved1){
432                                                 curcon->flag |= CONSTRAINT_DISABLE;
433                                                 break;
434                                         }
435                                         if (data->reserved2+3==data->reserved1){
436                                                 curcon->flag |= CONSTRAINT_DISABLE;
437                                                 break;
438                                         }
439                                 }
440                                         break;
441                                 case CONSTRAINT_TYPE_LOCKTRACK:
442                                 {
443                                         bLockTrackConstraint *data = curcon->data;
444                                         
445                                         if (!exist_object(data->tar)){
446                                                 data->tar = NULL;
447                                                 break;
448                                         }
449                                         
450                                         if ( (data->tar == owner) &&
451                                                  (!get_named_bone(get_armature(owner), 
452                                                                                   data->subtarget))) {
453                                                 curcon->flag |= CONSTRAINT_DISABLE;
454                                                 break;
455                                         }
456
457                                         if (data->lockflag==data->trackflag){
458                                                 curcon->flag |= CONSTRAINT_DISABLE;
459                                                 break;
460                                         }
461                                         if (data->lockflag+3==data->trackflag){
462                                                 curcon->flag |= CONSTRAINT_DISABLE;
463                                                 break;
464                                         }
465                                 }
466                                         break;
467                                 case CONSTRAINT_TYPE_STRETCHTO:
468                                 {
469                                         bStretchToConstraint *data = curcon->data;
470                                         
471                                         if (!exist_object(data->tar)){
472                                                 data->tar = NULL;
473                                                 break;
474                                         }
475                                         
476                                         if ( (data->tar == owner) &&
477                                                  (!get_named_bone(get_armature(owner), 
478                                                                                   data->subtarget))) {
479                                                 curcon->flag |= CONSTRAINT_DISABLE;
480                                                 break;
481                                         }
482                                 }
483                                         break;
484                                 case CONSTRAINT_TYPE_FOLLOWPATH:
485                                 {
486                                         bFollowPathConstraint *data = curcon->data;
487                                         
488                                         if (!exist_object(data->tar)){
489                                                 data->tar = NULL;
490                                                 break;
491                                         }
492                                         if (data->tar->type != OB_CURVE){
493                                                 data->tar = NULL;
494                                                 break;
495                                         }
496                                         if (data->upflag==data->trackflag){
497                                                 curcon->flag |= CONSTRAINT_DISABLE;
498                                                 break;
499                                         }
500                                         if (data->upflag+3==data->trackflag){
501                                                 curcon->flag |= CONSTRAINT_DISABLE;
502                                                 break;
503                                         }
504                                 }
505                                         break;
506                         }
507                 }
508         }
509 }
510
511 static void test_bonelist_constraints (Object *owner, ListBase *list)
512 {
513         Bone *bone;
514
515         for (bone = list->first; bone; bone=bone->next) {
516                 
517                 test_constraints(owner, bone->name);
518                 test_bonelist_constraints (owner, &bone->childbase);
519         }
520 }
521
522 void object_test_constraints (Object *owner)
523 {
524         test_constraints(owner, "");
525
526         if(owner->type==OB_ARMATURE) {
527                 bArmature *arm;
528                 arm = get_armature(owner);
529                 if (arm)
530                         test_bonelist_constraints (owner, &arm->bonebase);
531         }
532
533 }
534
535