Renamed get_constraint_target in constraint kernel file to get_constraint_target_matr...
[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 (add_constraint_element (data->tar, data->subtarget, owner, substring)){
410                                                         curcon->flag |= CONSTRAINT_DISABLE;
411                                                         result = 1;
412                                                         break;
413                                                         //              return 1;
414                                                 }
415                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_ACTION)){
416                                                         curcon->flag |= CONSTRAINT_DISABLE;
417                                                         result = 1;
418                                                         break;
419                                                         //              return 1;
420                                                 }
421                                         }
422                                         break;
423                                 case CONSTRAINT_TYPE_LOCLIKE:
424                                         {
425                                                 bLocateLikeConstraint *data = curcon->data;
426                                         
427                                                 if (!exist_object(data->tar)){
428                                                         data->tar = NULL;
429                                                         break;
430                                                 }
431                                                 
432                                                 if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
433                                                         curcon->flag |= CONSTRAINT_DISABLE;
434                                                         result = 1;
435                                                         break;
436                                                         //              return 1;
437                                                 }
438                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_LOCLIKE)){
439                                                         curcon->flag |= CONSTRAINT_DISABLE;
440                                                         result = 1;
441                                                         break;
442                                                         //              return 1;
443                                                 }
444                                         }
445                                         break;
446                                 case CONSTRAINT_TYPE_ROTLIKE:
447                                         {
448                                                 bRotateLikeConstraint *data = curcon->data;
449                                         
450                                                 if (!exist_object(data->tar)){
451                                                         data->tar = NULL;
452                                                         break;
453                                                 }
454                                                 
455                                                 if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
456                                                         curcon->flag |= CONSTRAINT_DISABLE;
457                                                         result = 1;
458                                                         break;
459                                                         //              return 1;
460                                                 }
461                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_ROTLIKE)){
462                                                         curcon->flag |= CONSTRAINT_DISABLE;
463                                                         result = 1;
464                                                         break;
465                                                         //              return 1;
466                                                 }
467                                         }
468                                         break;
469                                 case CONSTRAINT_TYPE_KINEMATIC:
470                                         {
471                                                 bKinematicConstraint *data = curcon->data;
472                                                 if (!exist_object(data->tar)){
473                                                         data->tar = NULL;
474                                                         break;
475                                                 }
476
477                                                 if ( (data->tar == owner) &&
478                                                          (!get_named_bone(get_armature(owner), 
479                                                                                           data->subtarget))) {
480                                                         curcon->flag |= CONSTRAINT_DISABLE;
481                                                         result = 1;
482                                                         break;
483                                                 }
484
485                                                 
486                                                 if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
487                                                         curcon->flag |= CONSTRAINT_DISABLE;
488                                                         result = 1;
489                                                         break;
490                                                         //      return 1;
491                                                 }
492                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_KINEMATIC)){
493                                                         curcon->flag |= CONSTRAINT_DISABLE;
494                                                         result = 1;
495                                                         break;
496                                                         //              return 1;
497                                                 }
498                                         }
499                                         break;
500                                 case CONSTRAINT_TYPE_TRACKTO:
501                                         {
502                                                 bTrackToConstraint *data = curcon->data;
503                                                 if (!exist_object(data->tar)) {
504                                                         data->tar = NULL;
505                                                         break;
506                                                 }
507                                                 
508                                                 if (typefrom != CONSTRAINT_TYPE_TRACKTO && typefrom != CONSTRAINT_TYPE_LOCKTRACK){
509                                                         if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
510                                                                 curcon->flag |= CONSTRAINT_DISABLE;
511                                                                 result = 1;
512                                                                 break;
513                                                                 //      return 1;
514                                                         }
515                                                 }
516                                                 else {
517                                                         curcon->flag |= CONSTRAINT_NOREFRESH;
518                                                 }
519
520                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_TRACKTO)){
521                                                         curcon->flag |= CONSTRAINT_DISABLE;
522                                                         result = 1;
523                                                         break;
524                                                         //              return 1;
525                                                 }
526                                                 if (data->reserved2==data->reserved1){
527                                                         curcon->flag |= CONSTRAINT_DISABLE;
528                                                         result = 1;
529                                                         break;
530                                                         //              return 1;
531                                                 }
532                                                 if (data->reserved2+3==data->reserved1){
533                                                         curcon->flag |= CONSTRAINT_DISABLE;
534                                                         result = 1;
535                                                         break;
536                                                         //              return 1;
537                                                 }
538                                         }
539                                         break;
540                                 case CONSTRAINT_TYPE_LOCKTRACK:
541                                         {
542                                                 bLockTrackConstraint *data = curcon->data;
543                                         
544                                                 if (!exist_object(data->tar)){
545                                                         data->tar = NULL;
546                                                         break;
547                                                 }
548                                                 
549                                                 if (typefrom != CONSTRAINT_TYPE_TRACKTO && typefrom != CONSTRAINT_TYPE_LOCKTRACK){
550                                                         if (add_constraint_element (data->tar, data->subtarget, owner, substring)){
551                                                                 curcon->flag |= CONSTRAINT_DISABLE;
552                                                                 result = 1;
553                                                                 break;
554                                                                 //              return 1;
555                                                         }
556                                                 }
557                                                 else {
558                                                         curcon->flag |= CONSTRAINT_NOREFRESH;
559                                                 }
560
561                                                 if (detect_constraint_loop (data->tar, data->subtarget, disable, CONSTRAINT_TYPE_LOCKTRACK)){
562                                                         curcon->flag |= CONSTRAINT_DISABLE;
563                                                         result = 1;
564                                                         break;
565                                                         //              return 1;
566                                                 }
567                                                 if (data->lockflag==data->trackflag){
568                                                         curcon->flag |= CONSTRAINT_DISABLE;
569                                                         result = 1;
570                                                         break;
571                                                         //              return 1;
572                                                 }
573                                                 if (data->lockflag+3==data->trackflag){
574                                                         curcon->flag |= CONSTRAINT_DISABLE;
575                                                         result = 1;
576                                                         break;
577                                                         //              return 1;
578                                                 }
579                                         }
580                                         break;
581                                 case CONSTRAINT_TYPE_FOLLOWPATH:
582                                         {
583                                                 bFollowPathConstraint *data = curcon->data;
584                                         
585                                                 if (!exist_object(data->tar)){
586                                                         data->tar = NULL;
587                                                         break;
588                                                 }
589                                                 if (data->tar->type != OB_CURVE){
590                                                         data->tar = NULL;
591                                                         break;
592                                                 }
593                                                 if (add_constraint_element (data->tar, "", owner, substring)){
594                                                         curcon->flag |= CONSTRAINT_DISABLE;
595                                                         result = 1;
596                                                         break;
597                                                         //              return 1;
598                                                 }
599                                                 if (detect_constraint_loop (data->tar, "", disable, CONSTRAINT_TYPE_FOLLOWPATH)){
600                                                         curcon->flag |= CONSTRAINT_DISABLE;
601                                                         result = 1;
602                                                         break;
603                                                         //              return 1;
604                                                 }
605                                                 if (data->upflag==data->trackflag){
606                                                         curcon->flag |= CONSTRAINT_DISABLE;
607                                                         result = 1;
608                                                         break;
609                                                         //              return 1;
610                                                 }
611                                                 if (data->upflag+3==data->trackflag){
612                                                         curcon->flag |= CONSTRAINT_DISABLE;
613                                                         result = 1;
614                                                         break;
615                                                         //              return 1;
616                                                 }
617                                         }
618                                         break;
619                                 }
620                         }
621                 }
622         }
623         
624         return result;
625 }
626
627 ListBase *get_constraint_client_channels (int forcevalid)
628 {
629
630         Object *ob;
631         char ipstr[64];
632
633         ob=OBACT;
634         
635         if (!ob)
636                 return NULL;
637         
638         /* See if we are a bone constraint */
639         if (G.obpose){
640                 switch (G.obpose->type){
641                 case OB_ARMATURE:
642                         {
643                                 bActionChannel *achan;
644                                 Bone *bone;
645
646                                 bone = get_first_selected_bone();
647                                 if (!bone) break;
648                                 
649                                 /* Make sure we have an action */
650                                 if (!G.obpose->action){
651                                         if (!forcevalid)
652                                                 return NULL;
653                                         
654                                         G.obpose->action=add_empty_action();
655                                 }
656                                 
657                                 /* Make sure we have an actionchannel */
658                                 achan = get_named_actionchannel(G.obpose->action, bone->name);
659                                 if (!achan){
660                                         if (!forcevalid)
661                                                 return NULL;
662                                         
663                                         achan = MEM_callocN (sizeof(bActionChannel), "actionChannel");
664
665                                         strcpy (achan->name, bone->name);
666                                         sprintf (ipstr, "%s.%s", G.obpose->action->id.name+2, achan->name);
667                                         ipstr[23]=0;
668                                         achan->ipo=     add_ipo(ipstr, ID_AC);  
669                                         
670                                         BLI_addtail (&G.obpose->action->chanbase, achan);
671                                 }
672                                 
673                                 return &achan->constraintChannels;
674                         }
675                 }
676         }
677         
678         return &ob->constraintChannels;
679 }
680
681 ListBase *get_constraint_client(char *name, short *clientType, void **clientdata)
682 {
683         Object *ob;
684         ListBase *list;
685
686         ob=OBACT;
687         if (clientType)
688                 *clientType = -1;
689
690         if (!ob)
691                 return NULL;
692
693         list = &ob->constraints;
694
695         /* Prep the object's constraint channels */
696         if (clientType)
697                 *clientType = TARGET_OBJECT;
698         
699         if (name)
700                 strcpy (name, ob->id.name+2);
701
702         if (G.obpose){
703                 switch (G.obpose->type){
704                 case OB_ARMATURE:
705                         {
706                                 Bone *bone;
707
708                                 bone = get_first_selected_bone();
709                                 if (!bone) break;
710
711                                 {
712                                         bPoseChannel    *chan;
713                                         
714                                         /* Is the bone the client? */
715                                         if (clientType)
716                                                 *clientType = TARGET_BONE;
717                                         if (clientdata)
718                                                 *clientdata = bone;
719                                         if (name)
720                                                 sprintf (name, "%s>>%s", name, bone->name);
721                                         chan = verify_pose_channel(G.obpose->pose, bone->name);
722                                         list = &chan->constraints;
723
724                                 }                       
725                         }
726                         break;
727                 }
728         }
729
730         return list;
731 }
732
733 bConstraint * add_new_constraint(char type)
734 {
735         bConstraint *con;
736
737         con = MEM_callocN(sizeof(bConstraint), "constraint");
738
739         /* Set up a generic constraint datablock */
740         con->type = type;
741         con->flag |= CONSTRAINT_EXPAND;
742         con->enforce=1.0F;
743         /* Load the data for it */
744         con->data = new_constraint_data(con->type);
745         strcpy (con->name, "Const");
746         return con;
747 }
748
749 void add_constraint_to_object(bConstraint *con, Object *ob)
750 {
751         ListBase *list;
752         list = &ob->constraints;
753         if (list)
754         {
755                 unique_constraint_name(con, list);
756                 BLI_addtail(list, con);
757         }
758 }
759
760 void add_constraint_to_client(bConstraint *con)
761 {
762         ListBase *list;
763         short type;
764         list = get_constraint_client(NULL, &type, NULL);
765         if (list)
766         {
767                 unique_constraint_name(con, list);
768                 BLI_addtail(list, con);
769         }
770 }
771
772 bConstraintChannel *add_new_constraint_channel(const char* name)
773 {
774         bConstraintChannel *chan = NULL;
775
776         chan = MEM_callocN(sizeof(bConstraintChannel), "constraintChannel");
777         strcpy(chan->name, name);
778         
779         return chan;
780 }
781
782 void add_influence_key_to_constraint (bConstraint *con){
783         printf("doesn't do anything yet\n");
784 }
785
786 char *get_con_subtarget_name(bConstraint *constraint, Object *target)
787 {
788         /*
789          * If the target for this constraint is target, return a pointer 
790          * to the name for this constraints subtarget ... NULL otherwise
791          */
792         switch (constraint->type) {
793
794                 case CONSTRAINT_TYPE_ACTION:
795                 {
796                         bActionConstraint *data = constraint->data;
797                         if (data->tar==target) return data->subtarget;
798                 }
799                 break;
800                 case CONSTRAINT_TYPE_LOCLIKE:
801                 {
802                         bLocateLikeConstraint *data = constraint->data;
803                         if (data->tar==target) return data->subtarget;
804                 }
805                 break;
806                 case CONSTRAINT_TYPE_ROTLIKE:
807                 {
808                         bRotateLikeConstraint *data = constraint->data;
809                         if (data->tar==target) return data->subtarget;
810                 }
811                 break;
812                 case CONSTRAINT_TYPE_KINEMATIC:
813                 {
814                         bKinematicConstraint *data = constraint->data;
815                         if (data->tar==target) return data->subtarget;
816                 }
817                 break;
818                 case CONSTRAINT_TYPE_TRACKTO:
819                 {
820                         bTrackToConstraint *data = constraint->data;
821                         if (data->tar==target) return data->subtarget;
822                 }
823                 break;
824                 case CONSTRAINT_TYPE_LOCKTRACK:
825                 {
826                         bLockTrackConstraint *data = constraint->data;
827                         if (data->tar==target) return data->subtarget;
828                 }
829                 break;
830                 case CONSTRAINT_TYPE_FOLLOWPATH: 
831                         /* wonder if this is relevent, since this constraint 
832                          * cannot have a subtarget - theeth 
833                          */
834                 {
835                         /*
836                          * bFollowPathConstraint *data = constraint->data;
837                          */
838                         return NULL;
839                 }
840                 break;
841         }
842         
843         return NULL;  
844 }