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