All constraints (except FollowPath) now check if subtarget (bone) is valid and disabl...
[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_editarmature.h"
57 #include "BIF_editconstraint.h"
58 #include "BIF_interface.h"
59 #include "BIF_screen.h"
60 #include "BIF_toolbox.h"
61
62 #include "BSE_editaction.h"
63
64 #include "blendef.h"
65 #include "nla.h"
66
67 #ifdef HAVE_CONFIG_H
68 #include <config.h>
69 #endif
70
71 static short add_constraint_element (Object *owner, const char *substring, Object *parent, const char *parentstring);
72 static short detect_constraint_loop (Object *owner, const char* substring, int disable, char type);
73 static void test_bonelist_constraints (Object *owner, ListBase *list);
74 static void clear_object_constraint_loop_flags(Object *ob);
75 //static int is_child_of(struct Object *owner, struct Object *parent);
76 //static int is_bonechild_of(struct Bone *bone, struct Bone *parent);
77 static int is_child_of_ex(Object *owner, const char *ownersubstr, Object *parent, const char *parsubstr);
78
79 ListBase g_conBase;
80 const char *g_conString;
81 Object *g_conObj;
82
83
84 static int is_child_of_ex(Object *owner, const char *ownersubstr, Object *parent, const char *parsubstr)
85 {
86         Object *curob;
87         Bone *bone = NULL;
88         Bone *parbone= NULL;
89
90         curob=owner;
91
92         /* If this is a bone */
93         if (strlen(ownersubstr))
94                 bone = get_named_bone(get_armature(owner->parent), ownersubstr);
95         
96         if (strlen(parsubstr))
97                 parbone = get_named_bone(get_armature(parent), parsubstr);
98
99
100         /* Traverse the scene graph */
101         while (curob && !bone){
102                 switch (curob->partype){
103                 case PARBONE:
104                         if (strlen(parsubstr)){
105                                 bone = get_named_bone(get_armature(curob->parent), curob->parsubstr);
106                                 break;
107                         }
108                         /* The break is supposed to be missing */
109                 default:
110                         if (curob==parent){
111                                 if (parbone)
112                                         return 0;
113                                 else
114                                         return 1;
115                         }
116                 }
117                 curob=curob->parent;
118         }
119
120
121         /* Descend into the armature scene graph */
122         while (bone){
123                 if (bone==parbone)
124                         return 1;
125                 bone=bone->parent;
126         }
127         
128         return 0;
129 }
130 /*
131 static int is_child_of(Object *owner, Object *parent)
132 {
133         Object *curpar;
134
135         for (curpar = owner->parent; curpar; curpar=curpar->parent){
136                 if (curpar==parent)
137                         return 1;
138         }
139
140         return 0;
141 }
142
143
144 static int is_bonechild_of(Bone *bone, Bone *parent)
145 {
146         Bone *curpar;
147
148         if (!bone)
149                 return 0;
150
151         for (curpar = bone->parent; curpar; curpar=curpar->parent){
152                 if (curpar==parent)
153                         return 1;
154         }
155         return 0;
156 }
157 */
158 static short add_constraint_element (Object *owner, const char *substring, Object *parent, const char *parentstring)
159 {
160         
161         if (!owner)
162                 return 0;
163
164         /* See if this is the original object */
165         if (parent == owner){
166                 if (!strcmp (parentstring, substring))
167                                 return 1;
168         }
169
170         if (owner == g_conObj){
171                 if (!strcmp (g_conString, substring))
172                         return 1;
173         }
174
175         /* See if this is a child of the adding object */
176         if (parent){
177 //              if (is_child_of (owner, parent))
178                 if (is_child_of_ex (owner, substring, parent, parentstring))
179                         return 1;
180                 /* Parent is a bone */
181 /*              if ((owner==parent) && (owner->type == OB_ARMATURE)){
182                         if (strlen (substring) && strlen(parentstring)){
183                                 if (is_bonechild_of(get_named_bone(owner->data, substring), get_named_bone(parent->data, parentstring)))
184                                         return 1;
185                         }
186                 }
187                 */
188         }
189         return 0;
190 }
191
192 static void test_bonelist_constraints (Object *owner, ListBase *list)
193 {
194         Bone *bone;
195         Base    *base1;
196
197
198         for (bone = list->first; bone; bone=bone->next){
199                 for (base1 = G.scene->base.first; base1; base1=base1->next){
200                         clear_object_constraint_loop_flags(base1->object);
201                 }
202                 test_constraints(owner, bone->name, 1);
203                 test_bonelist_constraints (owner, &bone->childbase);
204         }
205 }
206
207
208 static void clear_object_constraint_loop_flags(Object *ob)
209 {
210         bConstraint *con;
211
212         if (!ob)
213                 return;
214
215         /* Test object constraints */
216         for (con = ob->constraints.first; con; con=con->next){
217                 con->flag &= ~CONSTRAINT_LOOPTESTED;
218         }
219
220         switch (ob->type){
221         case OB_ARMATURE:
222                 if (ob->pose){
223                         bPoseChannel *pchan;
224                         for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next){
225                                 for (con = pchan->constraints.first; con; con=con->next){
226                                         con->flag &= ~CONSTRAINT_LOOPTESTED;
227                                 }
228                         }
229                 }
230                 break;
231         default:
232                 break;
233         }
234 }
235 void test_scene_constraints (void)
236 {
237         Base *base, *base1;
238
239 /*      Clear the "done" flags of all constraints */
240
241         for (base = G.scene->base.first; base; base=base->next){
242                 clear_object_constraint_loop_flags(base->object);
243         }
244
245         /*      Test all constraints */
246         for (base = G.scene->base.first; base; base=base->next){
247                 /* Test the object */
248                 
249                 for (base1 = G.scene->base.first; base1; base1=base1->next)
250                         clear_object_constraint_loop_flags(base1->object);
251                 
252
253                 test_constraints (base->object, "", 1);
254
255         
256                 /* Test the subobject constraints */
257                 switch (base->object->type){
258                 case OB_ARMATURE:
259                         {
260                                 bArmature *arm;
261                                 arm = get_armature(base->object);
262                                 if (arm)
263                                         test_bonelist_constraints (base->object, &arm->bonebase);
264                         }
265                         break;
266                 default:
267                         break;
268                 }
269
270
271         }
272 }
273
274 int test_constraints (Object *owner, const char *substring, int disable)
275 {
276 /*      init_constraint_elements();*/
277         g_conObj = owner;
278         g_conString = substring;
279
280         if (detect_constraint_loop (owner, substring, disable, 0))
281                 return 1;
282         else
283                 return 0;
284
285 /*      free_constraint_elements();     */
286 }
287
288 static short detect_constraint_loop (Object *owner, const char* substring, int disable, char typefrom)
289 {
290
291         bConstraint *curcon;
292         ListBase *conlist;
293         int             type;
294         int             result = 0;
295
296         if (!owner)
297                 return result;
298
299         /* Check parents */
300         /* Get the constraint list for this object */
301
302         if (strlen (substring)){
303                 switch (owner->type){
304                 case OB_ARMATURE:
305                         type = TARGET_BONE;
306                         break;
307                 default:
308                         type = TARGET_OBJECT;
309                         break;
310                 }
311         }
312         else
313                 type = TARGET_OBJECT;
314
315
316         switch (type){
317         case TARGET_OBJECT:
318                 conlist = &owner->constraints;
319                 /* Check parents */
320 #if 0
321                 if (owner->parent && (ELEM (owner->partype, PAROBJECT, PARBONE))){
322                         if (add_constraint_element (owner->parent, "", NULL, NULL)){
323                                 return 1;
324                         }
325                 /*      if (detect_constraint_loop (owner->parent, "", disable)){
326                                 return 1;
327                         }
328                 */
329                 }
330                 /* Check tracking */
331                 if (owner->track && (ELEM (owner->partype, PAROBJECT, PARBONE))){
332                         if (add_constraint_element (owner->track, "", NULL, NULL)){
333                                 return 1;
334                         }
335                 /*      if (detect_constraint_loop (owner->track, "", disable)){
336                                 return 1;
337                         }
338                 */
339                 }
340 #else
341                 if (owner->parent && (owner->partype==PAROBJECT))
342                         if (add_constraint_element (owner->parent, "", NULL, NULL))
343                                 return 1;
344
345                 if (owner->parent && (owner->partype==PARBONE))
346                         if (add_constraint_element (owner->parent, owner->parsubstr, NULL, NULL))
347                                 return 1;
348
349                 /* Check tracking */
350                 if (owner->track)
351                         if (add_constraint_element (owner->track, "", NULL, NULL))
352                                 return 1;
353 #endif
354
355                 break;
356         case TARGET_BONE:
357                 {
358                         Bone *bone;
359                         bPoseChannel *chan;
360
361                         bone = get_named_bone(((bArmature*)owner->data), substring);
362                         chan = get_pose_channel (owner->pose, substring);
363                         if (bone){
364                                 conlist = &chan->constraints;
365                                 if (bone->parent){
366                                         if (add_constraint_element (owner, bone->parent->name, NULL, NULL))
367                                                 return 1;
368                                         if (detect_constraint_loop (owner, bone->parent->name, disable, 0))
369                                                 return 1;
370                                 }
371                                 else{
372                                         if (add_constraint_element (owner, "", NULL, NULL))
373                                                 return 1;
374                                         if (detect_constraint_loop (owner, "", disable, 0))
375                                                 return 1;
376                                 }
377                         }
378                         else
379                                 conlist = NULL;
380                 }
381                 break;
382         default:
383                 conlist = NULL;
384                 break;
385         }
386         
387         /* Cycle constraints */
388         if (conlist){
389                 for (curcon = conlist->first; curcon; curcon=curcon->next){
390                         
391                         /* Clear the disable flag */
392                         
393                         if (curcon->flag & CONSTRAINT_LOOPTESTED){
394                                 return 0;
395                         }
396                         else {
397                                 curcon->flag &= ~CONSTRAINT_DISABLE;
398                                 curcon->flag |= CONSTRAINT_LOOPTESTED;
399                                 switch (curcon->type){
400                                 case CONSTRAINT_TYPE_ACTION:
401                                         {
402                                                 bActionConstraint *data = curcon->data;
403
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                                                         result = 1;
414                                                         break;
415                                                 }
416                                                 if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
417                                                         curcon->flag |= CONSTRAINT_DISABLE;
418                                                         result = 1;
419                                                         break;
420                                                         //              return 1;
421                                                 }
422                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_ACTION)){
423                                                         curcon->flag |= CONSTRAINT_DISABLE;
424                                                         result = 1;
425                                                         break;
426                                                         //              return 1;
427                                                 }
428                                         }
429                                         break;
430                                 case CONSTRAINT_TYPE_LOCLIKE:
431                                         {
432                                                 bLocateLikeConstraint *data = curcon->data;
433                                         
434                                                 if (!exist_object(data->tar)){
435                                                         data->tar = NULL;
436                                                         break;
437                                                 }
438                                                 
439                                                 if ( (data->tar == owner) &&
440                                                          (!get_named_bone(get_armature(owner), 
441                                                                                           data->subtarget))) {
442                                                         curcon->flag |= CONSTRAINT_DISABLE;
443                                                         result = 1;
444                                                         break;
445                                                 }
446                                                 if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
447                                                         curcon->flag |= CONSTRAINT_DISABLE;
448                                                         result = 1;
449                                                         break;
450                                                         //              return 1;
451                                                 }
452                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_LOCLIKE)){
453                                                         curcon->flag |= CONSTRAINT_DISABLE;
454                                                         result = 1;
455                                                         break;
456                                                         //              return 1;
457                                                 }
458                                         }
459                                         break;
460                                 case CONSTRAINT_TYPE_ROTLIKE:
461                                         {
462                                                 bRotateLikeConstraint *data = curcon->data;
463                                         
464                                                 if (!exist_object(data->tar)){
465                                                         data->tar = NULL;
466                                                         break;
467                                                 }
468                                                 
469                                                 if ( (data->tar == owner) &&
470                                                          (!get_named_bone(get_armature(owner), 
471                                                                                           data->subtarget))) {
472                                                         curcon->flag |= CONSTRAINT_DISABLE;
473                                                         result = 1;
474                                                         break;
475                                                 }
476                                                 if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
477                                                         curcon->flag |= CONSTRAINT_DISABLE;
478                                                         result = 1;
479                                                         break;
480                                                         //              return 1;
481                                                 }
482                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_ROTLIKE)){
483                                                         curcon->flag |= CONSTRAINT_DISABLE;
484                                                         result = 1;
485                                                         break;
486                                                         //              return 1;
487                                                 }
488                                         }
489                                         break;
490                                 case CONSTRAINT_TYPE_KINEMATIC:
491                                         {
492                                                 bKinematicConstraint *data = curcon->data;
493                                                 if (!exist_object(data->tar)){
494                                                         data->tar = NULL;
495                                                         break;
496                                                 }
497
498                                                 if ( (data->tar == owner) &&
499                                                          (!get_named_bone(get_armature(owner), 
500                                                                                           data->subtarget))) {
501                                                         curcon->flag |= CONSTRAINT_DISABLE;
502                                                         result = 1;
503                                                         break;
504                                                 }
505                                                 if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
506                                                         curcon->flag |= CONSTRAINT_DISABLE;
507                                                         result = 1;
508                                                         break;
509                                                         //      return 1;
510                                                 }
511                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_KINEMATIC)){
512                                                         curcon->flag |= CONSTRAINT_DISABLE;
513                                                         result = 1;
514                                                         break;
515                                                         //              return 1;
516                                                 }
517                                         }
518                                         break;
519                                 case CONSTRAINT_TYPE_TRACKTO:
520                                         {
521                                                 bTrackToConstraint *data = curcon->data;
522                                                 if (!exist_object(data->tar)) {
523                                                         data->tar = NULL;
524                                                         break;
525                                                 }
526                                                 
527                                                 if ( (data->tar == owner) &&
528                                                          (!get_named_bone(get_armature(owner), 
529                                                                                           data->subtarget))) {
530                                                         curcon->flag |= CONSTRAINT_DISABLE;
531                                                         result = 1;
532                                                         break;
533                                                 }
534                                                 if (typefrom != CONSTRAINT_TYPE_TRACKTO && typefrom != CONSTRAINT_TYPE_LOCKTRACK){
535                                                         if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
536                                                                 curcon->flag |= CONSTRAINT_DISABLE;
537                                                                 result = 1;
538                                                                 break;
539                                                                 //      return 1;
540                                                         }
541                                                 }
542                                                 else {
543                                                         curcon->flag |= CONSTRAINT_NOREFRESH;
544                                                 }
545
546                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_TRACKTO)){
547                                                         curcon->flag |= CONSTRAINT_DISABLE;
548                                                         result = 1;
549                                                         break;
550                                                         //              return 1;
551                                                 }
552                                                 if (data->reserved2==data->reserved1){
553                                                         curcon->flag |= CONSTRAINT_DISABLE;
554                                                         result = 1;
555                                                         break;
556                                                         //              return 1;
557                                                 }
558                                                 if (data->reserved2+3==data->reserved1){
559                                                         curcon->flag |= CONSTRAINT_DISABLE;
560                                                         result = 1;
561                                                         break;
562                                                         //              return 1;
563                                                 }
564                                         }
565                                         break;
566                                 case CONSTRAINT_TYPE_LOCKTRACK:
567                                         {
568                                                 bLockTrackConstraint *data = curcon->data;
569                                         
570                                                 if (!exist_object(data->tar)){
571                                                         data->tar = NULL;
572                                                         break;
573                                                 }
574                                                 
575                                                 if ( (data->tar == owner) &&
576                                                          (!get_named_bone(get_armature(owner), 
577                                                                                           data->subtarget))) {
578                                                         curcon->flag |= CONSTRAINT_DISABLE;
579                                                         result = 1;
580                                                         break;
581                                                 }
582                                                 if (typefrom != CONSTRAINT_TYPE_TRACKTO && typefrom != CONSTRAINT_TYPE_LOCKTRACK){
583                                                         if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
584                                                                 curcon->flag |= CONSTRAINT_DISABLE;
585                                                                 result = 1;
586                                                                 break;
587                                                                 //              return 1;
588                                                         }
589                                                 }
590                                                 else {
591                                                         curcon->flag |= CONSTRAINT_NOREFRESH;
592                                                 }
593
594                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_LOCKTRACK)){
595                                                         curcon->flag |= CONSTRAINT_DISABLE;
596                                                         result = 1;
597                                                         break;
598                                                         //              return 1;
599                                                 }
600                                                 if (data->lockflag==data->trackflag){
601                                                         curcon->flag |= CONSTRAINT_DISABLE;
602                                                         result = 1;
603                                                         break;
604                                                         //              return 1;
605                                                 }
606                                                 if (data->lockflag+3==data->trackflag){
607                                                         curcon->flag |= CONSTRAINT_DISABLE;
608                                                         result = 1;
609                                                         break;
610                                                         //              return 1;
611                                                 }
612                                         }
613                                         break;
614                                 case CONSTRAINT_TYPE_STRETCHTO:
615                                         {
616                                                 bStretchToConstraint *data = curcon->data;
617                                         
618                                                 if (!exist_object(data->tar)){
619                                                         data->tar = NULL;
620                                                         break;
621                                                 }
622
623                                                 if ( (data->tar == owner) &&
624                                                          (!get_named_bone(get_armature(owner), 
625                                                                                           data->subtarget))) {
626                                                         curcon->flag |= CONSTRAINT_DISABLE;
627                                                         result = 1;
628                                                         break;
629                                                 }
630                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_LOCKTRACK)){
631                                                         curcon->flag |= CONSTRAINT_DISABLE;
632                                                         result = 1;
633                                                         break;
634                                                         //              return 1;
635                                                 }
636                                         }
637                                         break;
638                                 case CONSTRAINT_TYPE_FOLLOWPATH:
639                                         {
640                                                 bFollowPathConstraint *data = curcon->data;
641                                         
642                                                 if (!exist_object(data->tar)){
643                                                         data->tar = NULL;
644                                                         break;
645                                                 }
646                                                 if (data->tar->type != OB_CURVE){
647                                                         data->tar = NULL;
648                                                         break;
649                                                 }
650                                                 if (add_constraint_element (data->tar, "", owner, substring)){
651                                                         curcon->flag |= CONSTRAINT_DISABLE;
652                                                         result = 1;
653                                                         break;
654                                                         //              return 1;
655                                                 }
656                                                 if (detect_constraint_loop (data->tar, "", disable, CONSTRAINT_TYPE_FOLLOWPATH)){
657                                                         curcon->flag |= CONSTRAINT_DISABLE;
658                                                         result = 1;
659                                                         break;
660                                                         //              return 1;
661                                                 }
662                                                 if (data->upflag==data->trackflag){
663                                                         curcon->flag |= CONSTRAINT_DISABLE;
664                                                         result = 1;
665                                                         break;
666                                                         //              return 1;
667                                                 }
668                                                 if (data->upflag+3==data->trackflag){
669                                                         curcon->flag |= CONSTRAINT_DISABLE;
670                                                         result = 1;
671                                                         break;
672                                                         //              return 1;
673                                                 }
674                                         }
675                                         break;
676                                 }
677                         }
678                 }
679         }
680         
681         return result;
682 }
683
684 ListBase *get_constraint_client_channels (int forcevalid)
685 {
686
687         Object *ob;
688         char ipstr[64];
689
690         ob=OBACT;
691         
692         if (!ob)
693                 return NULL;
694         
695         /* See if we are a bone constraint */
696         if (G.obpose){
697                 switch (G.obpose->type){
698                 case OB_ARMATURE:
699                         {
700                                 bActionChannel *achan;
701                                 Bone *bone;
702
703                                 bone = get_first_selected_bone();
704                                 if (!bone) break;
705                                 
706                                 /* Make sure we have an action */
707                                 if (!G.obpose->action){
708                                         if (!forcevalid)
709                                                 return NULL;
710                                         
711                                         G.obpose->action=add_empty_action();
712                                 }
713                                 
714                                 /* Make sure we have an actionchannel */
715                                 achan = get_named_actionchannel(G.obpose->action, bone->name);
716                                 if (!achan){
717                                         if (!forcevalid)
718                                                 return NULL;
719                                         
720                                         achan = MEM_callocN (sizeof(bActionChannel), "actionChannel");
721
722                                         strcpy (achan->name, bone->name);
723                                         sprintf (ipstr, "%s.%s", G.obpose->action->id.name+2, achan->name);
724                                         ipstr[23]=0;
725                                         achan->ipo=     add_ipo(ipstr, ID_AC);  
726                                         
727                                         BLI_addtail (&G.obpose->action->chanbase, achan);
728                                 }
729                                 
730                                 return &achan->constraintChannels;
731                         }
732                 }
733         }
734         
735         return &ob->constraintChannels;
736 }
737
738 ListBase *get_constraint_client(char *name, short *clientType, void **clientdata)
739 {
740         Object *ob;
741         ListBase *list;
742
743         ob=OBACT;
744         if (clientType)
745                 *clientType = -1;
746
747         if (!ob)
748                 return NULL;
749
750         list = &ob->constraints;
751
752         /* Prep the object's constraint channels */
753         if (clientType)
754                 *clientType = TARGET_OBJECT;
755         
756         if (name)
757                 strcpy (name, ob->id.name+2);
758
759         if (G.obpose){
760                 switch (G.obpose->type){
761                 case OB_ARMATURE:
762                         {
763                                 Bone *bone;
764
765                                 bone = get_first_selected_bone();
766                                 if (!bone) break;
767
768                                 {
769                                         bPoseChannel    *chan;
770                                         
771                                         /* Is the bone the client? */
772                                         if (clientType)
773                                                 *clientType = TARGET_BONE;
774                                         if (clientdata)
775                                                 *clientdata = bone;
776                                         if (name)
777                                                 sprintf (name, "%s>>%s", name, bone->name);
778                                         chan = verify_pose_channel(G.obpose->pose, bone->name);
779                                         list = &chan->constraints;
780
781                                 }                       
782                         }
783                         break;
784                 }
785         }
786
787         return list;
788 }
789
790 bConstraint * add_new_constraint(char type)
791 {
792         bConstraint *con;
793
794         con = MEM_callocN(sizeof(bConstraint), "constraint");
795
796         /* Set up a generic constraint datablock */
797         con->type = type;
798         con->flag |= CONSTRAINT_EXPAND;
799         con->enforce=1.0F;
800         /* Load the data for it */
801         con->data = new_constraint_data(con->type);
802         strcpy (con->name, "Const");
803         return con;
804 }
805
806 void add_constraint_to_object(bConstraint *con, Object *ob)
807 {
808         ListBase *list;
809         list = &ob->constraints;
810         if (list)
811         {
812                 unique_constraint_name(con, list);
813                 BLI_addtail(list, con);
814         }
815 }
816
817 void add_constraint_to_client(bConstraint *con)
818 {
819         ListBase *list;
820         short type;
821         list = get_constraint_client(NULL, &type, NULL);
822         if (list)
823         {
824                 unique_constraint_name(con, list);
825                 BLI_addtail(list, con);
826         }
827 }
828
829 bConstraintChannel *add_new_constraint_channel(const char* name)
830 {
831         bConstraintChannel *chan = NULL;
832
833         chan = MEM_callocN(sizeof(bConstraintChannel), "constraintChannel");
834         strcpy(chan->name, name);
835         
836         return chan;
837 }
838
839 void add_influence_key_to_constraint (bConstraint *con){
840         printf("doesn't do anything yet\n");
841 }
842
843 char *get_con_subtarget_name(bConstraint *constraint, Object *target)
844 {
845         /*
846          * If the target for this constraint is target, return a pointer 
847          * to the name for this constraints subtarget ... NULL otherwise
848          */
849         switch (constraint->type) {
850
851                 case CONSTRAINT_TYPE_ACTION:
852                 {
853                         bActionConstraint *data = constraint->data;
854                         if (data->tar==target) return data->subtarget;
855                 }
856                 break;
857                 case CONSTRAINT_TYPE_LOCLIKE:
858                 {
859                         bLocateLikeConstraint *data = constraint->data;
860                         if (data->tar==target) return data->subtarget;
861                 }
862                 break;
863                 case CONSTRAINT_TYPE_ROTLIKE:
864                 {
865                         bRotateLikeConstraint *data = constraint->data;
866                         if (data->tar==target) return data->subtarget;
867                 }
868                 break;
869                 case CONSTRAINT_TYPE_KINEMATIC:
870                 {
871                         bKinematicConstraint *data = constraint->data;
872                         if (data->tar==target) return data->subtarget;
873                 }
874                 break;
875                 case CONSTRAINT_TYPE_TRACKTO:
876                 {
877                         bTrackToConstraint *data = constraint->data;
878                         if (data->tar==target) return data->subtarget;
879                 }
880                 break;
881                 case CONSTRAINT_TYPE_LOCKTRACK:
882                 {
883                         bLockTrackConstraint *data = constraint->data;
884                         if (data->tar==target) return data->subtarget;
885                 }
886                 break;
887                 case CONSTRAINT_TYPE_STRETCHTO:
888                 {
889                         bStretchToConstraint *data = constraint->data;
890                         if (data->tar==target) return data->subtarget;
891                 }
892                 break;
893                 case CONSTRAINT_TYPE_FOLLOWPATH: 
894                         /* wonder if this is relevent, since this constraint 
895                          * cannot have a subtarget - theeth 
896                          */
897                 {
898                         /*
899                          * bFollowPathConstraint *data = constraint->data;
900                          */
901                         return NULL;
902                 }
903                 break;
904         }
905         
906         return NULL;  
907 }
908