Another painful editing issue solved!
[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_interface.h"
60 #include "BIF_screen.h"
61 #include "BIF_toolbox.h"
62
63 #include "blendef.h"
64 #include "nla.h"
65
66
67 /* called by buttons to find a bone to display/edit values for */
68 static bPoseChannel *get_active_posechannel (void)
69 {
70         Object *ob= OBACT;
71         bPoseChannel *pchan;
72         bArmature *arm;
73         
74         arm = get_armature(OBACT);
75         if (!arm)
76                 return NULL;
77         
78         /* find for active */
79         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
80                 if(pchan->bone && (pchan->bone->flag & BONE_ACTIVE))
81                         return pchan;
82         }
83         
84         return NULL;
85 }
86
87
88 ListBase *get_constraint_client_channels (int forcevalid)
89 {
90         Object *ob;
91         char ipstr[64];
92
93         ob=OBACT;
94         
95         if (!ob)
96                 return NULL;
97         
98         /* See if we are a bone constraint */
99         if (ob->flag & OB_POSEMODE) {
100                 bActionChannel *achan;
101                 bPoseChannel *pchan;
102
103                 pchan = get_active_posechannel();
104                 if (pchan) {
105                         
106                         /* Make sure we have an action */
107                         if (!ob->action){
108                                 if (!forcevalid)
109                                         return NULL;
110                                 
111                                 ob->action=add_empty_action();
112                         }
113                         
114                         /* Make sure we have an actionchannel */
115                         achan = get_named_actionchannel(ob->action, pchan->name);
116                         if (!achan){
117                                 if (!forcevalid)
118                                         return NULL;
119                                 
120                                 achan = MEM_callocN (sizeof(bActionChannel), "actionChannel");
121
122                                 strcpy (achan->name, pchan->name);
123                                 sprintf (ipstr, "%s.%s", ob->action->id.name+2, achan->name);
124                                 ipstr[23]=0;
125                                 achan->ipo=     add_ipo(ipstr, ID_AC);  
126                                 
127                                 BLI_addtail (&ob->action->chanbase, achan);
128                         }
129                         
130                         return &achan->constraintChannels;
131                 }
132                 else return NULL;
133         }
134         /* else we return object constraints */
135         return &ob->constraintChannels;
136 }
137
138 ListBase *get_constraint_client(char *name, short *clientType, void **clientdata)
139 {
140         Object *ob;
141         ListBase *list;
142
143         ob=OBACT;
144         if (clientType)
145                 *clientType = -1;
146
147         if (!ob)
148                 return NULL;
149
150         list = &ob->constraints;
151
152         /* Prep the object's constraint channels */
153         if (clientType)
154                 *clientType = TARGET_OBJECT;
155         
156         if (name)
157                 strcpy (name, ob->id.name+2);
158
159         if (ob->flag & OB_POSEMODE) {
160                 bPoseChannel *pchan;
161
162                 pchan = get_active_posechannel();
163                 if (pchan) {
164
165                         /* Is the bone the client? */
166                         if (clientType)
167                                 *clientType = TARGET_BONE;
168                         if (clientdata)
169                                 *clientdata = pchan->bone;
170                         if (name)
171                                 sprintf (name, "%s>>%s", name, pchan->name);
172
173                         list = &pchan->constraints;
174                 }
175         }
176
177         return list;
178 }
179
180 bConstraint * add_new_constraint(char type)
181 {
182         bConstraint *con;
183
184         con = MEM_callocN(sizeof(bConstraint), "constraint");
185
186         /* Set up a generic constraint datablock */
187         con->type = type;
188         con->flag |= CONSTRAINT_EXPAND;
189         con->enforce=1.0F;
190         /* Load the data for it */
191         con->data = new_constraint_data(con->type);
192         strcpy (con->name, "Const");
193         return con;
194 }
195
196 void add_constraint_to_object(bConstraint *con, Object *ob)
197 {
198         ListBase *list;
199         list = &ob->constraints;
200         if (list)
201         {
202                 unique_constraint_name(con, list);
203                 BLI_addtail(list, con);
204         }
205 }
206
207 void add_constraint_to_client(bConstraint *con)
208 {
209         ListBase *list;
210         short type;
211         list = get_constraint_client(NULL, &type, NULL);
212         if (list)
213         {
214                 unique_constraint_name(con, list);
215                 BLI_addtail(list, con);
216         }
217 }
218
219 bConstraintChannel *add_new_constraint_channel(const char* name)
220 {
221         bConstraintChannel *chan = NULL;
222
223         chan = MEM_callocN(sizeof(bConstraintChannel), "constraintChannel");
224         strcpy(chan->name, name);
225         
226         return chan;
227 }
228
229 void add_influence_key_to_constraint (bConstraint *con){
230         printf("doesn't do anything yet\n");
231 }
232
233 char *get_con_subtarget_name(bConstraint *constraint, Object *target)
234 {
235         /*
236          * If the target for this constraint is target, return a pointer 
237          * to the name for this constraints subtarget ... NULL otherwise
238          */
239         switch (constraint->type) {
240
241                 case CONSTRAINT_TYPE_ACTION:
242                 {
243                         bActionConstraint *data = constraint->data;
244                         if (data->tar==target) return data->subtarget;
245                 }
246                 break;
247                 case CONSTRAINT_TYPE_LOCLIKE:
248                 {
249                         bLocateLikeConstraint *data = constraint->data;
250                         if (data->tar==target) return data->subtarget;
251                 }
252                 break;
253                 case CONSTRAINT_TYPE_ROTLIKE:
254                 {
255                         bRotateLikeConstraint *data = constraint->data;
256                         if (data->tar==target) return data->subtarget;
257                 }
258                 break;
259                 case CONSTRAINT_TYPE_KINEMATIC:
260                 {
261                         bKinematicConstraint *data = constraint->data;
262                         if (data->tar==target) return data->subtarget;
263                 }
264                 break;
265                 case CONSTRAINT_TYPE_TRACKTO:
266                 {
267                         bTrackToConstraint *data = constraint->data;
268                         if (data->tar==target) return data->subtarget;
269                 }
270                 break;
271                 case CONSTRAINT_TYPE_LOCKTRACK:
272                 {
273                         bLockTrackConstraint *data = constraint->data;
274                         if (data->tar==target) return data->subtarget;
275                 }
276                 break;
277                 case CONSTRAINT_TYPE_STRETCHTO:
278                 {
279                         bStretchToConstraint *data = constraint->data;
280                         if (data->tar==target) return data->subtarget;
281                 }
282                 break;
283                 case CONSTRAINT_TYPE_FOLLOWPATH: 
284                         /* wonder if this is relevent, since this constraint 
285                          * cannot have a subtarget - theeth 
286                          */
287                 {
288                         /*
289                          * bFollowPathConstraint *data = constraint->data;
290                          */
291                         return NULL;
292                 }
293                 break;
294         }
295         
296         return NULL;  
297 }
298
299 /* checks validity of object pointers, and NULLs,
300    if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag */
301 static void test_constraints (Object *owner, const char* substring)
302 {
303         
304         bConstraint *curcon;
305         ListBase *conlist= NULL;
306         int type;
307         
308         if (owner==NULL) return;
309         
310         /* Check parents */
311         /* Get the constraint list for this object */
312         
313         if (strlen (substring)){
314                 switch (owner->type){
315                         case OB_ARMATURE:
316                                 type = TARGET_BONE;
317                                 break;
318                         default:
319                                 type = TARGET_OBJECT;
320                                 break;
321                 }
322         }
323         else
324                 type = TARGET_OBJECT;
325         
326         
327         switch (type){
328                 case TARGET_OBJECT:
329                         conlist = &owner->constraints;
330                         break;
331                 case TARGET_BONE:
332                         {
333                                 Bone *bone;
334                                 bPoseChannel *chan;
335                                 
336                                 bone = get_named_bone(((bArmature*)owner->data), substring);
337                                 chan = get_pose_channel (owner->pose, substring);
338                                 if (bone && chan){
339                                         conlist = &chan->constraints;
340                                 }
341                         }
342                         break;
343         }
344         
345         /* Cycle constraints */
346         if (conlist){
347                 for (curcon = conlist->first; curcon; curcon=curcon->next){
348                         curcon->flag &= ~CONSTRAINT_DISABLE;
349                         
350                         switch (curcon->type){
351                                 case CONSTRAINT_TYPE_ACTION:
352                                 {
353                                         bActionConstraint *data = curcon->data;
354                                         
355                                         if (!exist_object(data->tar)){
356                                                 data->tar = NULL;
357                                                 break;
358                                         }
359                                         
360                                         if ( (data->tar == owner) &&
361                                                  (!get_named_bone(get_armature(owner), 
362                                                                                   data->subtarget))) {
363                                                 curcon->flag |= CONSTRAINT_DISABLE;
364                                                 break;
365                                         }
366                                 }
367                                         break;
368                                 case CONSTRAINT_TYPE_LOCLIKE:
369                                 {
370                                         bLocateLikeConstraint *data = curcon->data;
371                                         
372                                         if (!exist_object(data->tar)){
373                                                 data->tar = NULL;
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_ROTLIKE:
386                                 {
387                                         bRotateLikeConstraint *data = curcon->data;
388                                         
389                                         if (!exist_object(data->tar)){
390                                                 data->tar = NULL;
391                                                 break;
392                                         }
393                                         
394                                         if ( (data->tar == owner) &&
395                                                  (!get_named_bone(get_armature(owner), 
396                                                                                   data->subtarget))) {
397                                                 curcon->flag |= CONSTRAINT_DISABLE;
398                                                 break;
399                                         }
400                                 }
401                                         break;
402                                 case CONSTRAINT_TYPE_KINEMATIC:
403                                 {
404                                         bKinematicConstraint *data = curcon->data;
405                                         if (!exist_object(data->tar)){
406                                                 data->tar = NULL;
407                                                 break;
408                                         }
409                                         
410                                         if ( (data->tar == owner) &&
411                                                  (!get_named_bone(get_armature(owner), 
412                                                                                   data->subtarget))) {
413                                                 curcon->flag |= CONSTRAINT_DISABLE;
414                                                 break;
415                                         }
416                                 }
417                                         break;
418                                 case CONSTRAINT_TYPE_TRACKTO:
419                                 {
420                                         bTrackToConstraint *data = curcon->data;
421                                         if (!exist_object(data->tar)) {
422                                                 data->tar = NULL;
423                                                 break;
424                                         }
425                                         
426                                         if ( (data->tar == owner) &&
427                                                  (!get_named_bone(get_armature(owner), 
428                                                                                   data->subtarget))) {
429                                                 curcon->flag |= CONSTRAINT_DISABLE;
430                                                 break;
431                                         }
432                                         if (data->reserved2==data->reserved1){
433                                                 curcon->flag |= CONSTRAINT_DISABLE;
434                                                 break;
435                                         }
436                                         if (data->reserved2+3==data->reserved1){
437                                                 curcon->flag |= CONSTRAINT_DISABLE;
438                                                 break;
439                                         }
440                                 }
441                                         break;
442                                 case CONSTRAINT_TYPE_LOCKTRACK:
443                                 {
444                                         bLockTrackConstraint *data = curcon->data;
445                                         
446                                         if (!exist_object(data->tar)){
447                                                 data->tar = NULL;
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                                                 break;
475                                         }
476                                         
477                                         if ( (data->tar == owner) &&
478                                                  (!get_named_bone(get_armature(owner), 
479                                                                                   data->subtarget))) {
480                                                 curcon->flag |= CONSTRAINT_DISABLE;
481                                                 break;
482                                         }
483                                 }
484                                         break;
485                                 case CONSTRAINT_TYPE_FOLLOWPATH:
486                                 {
487                                         bFollowPathConstraint *data = curcon->data;
488                                         
489                                         if (!exist_object(data->tar)){
490                                                 data->tar = NULL;
491                                                 break;
492                                         }
493                                         if (data->tar->type != OB_CURVE){
494                                                 data->tar = NULL;
495                                                 break;
496                                         }
497                                         if (data->upflag==data->trackflag){
498                                                 curcon->flag |= CONSTRAINT_DISABLE;
499                                                 break;
500                                         }
501                                         if (data->upflag+3==data->trackflag){
502                                                 curcon->flag |= CONSTRAINT_DISABLE;
503                                                 break;
504                                         }
505                                 }
506                                         break;
507                         }
508                 }
509         }
510 }
511
512 static void test_bonelist_constraints (Object *owner, ListBase *list)
513 {
514         Bone *bone;
515
516         for (bone = list->first; bone; bone=bone->next) {
517                 
518                 test_constraints(owner, bone->name);
519                 test_bonelist_constraints (owner, &bone->childbase);
520         }
521 }
522
523 void object_test_constraints (Object *owner)
524 {
525         test_constraints(owner, "");
526
527         if(owner->type==OB_ARMATURE) {
528                 bArmature *arm;
529                 arm = get_armature(owner);
530                 if (arm)
531                         test_bonelist_constraints (owner, &arm->bonebase);
532         }
533
534 }
535
536