Huge commit, but not much features... had to shuffle a lot of code around.
[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         ListBase *list;
120
121         if (!ob)
122                 return NULL;
123
124         list = &ob->constraints;
125
126         if (ob->flag & OB_POSEMODE) {
127                 bPoseChannel *pchan;
128
129                 pchan = get_active_posechannel(ob);
130                 if (pchan)
131                         list = &pchan->constraints;
132         }
133
134         return list;
135 }
136
137 /* single constraint */
138 bConstraint *get_active_constraint(Object *ob)
139 {
140         ListBase *lb= get_active_constraints(ob);
141
142         if(lb) {
143                 bConstraint *con;
144                 for(con= lb->first; con; con=con->next)
145                         if(con->flag & CONSTRAINT_ACTIVE)
146                                 return con;
147         }
148         return NULL;
149 }
150
151 /* single channel, for ipo */
152 bConstraintChannel *get_active_constraint_channel(Object *ob)
153 {
154         bConstraint *con;
155         bConstraintChannel *chan;
156         
157         if (ob->flag & OB_POSEMODE) {
158                 if(ob->action) {
159                         bPoseChannel *pchan;
160                         
161                         pchan = get_active_posechannel(ob);
162                         if(pchan) {
163                                 for(con= pchan->constraints.first; con; con= con->next)
164                                         if(con->flag & CONSTRAINT_ACTIVE)
165                                                 break;
166                                 if(con) {
167                                         bActionChannel *achan = get_named_actionchannel(ob->action, pchan->name);
168                                         if(achan) {
169                                                 for(chan= achan->constraintChannels.first; chan; chan= chan->next)
170                                                         if(!strcmp(chan->name, con->name))
171                                                                 break;
172                                                 return chan;
173                                         }
174                                 }
175                         }
176                 }
177         }
178         else {
179                 for(con= ob->constraints.first; con; con= con->next)
180                         if(con->flag & CONSTRAINT_ACTIVE)
181                                 break;
182                 if(con) {
183                         for(chan= ob->constraintChannels.first; chan; chan= chan->next)
184                                 if(!strcmp(chan->name, con->name))
185                                         break;
186                         return chan;
187                 }
188         }
189         
190         return NULL;
191 }
192
193
194
195 bConstraint *add_new_constraint(short type)
196 {
197         bConstraint *con;
198
199         con = MEM_callocN(sizeof(bConstraint), "constraint");
200
201         /* Set up a generic constraint datablock */
202         con->type = type;
203         con->flag |= CONSTRAINT_EXPAND;
204         con->enforce=1.0F;
205         /* Load the data for it */
206         con->data = new_constraint_data(con->type);
207         strcpy (con->name, "Const");
208         return con;
209 }
210
211 void add_constraint_to_object(bConstraint *con, Object *ob)
212 {
213         ListBase *list;
214         list = &ob->constraints;
215         
216         if (list) {
217                 unique_constraint_name(con, list);
218                 BLI_addtail(list, con);
219                 
220                 con->flag |= CONSTRAINT_ACTIVE;
221                 for(con= con->prev; con; con= con->prev)
222                         con->flag &= ~CONSTRAINT_ACTIVE;
223         }
224 }
225
226
227 char *get_con_subtarget_name(bConstraint *con, Object *target)
228 {
229         /*
230          * If the target for this constraint is target, return a pointer 
231          * to the name for this constraints subtarget ... NULL otherwise
232          */
233         switch (con->type) {
234
235                 case CONSTRAINT_TYPE_ACTION:
236                 {
237                         bActionConstraint *data = con->data;
238                         if (data->tar==target) return data->subtarget;
239                 }
240                 break;
241                 case CONSTRAINT_TYPE_LOCLIKE:
242                 {
243                         bLocateLikeConstraint *data = con->data;
244                         if (data->tar==target) return data->subtarget;
245                 }
246                 break;
247                 case CONSTRAINT_TYPE_ROTLIKE:
248                 {
249                         bRotateLikeConstraint *data = con->data;
250                         if (data->tar==target) return data->subtarget;
251                 }
252                 break;
253                 case CONSTRAINT_TYPE_KINEMATIC:
254                 {
255                         bKinematicConstraint *data = con->data;
256                         if (data->tar==target) return data->subtarget;
257                 }
258                 break;
259                 case CONSTRAINT_TYPE_TRACKTO:
260                 {
261                         bTrackToConstraint *data = con->data;
262                         if (data->tar==target) return data->subtarget;
263                 }
264                 break;
265                 case CONSTRAINT_TYPE_LOCKTRACK:
266                 {
267                         bLockTrackConstraint *data = con->data;
268                         if (data->tar==target) return data->subtarget;
269                 }
270                 break;
271                 case CONSTRAINT_TYPE_STRETCHTO:
272                 {
273                         bStretchToConstraint *data = con->data;
274                         if (data->tar==target) return data->subtarget;
275                 }
276                 break;
277                 case CONSTRAINT_TYPE_FOLLOWPATH: 
278                         /* wonder if this is relevent, since this constraint 
279                          * cannot have a subtarget - theeth 
280                          */
281                 {
282                         /*
283                          * bFollowPathConstraint *data = con->data;
284                          */
285                         return NULL;
286                 }
287                 break;
288         }
289         
290         return NULL;  
291 }
292
293 /* checks validity of object pointers, and NULLs,
294    if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag */
295 static void test_constraints (Object *owner, const char* substring)
296 {
297         
298         bConstraint *curcon;
299         ListBase *conlist= NULL;
300         int type;
301         
302         if (owner==NULL) return;
303         
304         /* Check parents */
305         /* Get the constraint list for this object */
306         
307         if (strlen (substring)){
308                 switch (owner->type){
309                         case OB_ARMATURE:
310                                 type = TARGET_BONE;
311                                 break;
312                         default:
313                                 type = TARGET_OBJECT;
314                                 break;
315                 }
316         }
317         else
318                 type = TARGET_OBJECT;
319         
320         
321         switch (type){
322                 case TARGET_OBJECT:
323                         conlist = &owner->constraints;
324                         break;
325                 case TARGET_BONE:
326                         {
327                                 Bone *bone;
328                                 bPoseChannel *chan;
329                                 
330                                 bone = get_named_bone(((bArmature*)owner->data), substring);
331                                 chan = get_pose_channel (owner->pose, substring);
332                                 if (bone && chan){
333                                         conlist = &chan->constraints;
334                                 }
335                         }
336                         break;
337         }
338         
339         /* Cycle constraints */
340         if (conlist){
341                 for (curcon = conlist->first; curcon; curcon=curcon->next){
342                         curcon->flag &= ~CONSTRAINT_DISABLE;
343                         
344                         switch (curcon->type){
345                                 case CONSTRAINT_TYPE_ACTION:
346                                 {
347                                         bActionConstraint *data = curcon->data;
348                                         
349                                         if (!exist_object(data->tar)){
350                                                 data->tar = NULL;
351                                                 curcon->flag |= CONSTRAINT_DISABLE;
352                                                 break;
353                                         }
354                                         
355                                         if ( (data->tar == owner) &&
356                                                  (!get_named_bone(get_armature(owner), 
357                                                                                   data->subtarget))) {
358                                                 curcon->flag |= CONSTRAINT_DISABLE;
359                                                 break;
360                                         }
361                                 }
362                                         break;
363                                 case CONSTRAINT_TYPE_LOCLIKE:
364                                 {
365                                         bLocateLikeConstraint *data = curcon->data;
366                                         
367                                         if (!exist_object(data->tar)){
368                                                 data->tar = NULL;
369                                                 curcon->flag |= CONSTRAINT_DISABLE;
370                                                 break;
371                                         }
372                                         
373                                         if ( (data->tar == owner) &&
374                                                  (!get_named_bone(get_armature(owner), 
375                                                                                   data->subtarget))) {
376                                                 curcon->flag |= CONSTRAINT_DISABLE;
377                                                 break;
378                                         }
379                                 }
380                                         break;
381                                 case CONSTRAINT_TYPE_ROTLIKE:
382                                 {
383                                         bRotateLikeConstraint *data = curcon->data;
384                                         
385                                         if (!exist_object(data->tar)){
386                                                 data->tar = NULL;
387                                                 curcon->flag |= CONSTRAINT_DISABLE;
388                                                 break;
389                                         }
390                                         
391                                         if ( (data->tar == owner) &&
392                                                  (!get_named_bone(get_armature(owner), 
393                                                                                   data->subtarget))) {
394                                                 curcon->flag |= CONSTRAINT_DISABLE;
395                                                 break;
396                                         }
397                                 }
398                                         break;
399                                 case CONSTRAINT_TYPE_KINEMATIC:
400                                 {
401                                         bKinematicConstraint *data = curcon->data;
402                                         if (!exist_object(data->tar)){
403                                                 data->tar = NULL;
404                                                 curcon->flag |= CONSTRAINT_DISABLE;
405                                                 break;
406                                         }
407                                         
408                                         if ( (data->tar == owner) &&
409                                                  (!get_named_bone(get_armature(owner), 
410                                                                                   data->subtarget))) {
411                                                 curcon->flag |= CONSTRAINT_DISABLE;
412                                                 break;
413                                         }
414                                 }
415                                         break;
416                                 case CONSTRAINT_TYPE_TRACKTO:
417                                 {
418                                         bTrackToConstraint *data = curcon->data;
419                                         if (!exist_object(data->tar)) {
420                                                 data->tar = NULL;
421                                                 curcon->flag |= CONSTRAINT_DISABLE;
422                                                 break;
423                                         }
424                                         
425                                         if ( (data->tar == owner) &&
426                                                  (!get_named_bone(get_armature(owner), 
427                                                                                   data->subtarget))) {
428                                                 curcon->flag |= CONSTRAINT_DISABLE;
429                                                 break;
430                                         }
431                                         if (data->reserved2==data->reserved1){
432                                                 curcon->flag |= CONSTRAINT_DISABLE;
433                                                 break;
434                                         }
435                                         if (data->reserved2+3==data->reserved1){
436                                                 curcon->flag |= CONSTRAINT_DISABLE;
437                                                 break;
438                                         }
439                                 }
440                                         break;
441                                 case CONSTRAINT_TYPE_LOCKTRACK:
442                                 {
443                                         bLockTrackConstraint *data = curcon->data;
444                                         
445                                         if (!exist_object(data->tar)){
446                                                 data->tar = NULL;
447                                                 curcon->flag |= CONSTRAINT_DISABLE;
448                                                 break;
449                                         }
450                                         
451                                         if ( (data->tar == owner) &&
452                                                  (!get_named_bone(get_armature(owner), 
453                                                                                   data->subtarget))) {
454                                                 curcon->flag |= CONSTRAINT_DISABLE;
455                                                 break;
456                                         }
457
458                                         if (data->lockflag==data->trackflag){
459                                                 curcon->flag |= CONSTRAINT_DISABLE;
460                                                 break;
461                                         }
462                                         if (data->lockflag+3==data->trackflag){
463                                                 curcon->flag |= CONSTRAINT_DISABLE;
464                                                 break;
465                                         }
466                                 }
467                                         break;
468                                 case CONSTRAINT_TYPE_STRETCHTO:
469                                 {
470                                         bStretchToConstraint *data = curcon->data;
471                                         
472                                         if (!exist_object(data->tar)){
473                                                 data->tar = NULL;
474                                                 curcon->flag |= CONSTRAINT_DISABLE;
475                                                 break;
476                                         }
477                                         
478                                         if ( (data->tar == owner) &&
479                                                  (!get_named_bone(get_armature(owner), 
480                                                                                   data->subtarget))) {
481                                                 curcon->flag |= CONSTRAINT_DISABLE;
482                                                 break;
483                                         }
484                                 }
485                                         break;
486                                 case CONSTRAINT_TYPE_FOLLOWPATH:
487                                 {
488                                         bFollowPathConstraint *data = curcon->data;
489                                         
490                                         if (!exist_object(data->tar)){
491                                                 data->tar = NULL;
492                                                 curcon->flag |= CONSTRAINT_DISABLE;
493                                                 break;
494                                         }
495                                         if (data->tar->type != OB_CURVE){
496                                                 data->tar = NULL;
497                                                 curcon->flag |= CONSTRAINT_DISABLE;
498                                                 break;
499                                         }
500                                         if (data->upflag==data->trackflag){
501                                                 curcon->flag |= CONSTRAINT_DISABLE;
502                                                 break;
503                                         }
504                                         if (data->upflag+3==data->trackflag){
505                                                 curcon->flag |= CONSTRAINT_DISABLE;
506                                                 break;
507                                         }
508                                 }
509                                         break;
510                         }
511                 }
512         }
513 }
514
515 static void test_bonelist_constraints (Object *owner, ListBase *list)
516 {
517         Bone *bone;
518
519         for (bone = list->first; bone; bone=bone->next) {
520                 
521                 test_constraints(owner, bone->name);
522                 test_bonelist_constraints (owner, &bone->childbase);
523         }
524 }
525
526 void object_test_constraints (Object *owner)
527 {
528         test_constraints(owner, "");
529
530         if(owner->type==OB_ARMATURE) {
531                 bArmature *arm;
532                 arm = get_armature(owner);
533                 if (arm)
534                         test_bonelist_constraints (owner, &arm->bonebase);
535         }
536
537 }
538
539