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