correct fsf address
[blender.git] / source / blender / editors / animation / drivers.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL 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.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung (full recode)
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29  
30 #include <stdio.h>
31 #include <stddef.h>
32 #include <string.h>
33 #include <math.h>
34 #include <float.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_math.h"
40 #include "BLI_dynstr.h"
41
42 #include "DNA_anim_types.h"
43 #include "DNA_action_types.h"
44 #include "DNA_armature_types.h"
45 #include "DNA_constraint_types.h"
46 #include "DNA_key_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_material_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_userdef_types.h"
51 #include "DNA_windowmanager_types.h"
52
53 #include "BKE_animsys.h"
54 #include "BKE_action.h"
55 #include "BKE_constraint.h"
56 #include "BKE_depsgraph.h"
57 #include "BKE_fcurve.h"
58 #include "BKE_utildefines.h"
59 #include "BKE_context.h"
60 #include "BKE_report.h"
61 #include "BKE_key.h"
62 #include "BKE_material.h"
63
64 #include "ED_anim_api.h"
65 #include "ED_keyframing.h"
66 #include "ED_keyframes_edit.h"
67 #include "ED_screen.h"
68 #include "ED_util.h"
69
70 #include "UI_interface.h"
71
72 #include "WM_api.h"
73 #include "WM_types.h"
74
75 #include "RNA_access.h"
76 #include "RNA_define.h"
77 #include "RNA_types.h"
78
79 /* ************************************************** */
80 /* Animation Data Validation */
81
82 /* Get (or add relevant data to be able to do so) F-Curve from the driver stack, 
83  * for the given Animation Data block. This assumes that all the destinations are valid.
84  *      
85  *      - add:  0 - don't add anything if not found, 
86  *                      1 - add new Driver FCurve, 
87  *                      -1 - add new Driver FCurve without driver stuff (for pasting)
88  */
89 FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_index, short add)
90 {
91         AnimData *adt;
92         FCurve *fcu;
93         
94         /* sanity checks */
95         if ELEM(NULL, id, rna_path)
96                 return NULL;
97         
98         /* init animdata if none available yet */
99         adt= BKE_animdata_from_id(id);
100         if ((adt == NULL) && (add))
101                 adt= BKE_id_add_animdata(id);
102         if (adt == NULL) { 
103                 /* if still none (as not allowed to add, or ID doesn't have animdata for some reason) */
104                 return NULL;
105         }
106                 
107         /* try to find f-curve matching for this setting 
108          *      - add if not found and allowed to add one
109          *              TODO: add auto-grouping support? how this works will need to be resolved
110          */
111         fcu= list_find_fcurve(&adt->drivers, rna_path, array_index);
112         
113         if ((fcu == NULL) && (add)) {
114                 /* use default settings to make a F-Curve */
115                 fcu= MEM_callocN(sizeof(FCurve), "FCurve");
116                 
117                 fcu->flag = (FCURVE_VISIBLE|FCURVE_AUTO_HANDLES|FCURVE_SELECTED);
118                 
119                 /* store path - make copy, and store that */
120                 fcu->rna_path= BLI_strdupn(rna_path, strlen(rna_path));
121                 fcu->array_index= array_index;
122                 
123                 /* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */
124                 if (add > 0) {
125                         /* add some new driver data */
126                         fcu->driver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
127                         
128                         /* add simple generator modifier for driver so that there is some visible representation */
129                         add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
130                 }
131                 
132                 /* just add F-Curve to end of driver list */
133                 BLI_addtail(&adt->drivers, fcu);
134         }
135         
136         /* return the F-Curve */
137         return fcu;
138 }
139
140 /* ************************************************** */
141 /* Driver Management API */
142
143 /* Main Driver Management API calls:
144  *      Add a new driver for the specified property on the given ID block
145  */
146 short ANIM_add_driver (ID *id, const char rna_path[], int array_index, short flag, int type)
147 {       
148         PointerRNA id_ptr, ptr;
149         PropertyRNA *prop;
150         FCurve *fcu;
151         int array_index_max;
152         int done = 0;
153         
154         /* validate pointer first - exit if failure */
155         RNA_id_pointer_create(id, &id_ptr);
156         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
157                 printf("Add Driver: Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path);
158                 return 0;
159         }
160         
161         /* key entire array convenience method */
162         if (array_index == -1) {
163                 array_index_max= RNA_property_array_length(&ptr, prop);
164                 array_index= 0;
165         }
166         else
167                 array_index_max= array_index;
168         
169         /* maximum index should be greater than the start index */
170         if (array_index == array_index_max)
171                 array_index_max += 1;
172         
173         /* will only loop once unless the array index was -1 */
174         for (; array_index < array_index_max; array_index++) {
175                 /* create F-Curve with Driver */
176                 fcu= verify_driver_fcurve(id, rna_path, array_index, 1);
177                 
178                 if (fcu && fcu->driver) {
179                         ChannelDriver *driver= fcu->driver;
180                         
181                         /* set the type of the driver */
182                         driver->type= type;
183                         
184                         /* fill in current value for python */
185                         if (type == DRIVER_TYPE_PYTHON) {
186                                 PropertyType proptype= RNA_property_type(prop);
187                                 int array= RNA_property_array_length(&ptr, prop);
188                                 char *expression= driver->expression;
189                                 int val, maxlen= sizeof(driver->expression);
190                                 float fval;
191                                 
192                                 if (proptype == PROP_BOOLEAN) {
193                                         if (!array) val= RNA_property_boolean_get(&ptr, prop);
194                                         else val= RNA_property_boolean_get_index(&ptr, prop, array_index);
195                                         
196                                         BLI_strncpy(expression, (val)? "True": "False", maxlen);
197                                 }
198                                 else if (proptype == PROP_INT) {
199                                         if (!array) val= RNA_property_int_get(&ptr, prop);
200                                         else val= RNA_property_int_get_index(&ptr, prop, array_index);
201                                         
202                                         BLI_snprintf(expression, maxlen, "%d", val);
203                                 }
204                                 else if (proptype == PROP_FLOAT) {
205                                         if (!array) fval= RNA_property_float_get(&ptr, prop);
206                                         else fval= RNA_property_float_get_index(&ptr, prop, array_index);
207                                         
208                                         BLI_snprintf(expression, maxlen, "%.3f", fval);
209                                 }
210                         }
211                 }
212                 
213                 /* set the done status */
214                 done += (fcu != NULL);
215         }
216         
217         /* done */
218         return done;
219 }
220
221 /* Main Driver Management API calls:
222  *      Remove the driver for the specified property on the given ID block (if available)
223  */
224 short ANIM_remove_driver (struct ID *id, const char rna_path[], int array_index, short flag)
225 {
226         AnimData *adt;
227         FCurve *fcu;
228         
229         /* get F-Curve
230          * Note: here is one of the places where we don't want new F-Curve + Driver added!
231          *              so 'add' var must be 0
232          */
233         /* we don't check the validity of the path here yet, but it should be ok... */
234         fcu= verify_driver_fcurve(id, rna_path, array_index, 0);
235         adt= BKE_animdata_from_id(id);
236         
237         /* only continue if we have an driver to remove */
238         if (adt && fcu) {
239                 /* remove F-Curve from driver stack, then free it */
240                 BLI_remlink(&adt->drivers, fcu);
241                 free_fcurve(fcu);
242                 
243                 /* done successfully */
244                 return 1;
245         }
246         
247         /* failed */
248         return 0;
249 }
250
251 /* ************************************************** */
252 /* Driver Management API - Copy/Paste Drivers */
253
254 /* Copy/Paste Buffer for Driver Data... */
255 static FCurve *channeldriver_copypaste_buf = NULL;
256
257 /* This function frees any MEM_calloc'ed copy/paste buffer data */
258 // XXX find some header to put this in!
259 void free_anim_drivers_copybuf (void)
260 {
261         /* free the buffer F-Curve if it exists, as if it were just another F-Curve */
262         if (channeldriver_copypaste_buf)
263                 free_fcurve(channeldriver_copypaste_buf);
264         channeldriver_copypaste_buf= NULL;
265 }
266
267 /* Checks if there is a driver in the copy/paste buffer */
268 short ANIM_driver_can_paste (void)
269 {
270         return (channeldriver_copypaste_buf != NULL);
271 }
272
273 /* ------------------- */
274
275 /* Main Driver Management API calls:
276  *      Make a copy of the driver for the specified property on the given ID block
277  */
278 short ANIM_copy_driver (ID *id, const char rna_path[], int array_index, short flag)
279 {
280         PointerRNA id_ptr, ptr;
281         PropertyRNA *prop;
282         FCurve *fcu;
283         
284         /* validate pointer first - exit if failure */
285         RNA_id_pointer_create(id, &id_ptr);
286         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
287                 printf("Copy Driver: Could not find Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path);
288                 return 0;
289         }
290         
291         /* try to get F-Curve with Driver */
292         fcu= verify_driver_fcurve(id, rna_path, array_index, 0);
293         
294         /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
295         free_anim_drivers_copybuf();
296         
297         /* copy this to the copy/paste buf if it exists */
298         if (fcu && fcu->driver) {
299                 /* make copies of some info such as the rna_path, then clear this info from the F-Curve temporarily
300                  * so that we don't end up wasting memory storing the path which won't get used ever...
301                  */
302                 char *tmp_path = fcu->rna_path;
303                 fcu->rna_path= NULL;
304                 
305                 /* make a copy of the F-Curve with */
306                 channeldriver_copypaste_buf= copy_fcurve(fcu);
307                 
308                 /* restore the path */
309                 fcu->rna_path= tmp_path;
310                 
311                 /* copied... */
312                 return 1;
313         }
314         
315         /* done */
316         return 0;
317 }
318
319 /* Main Driver Management API calls:
320  *      Add a new driver for the specified property on the given ID block or replace an existing one
321  *      with the driver + driver-curve data from the buffer 
322  */
323 short ANIM_paste_driver (ID *id, const char rna_path[], int array_index, short flag)
324 {       
325         PointerRNA id_ptr, ptr;
326         PropertyRNA *prop;
327         FCurve *fcu;
328         
329         /* validate pointer first - exit if failure */
330         RNA_id_pointer_create(id, &id_ptr);
331         if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) {
332                 printf("Paste Driver: Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", id->name, rna_path);
333                 return 0;
334         }
335         
336         /* if the buffer is empty, cannot paste... */
337         if (channeldriver_copypaste_buf == NULL) {
338                 printf("Paste Driver: No Driver to paste. \n");
339                 return 0;
340         }
341         
342         /* create Driver F-Curve, but without data which will be copied across... */
343         fcu= verify_driver_fcurve(id, rna_path, array_index, -1);
344
345         if (fcu) {
346                 /* copy across the curve data from the buffer curve 
347                  * NOTE: this step needs care to not miss new settings
348                  */
349                         /* keyframes/samples */
350                 fcu->bezt= MEM_dupallocN(channeldriver_copypaste_buf->bezt);
351                 fcu->fpt= MEM_dupallocN(channeldriver_copypaste_buf->fpt);
352                 fcu->totvert= channeldriver_copypaste_buf->totvert;
353                 
354                         /* modifiers */
355                 copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers);
356                 
357                         /* flags - on a per-relevant-flag basis */
358                 if (channeldriver_copypaste_buf->flag & FCURVE_AUTO_HANDLES)
359                         fcu->flag |= FCURVE_AUTO_HANDLES;
360                 else
361                         fcu->flag &= ~FCURVE_AUTO_HANDLES;
362                         /* extrapolation mode */
363                 fcu->extend= channeldriver_copypaste_buf->extend;
364                         
365                         /* the 'juicy' stuff - the driver */
366                 fcu->driver= fcurve_copy_driver(channeldriver_copypaste_buf->driver);
367         }
368         
369         /* done */
370         return (fcu != NULL);
371 }
372
373 /* ************************************************** */
374 /* UI-Button Interface */
375
376 /* Add Driver Button Operator ------------------------ */
377
378 static int add_driver_button_exec (bContext *C, wmOperator *op)
379 {
380         PointerRNA ptr;
381         PropertyRNA *prop= NULL;
382         char *path;
383         short success= 0;
384         int index, all= RNA_boolean_get(op->ptr, "all");
385         
386         /* try to create driver using property retrieved from UI */
387         memset(&ptr, 0, sizeof(PointerRNA));
388         uiAnimContextProperty(C, &ptr, &prop, &index);
389
390         if (all)
391                 index= -1;
392
393         if (ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
394                 path= RNA_path_from_ID_to_property(&ptr, prop);
395                 
396                 if (path) {                     
397                         success+= ANIM_add_driver(ptr.id.data, path, index, 0, DRIVER_TYPE_PYTHON);
398                         
399                         MEM_freeN(path);
400                 }
401         }
402         
403         if (success) {
404                 /* send updates */
405                 DAG_ids_flush_update(0);
406                 
407                 WM_event_add_notifier(C, NC_ANIMATION|ND_FCURVES_ORDER, NULL); // XXX
408         }
409         
410         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
411 }
412
413 void ANIM_OT_driver_button_add (wmOperatorType *ot)
414 {
415         /* identifiers */
416         ot->name= "Add Driver";
417         ot->idname= "ANIM_OT_driver_button_add";
418         ot->description= "Add driver(s) for the property(s) connected represented by the highlighted button";
419         
420         /* callbacks */
421         ot->exec= add_driver_button_exec; 
422         //op->poll= ??? // TODO: need to have some animateable property to do this
423         
424         /* flags */
425         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
426
427         /* properties */
428         RNA_def_boolean(ot->srna, "all", 1, "All", "Create drivers for all elements of the array.");
429 }
430
431 /* Remove Driver Button Operator ------------------------ */
432
433 static int remove_driver_button_exec (bContext *C, wmOperator *op)
434 {
435         PointerRNA ptr;
436         PropertyRNA *prop= NULL;
437         char *path;
438         short success= 0;
439         int a, index, length, all= RNA_boolean_get(op->ptr, "all");
440         
441         /* try to find driver using property retrieved from UI */
442         memset(&ptr, 0, sizeof(PointerRNA));
443         uiAnimContextProperty(C, &ptr, &prop, &index);
444
445         if (ptr.data && prop) {
446                 path= RNA_path_from_ID_to_property(&ptr, prop);
447                 
448                 if (path) {
449                         if (all) {
450                                 length= RNA_property_array_length(&ptr, prop);
451                                 
452                                 if(length) index= 0;
453                                 else length= 1;
454                         }
455                         else
456                                 length= 1;
457                         
458                         for (a=0; a<length; a++)
459                                 success+= ANIM_remove_driver(ptr.id.data, path, index+a, 0);
460                         
461                         MEM_freeN(path);
462                 }
463         }
464         
465         
466         if (success) {
467                 /* send updates */
468                 DAG_ids_flush_update(0);
469                 
470                 WM_event_add_notifier(C, NC_ANIMATION|ND_FCURVES_ORDER, NULL);  // XXX
471         }
472         
473         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
474 }
475
476 void ANIM_OT_driver_button_remove (wmOperatorType *ot)
477 {
478         /* identifiers */
479         ot->name= "Remove Driver";
480         ot->idname= "ANIM_OT_driver_button_remove";
481         ot->description= "Remove the driver(s) for the property(s) connected represented by the highlighted button";
482         
483         /* callbacks */
484         ot->exec= remove_driver_button_exec; 
485         //op->poll= ??? // TODO: need to have some driver to be able to do this...
486         
487         /* flags */
488         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
489
490         /* properties */
491         RNA_def_boolean(ot->srna, "all", 1, "All", "Delete drivers for all elements of the array.");
492 }
493
494 /* Copy Driver Button Operator ------------------------ */
495
496 static int copy_driver_button_exec (bContext *C, wmOperator *op)
497 {
498         PointerRNA ptr;
499         PropertyRNA *prop= NULL;
500         char *path;
501         short success= 0;
502         int index;
503         
504         /* try to create driver using property retrieved from UI */
505         memset(&ptr, 0, sizeof(PointerRNA));
506         uiAnimContextProperty(C, &ptr, &prop, &index);
507         
508         if (ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
509                 path= RNA_path_from_ID_to_property(&ptr, prop);
510                 
511                 if (path) {
512                         /* only copy the driver for the button that this was involved for */
513                         success= ANIM_copy_driver(ptr.id.data, path, index, 0);
514                         
515                         MEM_freeN(path);
516                 }
517         }
518         
519         /* since we're just copying, we don't really need to do anything else...*/
520         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
521 }
522
523 void ANIM_OT_copy_driver_button (wmOperatorType *ot)
524 {
525         /* identifiers */
526         ot->name= "Copy Driver";
527         ot->idname= "ANIM_OT_copy_driver_button";
528         ot->description= "Copy the driver for the highlighted button";
529         
530         /* callbacks */
531         ot->exec= copy_driver_button_exec; 
532         //op->poll= ??? // TODO: need to have some driver to be able to do this...
533         
534         /* flags */
535         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
536 }
537
538 /* Paste Driver Button Operator ------------------------ */
539
540 static int paste_driver_button_exec (bContext *C, wmOperator *op)
541 {
542         PointerRNA ptr;
543         PropertyRNA *prop= NULL;
544         char *path;
545         short success= 0;
546         int index;
547         
548         /* try to create driver using property retrieved from UI */
549         memset(&ptr, 0, sizeof(PointerRNA));
550         uiAnimContextProperty(C, &ptr, &prop, &index);
551         
552         if (ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
553                 path= RNA_path_from_ID_to_property(&ptr, prop);
554                 
555                 if (path) {
556                         /* only copy the driver for the button that this was involved for */
557                         success= ANIM_paste_driver(ptr.id.data, path, index, 0);
558                         
559                         MEM_freeN(path);
560                 }
561         }
562         
563         /* since we're just copying, we don't really need to do anything else...*/
564         return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
565 }
566
567 void ANIM_OT_paste_driver_button (wmOperatorType *ot)
568 {
569         /* identifiers */
570         ot->name= "Paste Driver";
571         ot->idname= "ANIM_OT_paste_driver_button";
572         ot->description= "Paste the driver in the copy/paste buffer for the highlighted button";
573         
574         /* callbacks */
575         ot->exec= paste_driver_button_exec; 
576         //op->poll= ??? // TODO: need to have some driver to be able to do this...
577         
578         /* flags */
579         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
580 }
581
582 /* ************************************************** */