svn merge ^/trunk/blender -r40644:40720
[blender-staging.git] / source / blender / editors / animation / keyframes_edit.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation
19  *
20  * Contributor(s): Joshua Leung
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/editors/animation/keyframes_edit.c
26  *  \ingroup edanimation
27  */
28
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33 #include <float.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_blenlib.h"
38 #include "BLI_math.h"
39 #include "BLI_utildefines.h"
40
41 #include "DNA_anim_types.h"
42 #include "DNA_armature_types.h"
43 #include "DNA_camera_types.h"
44 #include "DNA_key_types.h"
45 #include "DNA_lamp_types.h"
46 #include "DNA_lattice_types.h"
47 #include "DNA_mesh_types.h"
48 #include "DNA_material_types.h"
49 #include "DNA_object_types.h"
50 #include "DNA_meta_types.h"
51 #include "DNA_node_types.h"
52 #include "DNA_particle_types.h"
53 #include "DNA_scene_types.h"
54 #include "DNA_space_types.h"
55 #include "DNA_world_types.h"
56
57 #include "BKE_fcurve.h"
58 #include "BKE_key.h"
59 #include "BKE_material.h"
60
61
62 #include "ED_anim_api.h"
63 #include "ED_keyframes_edit.h"
64 #include "ED_markers.h"
65
66 /* This file defines an API and set of callback-operators for non-destructive editing of keyframe data.
67  *
68  * Two API functions are defined for actually performing the operations on the data:
69  *                      ANIM_fcurve_keyframes_loop()
70  * which take the data they operate on, a few callbacks defining what operations to perform.
71  *
72  * As operators which work on keyframes usually apply the same operation on all BezTriples in 
73  * every channel, the code has been optimised providing a set of functions which will get the 
74  * appropriate bezier-modify function to set. These functions (ANIM_editkeyframes_*) will need
75  * to be called before getting any channels.
76  * 
77  * A set of 'validation' callbacks are provided for checking if a BezTriple should be operated on.
78  * These should only be used when using a 'general' BezTriple editor (i.e. selection setters which 
79  * don't check existing selection status).
80  * 
81  * - Joshua Leung, Dec 2008
82  */
83
84 /* ************************************************************************** */
85 /* Keyframe Editing Loops - Exposed API */
86
87 /* --------------------------- Base Functions ------------------------------------ */
88
89 /* This function is used to loop over BezTriples in the given F-Curve, applying a given 
90  * operation on them, and optionally applies an F-Curve validation function afterwards.
91  */
92 // TODO: make this function work on samples too...
93 short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb) 
94 {
95         BezTriple *bezt;
96         short ok = 0;
97         unsigned int i;
98
99         /* sanity check */
100         if (ELEM(NULL, fcu, fcu->bezt))
101                 return 0;
102
103         /* set the F-Curve into the editdata so that it can be accessed */
104         if (ked) {
105                 ked->fcu= fcu;
106                 ked->curIndex= 0;
107                 ked->curflags= ok;
108         }
109
110         /* if function to apply to bezier curves is set, then loop through executing it on beztriples */
111         if (key_cb) {
112                 /* if there's a validation func, include that check in the loop 
113                  * (this is should be more efficient than checking for it in every loop)
114                  */
115                 if (key_ok) {
116                         for (bezt=fcu->bezt, i=0; i < fcu->totvert; bezt++, i++) {
117                                 if (ked) {
118                                         /* advance the index, and reset the ok flags (to not influence the result) */
119                                         ked->curIndex= i;
120                                         ked->curflags= 0;
121                                 }
122                                 
123                                 /* Only operate on this BezTriple if it fullfills the criteria of the validation func */
124                                 if ( (ok = key_ok(ked, bezt)) ) {
125                                         if (ked) ked->curflags= ok;
126                                         
127                                         /* Exit with return-code '1' if function returns positive
128                                          * This is useful if finding if some BezTriple satisfies a condition.
129                                          */
130                                         if (key_cb(ked, bezt)) return 1;
131                                 }
132                         }
133                 }
134                 else {
135                         for (bezt=fcu->bezt, i=0; i < fcu->totvert; bezt++, i++) {
136                                 if (ked) ked->curIndex= i;
137                                 
138                                 /* Exit with return-code '1' if function returns positive
139                                 * This is useful if finding if some BezTriple satisfies a condition.
140                                 */
141                                 if (key_cb(ked, bezt)) return 1;
142                         }
143                 }
144         }
145         
146         /* unset the F-Curve from the editdata now that it's done */
147         if (ked) {
148                 ked->fcu= NULL;
149                 ked->curIndex= 0;
150                 ked->curflags= 0;
151         }
152
153         /* if fcu_cb (F-Curve post-editing callback) has been specified then execute it */
154         if (fcu_cb)
155                 fcu_cb(fcu);
156         
157         /* done */      
158         return 0;
159 }
160
161 /* -------------------------------- Further Abstracted (Not Exposed Directly) ----------------------------- */
162
163 /* This function is used to loop over the keyframe data in an Action Group */
164 static short agrp_keyframes_loop(KeyframeEditData *ked, bActionGroup *agrp, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
165 {
166         FCurve *fcu;
167         
168         /* sanity check */
169         if (agrp == NULL)
170                 return 0;
171         
172         /* only iterate over the F-Curves that are in this group */
173         for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next) {
174                 if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb))
175                         return 1;
176         }
177         
178         return 0;
179 }
180
181 /* This function is used to loop over the keyframe data in an Action */
182 static short act_keyframes_loop(KeyframeEditData *ked, bAction *act, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
183 {
184         FCurve *fcu;
185         
186         /* sanity check */
187         if (act == NULL)
188                 return 0;
189         
190         /* just loop through all F-Curves */
191         for (fcu= act->curves.first; fcu; fcu= fcu->next) {
192                 if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb))
193                         return 1;
194         }
195         
196         return 0;
197 }
198
199 /* This function is used to loop over the keyframe data in an Object */
200 static short ob_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Object *ob, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
201 {
202         bAnimContext ac = {NULL};
203         ListBase anim_data = {NULL, NULL};
204         bAnimListElem *ale;
205         int filter;
206         int ret=0;
207         
208         bAnimListElem dummychan = {NULL};
209         Base dummybase = {NULL};
210         
211         if (ob == NULL)
212                 return 0;
213         
214         /* create a dummy wrapper data to work with */
215         dummybase.object = ob;
216         
217         dummychan.type = ANIMTYPE_OBJECT;
218         dummychan.data = &dummybase;
219         dummychan.id = &ob->id;
220         dummychan.adt = ob->adt;
221         
222         ac.ads = ads;
223         ac.data = &dummychan;
224         ac.datatype = ANIMCONT_CHANNEL;
225         
226         /* get F-Curves to take keyframes from */
227         filter= ANIMFILTER_DATA_VISIBLE; // curves only
228         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
229         
230         /* loop through each F-Curve, applying the operation as required, but stopping on the first one */
231         for (ale= anim_data.first; ale; ale= ale->next) {
232                 if (ANIM_fcurve_keyframes_loop(ked, (FCurve*)ale->data, key_ok, key_cb, fcu_cb)) {
233                         ret = 1;
234                         break;
235                 }
236         }
237         
238         BLI_freelistN(&anim_data);
239         
240         /* return return code - defaults to zero if nothing happened */
241         return ret;
242 }
243
244 /* This function is used to loop over the keyframe data in a Scene */
245 static short scene_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Scene *sce, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
246 {
247         bAnimContext ac = {NULL};
248         ListBase anim_data = {NULL, NULL};
249         bAnimListElem *ale;
250         int filter;
251         int ret=0;
252         
253         bAnimListElem dummychan = {NULL};
254         
255         if (sce == NULL)
256                 return 0;
257         
258         /* create a dummy wrapper data to work with */
259         dummychan.type = ANIMTYPE_SCENE;
260         dummychan.data = sce;
261         dummychan.id = &sce->id;
262         dummychan.adt = sce->adt;
263         
264         ac.ads = ads;
265         ac.data = &dummychan;
266         ac.datatype = ANIMCONT_CHANNEL;
267         
268         /* get F-Curves to take keyframes from */
269         filter= ANIMFILTER_DATA_VISIBLE; // curves only
270         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
271         
272         /* loop through each F-Curve, applying the operation as required, but stopping on the first one */
273         for (ale= anim_data.first; ale; ale= ale->next) {
274                 if (ANIM_fcurve_keyframes_loop(ked, (FCurve*)ale->data, key_ok, key_cb, fcu_cb)) {
275                         ret = 1;
276                         break;
277                 }
278         }
279         
280         BLI_freelistN(&anim_data);
281         
282         /* return return code - defaults to zero if nothing happened */
283         return ret;
284 }
285
286 /* This function is used to loop over the keyframe data in a DopeSheet summary */
287 static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
288 {
289         ListBase anim_data = {NULL, NULL};
290         bAnimListElem *ale;
291         int filter, ret_code=0;
292         
293         /* sanity check */
294         if (ac == NULL)
295                 return 0;
296         
297         /* get F-Curves to take keyframes from */
298         filter= ANIMFILTER_DATA_VISIBLE;
299         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
300         
301         /* loop through each F-Curve, working on the keyframes until the first curve aborts */
302         for (ale= anim_data.first; ale; ale= ale->next) {
303                 ret_code= ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb);
304                 
305                 if (ret_code)
306                         break;
307         }
308         
309         BLI_freelistN(&anim_data);
310         
311         return ret_code;
312 }
313
314 /* --- */
315
316 /* This function is used to apply operation to all keyframes, regardless of the type */
317 short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, bAnimListElem *ale, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
318 {
319         /* sanity checks */
320         if (ale == NULL)
321                 return 0;
322         
323         /* method to use depends on the type of keyframe data */
324         switch (ale->datatype) {
325                 /* direct keyframe data (these loops are exposed) */
326                 case ALE_FCURVE: /* F-Curve */
327                         return ANIM_fcurve_keyframes_loop(ked, ale->key_data, key_ok, key_cb, fcu_cb);
328                 
329                 /* indirect 'summaries' (these are not exposed directly) 
330                  * NOTE: must keep this code in sync with the drawing code and also the filtering code!
331                  */
332                 case ALE_GROUP: /* action group */
333                         return agrp_keyframes_loop(ked, (bActionGroup *)ale->data, key_ok, key_cb, fcu_cb);
334                 case ALE_ACT: /* action */
335                         return act_keyframes_loop(ked, (bAction *)ale->key_data, key_ok, key_cb, fcu_cb);
336                         
337                 case ALE_OB: /* object */
338                         return ob_keyframes_loop(ked, ads, (Object *)ale->key_data, key_ok, key_cb, fcu_cb);
339                 case ALE_SCE: /* scene */
340                         return scene_keyframes_loop(ked, ads, (Scene *)ale->data, key_ok, key_cb, fcu_cb);
341                 case ALE_ALL: /* 'all' (DopeSheet summary) */
342                         return summary_keyframes_loop(ked, (bAnimContext *)ale->data, key_ok, key_cb, fcu_cb);
343         }
344         
345         return 0;
346 }
347
348 /* This function is used to apply operation to all keyframes, regardless of the type without needed an AnimListElem wrapper */
349 short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, void *data, int keytype, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
350 {
351         /* sanity checks */
352         if (data == NULL)
353                 return 0;
354         
355         /* method to use depends on the type of keyframe data */
356         switch (keytype) {
357                 /* direct keyframe data (these loops are exposed) */
358                 case ALE_FCURVE: /* F-Curve */
359                         return ANIM_fcurve_keyframes_loop(ked, data, key_ok, key_cb, fcu_cb);
360                 
361                 /* indirect 'summaries' (these are not exposed directly) 
362                  * NOTE: must keep this code in sync with the drawing code and also the filtering code!
363                  */
364                 case ALE_GROUP: /* action group */
365                         return agrp_keyframes_loop(ked, (bActionGroup *)data, key_ok, key_cb, fcu_cb);
366                 case ALE_ACT: /* action */
367                         return act_keyframes_loop(ked, (bAction *)data, key_ok, key_cb, fcu_cb);
368                         
369                 case ALE_OB: /* object */
370                         return ob_keyframes_loop(ked, ads, (Object *)data, key_ok, key_cb, fcu_cb);
371                 case ALE_SCE: /* scene */
372                         return scene_keyframes_loop(ked, ads, (Scene *)data, key_ok, key_cb, fcu_cb);
373                 case ALE_ALL: /* 'all' (DopeSheet summary) */
374                         return summary_keyframes_loop(ked, (bAnimContext *)data, key_ok, key_cb, fcu_cb);
375         }
376         
377         return 0;
378 }
379
380 /* ************************************************************************** */
381 /* Keyframe Integrity Tools */
382
383 /* Rearrange keyframes if some are out of order */
384 // used to be recalc_*_ipos() where * was object or action
385 void ANIM_editkeyframes_refresh(bAnimContext *ac)
386 {
387         ListBase anim_data = {NULL, NULL};
388         bAnimListElem *ale;
389         int filter;
390         /* when not in graph view, don't use handles */
391         SpaceIpo *sipo= (ac->spacetype == SPACE_IPO) ? (SpaceIpo *)ac->sl : NULL;
392         const short use_handle = sipo ? !(sipo->flag & SIPO_NOHANDLES) : FALSE;
393         
394         /* filter animation data */
395         filter= ANIMFILTER_DATA_VISIBLE; 
396         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
397         
398         /* loop over F-Curves that are likely to have been edited, and check them */
399         for (ale= anim_data.first; ale; ale= ale->next) {
400                 FCurve *fcu= ale->key_data;
401                 
402                 /* make sure keyframes in F-Curve are all in order, and handles are in valid positions */
403                 sort_time_fcurve(fcu);
404                 testhandles_fcurve(fcu, use_handle);
405         }
406         
407         /* free temp data */
408         BLI_freelistN(&anim_data);
409 }
410
411 /* ************************************************************************** */
412 /* BezTriple Validation Callbacks */
413
414 /* ------------------------ */
415 /* Some macros to make this easier... */
416
417 /* run the given check on the 3 handles 
418  *      - check should be a macro, which takes the handle index as its single arg, which it substitutes later
419  *      - requires that a var, of type short, is named 'ok', and has been initialized to 0
420  */
421 #define KEYFRAME_OK_CHECKS(check) \
422         { \
423                 if (check(1)) \
424                         ok |= KEYFRAME_OK_KEY; \
425                  \
426                 if (ked && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { \
427                         if (check(0)) \
428                                 ok |= KEYFRAME_OK_H1; \
429                         if (check(2)) \
430                                 ok |= KEYFRAME_OK_H2; \
431                 } \
432         }       
433  
434 /* ------------------------ */
435  
436 static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt)
437 {
438         short ok = 0;
439         
440         /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */
441         #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][0], ked->f1)
442                 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
443         #undef KEY_CHECK_OK
444         
445         /* return ok flags */
446         return ok;
447 }
448
449 static short ok_bezier_framerange(KeyframeEditData *ked, BezTriple *bezt)
450 {
451         short ok = 0;
452         
453         /* frame range is stored in float properties */
454         #define KEY_CHECK_OK(_index) ((bezt->vec[_index][0] > ked->f1) && (bezt->vec[_index][0] < ked->f2))
455                 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
456         #undef KEY_CHECK_OK
457         
458         /* return ok flags */
459         return ok;
460 }
461
462 static short ok_bezier_selected(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
463 {
464         /* this macro checks all beztriple handles for selection... 
465          *      only one of the verts has to be selected for this to be ok...
466          */
467         if (BEZSELECTED(bezt))
468                 return KEYFRAME_OK_ALL;
469         else
470                 return 0;
471 }
472
473 static short ok_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
474 {       
475         short ok = 0;
476         
477         /* value is stored in f1 property 
478          *      - this float accuracy check may need to be dropped?
479          *      - should value be stored in f2 instead so that we won't have conflicts when using f1 for frames too?
480          */
481         #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][1], ked->f1)
482                 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
483         #undef KEY_CHECK_OK
484         
485         /* return ok flags */
486         return ok;
487 }
488
489 static short ok_bezier_valuerange(KeyframeEditData *ked, BezTriple *bezt)
490 {
491         short ok = 0;
492         
493         /* value range is stored in float properties */
494         #define KEY_CHECK_OK(_index) ((bezt->vec[_index][1] > ked->f1) && (bezt->vec[_index][1] < ked->f2))
495                 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
496         #undef KEY_CHECK_OK
497         
498         /* return ok flags */
499         return ok;
500 }
501
502 static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
503 {
504         /* rect is stored in data property (it's of type rectf, but may not be set) */
505         if (ked->data) {
506                 short ok = 0;
507                 
508                 #define KEY_CHECK_OK(_index) BLI_in_rctf(ked->data, bezt->vec[_index][0], bezt->vec[_index][1])
509                         KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
510                 #undef KEY_CHECK_OK
511                 
512                 /* return ok flags */
513                 return ok;
514         }
515         else 
516                 return 0;
517 }
518
519
520 KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
521 {
522         /* eEditKeyframes_Validate */
523         switch (mode) {
524                 case BEZT_OK_FRAME: /* only if bezt falls on the right frame (float) */
525                         return ok_bezier_frame;
526                 case BEZT_OK_FRAMERANGE: /* only if bezt falls within the specified frame range (floats) */
527                         return ok_bezier_framerange;
528                 case BEZT_OK_SELECTED:  /* only if bezt is selected (self) */
529                         return ok_bezier_selected;
530                 case BEZT_OK_VALUE: /* only if bezt value matches (float) */
531                         return ok_bezier_value;
532                 case BEZT_OK_VALUERANGE: /* only if bezier falls within the specified value range (floats) */
533                         return ok_bezier_valuerange;
534                 case BEZT_OK_REGION: /* only if bezier falls within the specified rect (data -> rectf) */
535                         return ok_bezier_region;
536                 default: /* nothing was ok */
537                         return NULL;
538         }
539 }
540
541 /* ******************************************* */
542 /* Assorted Utility Functions */
543
544 /* helper callback for <animeditor>_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
545 short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
546 {
547         /* only if selected */
548         if (bezt->f2 & SELECT) {
549                 /* store average time in float 1 (only do rounding at last step) */
550                 ked->f1 += bezt->vec[1][0];
551                 
552                 /* store average value in float 2 (only do rounding at last step) 
553                  *      - this isn't always needed, but some operators may also require this
554                  */
555                 ked->f2 += bezt->vec[1][1];
556                 
557                 /* increment number of items */
558                 ked->i1++;
559         }
560         
561         return 0;
562 }
563
564 /* helper callback for columnselect_<animeditor>_keys() -> populate list CfraElems with frame numbers from selected beztriples */
565 short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
566 {
567         /* only if selected */
568         if (bezt->f2 & SELECT) {
569                 CfraElem *ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
570                 BLI_addtail(&ked->list, ce);
571                 
572                 ce->cfra= bezt->vec[1][0];
573         }
574         
575         return 0;
576 }
577
578 /* used to remap times from one range to another
579  * requires:  ked->data = KeyframeEditCD_Remap  
580  */
581 void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt)
582 {
583         KeyframeEditCD_Remap *rmap= (KeyframeEditCD_Remap*)ked->data;
584         const float scale = (rmap->newMax - rmap->newMin) / (rmap->oldMax - rmap->oldMin);
585         
586         /* perform transform on all three handles unless indicated otherwise */
587         // TODO: need to include some checks for that
588         
589         bezt->vec[0][0]= scale*(bezt->vec[0][0] - rmap->oldMin) + rmap->newMin;
590         bezt->vec[1][0]= scale*(bezt->vec[1][0] - rmap->oldMin) + rmap->newMin;
591         bezt->vec[2][0]= scale*(bezt->vec[2][0] - rmap->oldMin) + rmap->newMin;
592 }
593
594 /* ******************************************* */
595 /* Transform */
596
597 /* snaps the keyframe to the nearest frame */
598 static short snap_bezier_nearest(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
599 {
600         if (bezt->f2 & SELECT)
601                 bezt->vec[1][0]= (float)(floorf(bezt->vec[1][0]+0.5f));
602         return 0;
603 }
604
605 /* snaps the keyframe to the neares second */
606 static short snap_bezier_nearestsec(KeyframeEditData *ked, BezTriple *bezt)
607 {
608         const Scene *scene= ked->scene;
609         const float secf = (float)FPS;
610         
611         if (bezt->f2 & SELECT)
612                 bezt->vec[1][0]= ((float)floor(bezt->vec[1][0]/secf + 0.5f) * secf);
613         return 0;
614 }
615
616 /* snaps the keyframe to the current frame */
617 static short snap_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
618 {
619         const Scene *scene= ked->scene;
620         if (bezt->f2 & SELECT)
621                 bezt->vec[1][0]= (float)CFRA;
622         return 0;
623 }
624
625 /* snaps the keyframe time to the nearest marker's frame */
626 static short snap_bezier_nearmarker(KeyframeEditData *ked, BezTriple *bezt)
627 {
628         if (bezt->f2 & SELECT)
629                 bezt->vec[1][0]= (float)ED_markers_find_nearest_marker_time(&ked->list, bezt->vec[1][0]);
630         return 0;
631 }
632
633 /* make the handles have the same value as the key */
634 static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
635 {
636         if (bezt->f2 & SELECT) {
637                 bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
638                 
639                 if (ELEM3(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h1= HD_ALIGN;
640                 if (ELEM3(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h2= HD_ALIGN;
641         }
642         return 0;       
643 }
644
645 /* value to snap to is stored in the custom data -> first float value slot */
646 static short snap_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
647 {
648         if (bezt->f2 & SELECT)
649                 bezt->vec[1][1]= ked->f1;
650         return 0;
651 }
652
653 KeyframeEditFunc ANIM_editkeyframes_snap(short type)
654 {
655         /* eEditKeyframes_Snap */
656         switch (type) {
657                 case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
658                         return snap_bezier_nearest;
659                 case SNAP_KEYS_CURFRAME: /* snap to current frame */
660                         return snap_bezier_cframe;
661                 case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
662                         return snap_bezier_nearmarker;
663                 case SNAP_KEYS_NEARSEC: /* snap to nearest second */
664                         return snap_bezier_nearestsec;
665                 case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */
666                         return snap_bezier_horizontal;
667                 case SNAP_KEYS_VALUE: /* snap to given value */
668                         return snap_bezier_value;
669                 default: /* just in case */
670                         return snap_bezier_nearest;
671         }
672 }
673
674 /* --------- */
675
676 static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
677 {
678         const Scene *scene= ked->scene;
679         float diff;
680         
681         if (bezt->f2 & SELECT) {
682                 diff= ((float)CFRA - bezt->vec[1][0]);
683                 bezt->vec[1][0]= ((float)CFRA + diff);
684         }
685         
686         return 0;
687 }
688
689 static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
690 {
691         float diff;
692         
693         if (bezt->f2 & SELECT) {
694                 diff= (0.0f - bezt->vec[1][0]);
695                 bezt->vec[1][0]= (0.0f + diff);
696         }
697         
698         return 0;
699 }
700
701 static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
702 {
703         float diff;
704         
705         if (bezt->f2 & SELECT) {
706                 diff= (0.0f - bezt->vec[1][1]);
707                 bezt->vec[1][1]= (0.0f + diff);
708         }
709         
710         return 0;
711 }
712
713 static short mirror_bezier_marker(KeyframeEditData *ked, BezTriple *bezt)
714 {
715         /* mirroring time stored in f1 */
716         if (bezt->f2 & SELECT) {
717                 const float diff= (ked->f1 - bezt->vec[1][0]);
718                 bezt->vec[1][0]= (ked->f1 + diff);
719         }
720         
721         return 0;
722 }
723
724 static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
725 {
726         float diff;
727         
728         /* value to mirror over is stored in the custom data -> first float value slot */
729         if (bezt->f2 & SELECT) {
730                 diff= (ked->f1 - bezt->vec[1][1]);
731                 bezt->vec[1][1]= (ked->f1 + diff);
732         }
733         
734         return 0;
735 }
736
737 /* Note: for markers and 'value', the values to use must be supplied as the first float value */
738 // calchandles_fcurve
739 KeyframeEditFunc ANIM_editkeyframes_mirror(short type)
740 {
741         switch (type) {
742                 case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
743                         return mirror_bezier_cframe;
744                 case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
745                         return mirror_bezier_yaxis;
746                 case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
747                         return mirror_bezier_xaxis;
748                 case MIRROR_KEYS_MARKER: /* mirror over marker */
749                         return mirror_bezier_marker; 
750                 case MIRROR_KEYS_VALUE: /* mirror over given value */
751                         return mirror_bezier_value;
752                 default: /* just in case */
753                         return mirror_bezier_yaxis;
754                         break;
755         }
756 }
757
758 /* ******************************************* */
759 /* Settings */
760
761 /* standard validation step for a few of these (implemented as macro for inlining without fn-call overhead):
762  *      "if the handles are not of the same type, set them to type free"
763  */
764 #define ENSURE_HANDLES_MATCH(bezt) \
765                 if (bezt->h1 != bezt->h2) { \
766                         if ELEM3(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM) bezt->h1= HD_FREE; \
767                         if ELEM3(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM) bezt->h2= HD_FREE; \
768                 }
769
770 /* Sets the selected bezier handles to type 'auto' */
771 static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
772 {
773         if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
774                 if (bezt->f1 & SELECT) bezt->h1= HD_AUTO;
775                 if (bezt->f3 & SELECT) bezt->h2= HD_AUTO;
776                 
777                 ENSURE_HANDLES_MATCH(bezt);
778         }
779         return 0;
780 }
781
782 /* Sets the selected bezier handles to type 'auto-clamped'
783  * NOTE: this is like auto above, but they're handled a bit different
784  */
785 static short set_bezier_auto_clamped(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
786 {
787         if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
788                 if (bezt->f1 & SELECT) bezt->h1= HD_AUTO_ANIM;
789                 if (bezt->f3 & SELECT) bezt->h2= HD_AUTO_ANIM;
790                 
791                 ENSURE_HANDLES_MATCH(bezt);
792         }
793         return 0;
794 }
795
796 /* Sets the selected bezier handles to type 'vector'  */
797 static short set_bezier_vector(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
798 {
799         if (bezt->f1 & SELECT) bezt->h1= HD_VECT;
800         if (bezt->f3 & SELECT) bezt->h2= HD_VECT;
801         return 0;
802 }
803
804 /* Queries if the handle should be set to 'free' or 'align' */
805 // NOTE: this was used for the 'toggle free/align' option
806 //              currently this isn't used, but may be restored later
807 static short bezier_isfree(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
808 {
809         if ((bezt->f1 & SELECT) && (bezt->h1)) return 1;
810         if ((bezt->f3 & SELECT) && (bezt->h2)) return 1;
811         return 0;
812 }
813
814 /* Sets selected bezier handles to type 'align' */
815 static short set_bezier_align(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
816 {       
817         if (bezt->f1 & SELECT) bezt->h1= HD_ALIGN;
818         if (bezt->f3 & SELECT) bezt->h2= HD_ALIGN;
819         return 0;
820 }
821
822 /* Sets selected bezier handles to type 'free'  */
823 static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
824 {
825         if (bezt->f1 & SELECT) bezt->h1= HD_FREE;
826         if (bezt->f3 & SELECT) bezt->h2= HD_FREE;
827         return 0;
828 }
829
830 /* Set all selected Bezier Handles to a single type */
831 // calchandles_fcurve
832 KeyframeEditFunc ANIM_editkeyframes_handles(short code)
833 {
834         switch (code) {
835                 case HD_AUTO: /* auto */
836                         return set_bezier_auto;
837                 case HD_AUTO_ANIM: /* auto clamped */
838                         return set_bezier_auto_clamped;
839                         
840                 case HD_VECT: /* vector */
841                         return set_bezier_vector;
842                 case HD_FREE: /* free */
843                         return set_bezier_free;
844                 case HD_ALIGN: /* align */
845                         return set_bezier_align;
846                 
847                 default: /* check for toggle free or align? */
848                         return bezier_isfree;
849         }
850 }
851
852 /* ------- */
853
854 static short set_bezt_constant(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
855 {
856         if (bezt->f2 & SELECT) 
857                 bezt->ipo= BEZT_IPO_CONST;
858         return 0;
859 }
860
861 static short set_bezt_linear(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
862 {
863         if (bezt->f2 & SELECT) 
864                 bezt->ipo= BEZT_IPO_LIN;
865         return 0;
866 }
867
868 static short set_bezt_bezier(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
869 {
870         if (bezt->f2 & SELECT) 
871                 bezt->ipo= BEZT_IPO_BEZ;
872         return 0;
873 }
874
875 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
876 // ANIM_editkeyframes_ipocurve_ipotype() !
877 KeyframeEditFunc ANIM_editkeyframes_ipo(short code)
878 {
879         switch (code) {
880                 case BEZT_IPO_CONST: /* constant */
881                         return set_bezt_constant;
882                 case BEZT_IPO_LIN: /* linear */ 
883                         return set_bezt_linear;
884                 default: /* bezier */
885                         return set_bezt_bezier;
886         }
887 }
888
889 /* ------- */
890
891 static short set_keytype_keyframe(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
892 {
893         if (bezt->f2 & SELECT) 
894                 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_KEYFRAME;
895         return 0;
896 }
897
898 static short set_keytype_breakdown(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
899 {
900         if (bezt->f2 & SELECT) 
901                 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_BREAKDOWN;
902         return 0;
903 }
904
905 static short set_keytype_extreme(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
906 {
907         if (bezt->f2 & SELECT) 
908                 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_EXTREME;
909         return 0;
910 }
911
912 static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
913 {
914         if (bezt->f2 & SELECT) 
915                 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_JITTER;
916         return 0;
917 }
918
919 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
920 KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
921 {
922         switch (code) {
923                 case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */
924                         return set_keytype_breakdown;
925                         
926                 case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */
927                         return set_keytype_extreme;
928                         
929                 case BEZT_KEYTYPE_JITTER: /* jitter keyframe */
930                         return set_keytype_jitter;
931                         
932                 case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */       
933                 default:
934                         return set_keytype_keyframe;
935         }
936 }
937
938 /* ******************************************* */
939 /* Selection */
940
941 static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt) 
942 {
943         /* if we've got info on what to select, use it, otherwise select all */
944         if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) {
945                 if (ked->curflags & KEYFRAME_OK_KEY)
946                         bezt->f2 |= SELECT;
947                 if (ked->curflags & KEYFRAME_OK_H1)
948                         bezt->f1 |= SELECT;
949                 if (ked->curflags & KEYFRAME_OK_H2)
950                         bezt->f3 |= SELECT;
951         }
952         else {
953                 BEZ_SEL(bezt);
954         }
955         
956         return 0;
957 }
958
959 static short select_bezier_subtract(KeyframeEditData *ked, BezTriple *bezt) 
960 {
961         /* if we've got info on what to deselect, use it, otherwise deselect all */
962         if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) {
963                 if (ked->curflags & KEYFRAME_OK_KEY)
964                         bezt->f2 &= ~SELECT;
965                 if (ked->curflags & KEYFRAME_OK_H1)
966                         bezt->f1 &= ~SELECT;
967                 if (ked->curflags & KEYFRAME_OK_H2)
968                         bezt->f3 &= ~SELECT;
969         }
970         else {
971                 BEZ_DESEL(bezt);
972         }
973         
974         return 0;
975 }
976
977 static short select_bezier_invert(KeyframeEditData *UNUSED(ked), BezTriple *bezt) 
978 {
979         /* Invert the selection for the whole bezier triple */
980         bezt->f2 ^= SELECT;
981         if (bezt->f2 & SELECT) {
982                 bezt->f1 |= SELECT;
983                 bezt->f3 |= SELECT;
984         }
985         else {
986                 bezt->f1 &= ~SELECT;
987                 bezt->f3 &= ~SELECT;
988         }
989         return 0;
990 }
991
992 KeyframeEditFunc ANIM_editkeyframes_select(short selectmode)
993 {
994         switch (selectmode) {
995                 case SELECT_ADD: /* add */
996                         return select_bezier_add;
997                 case SELECT_SUBTRACT: /* subtract */
998                         return select_bezier_subtract;
999                 case SELECT_INVERT: /* invert */
1000                         return select_bezier_invert;
1001                 default: /* replace (need to clear all, then add) */
1002                         return select_bezier_add;
1003         }
1004 }
1005
1006 /* ******************************************* */
1007 /* Selection Maps */
1008
1009 /* Selection maps are simply fancy names for char arrays that store on/off
1010  * info for whether the selection status. The main purpose for these is to
1011  * allow extra info to be tagged to the keyframes without influencing their
1012  * values or having to be removed later.
1013  */
1014
1015 /* ----------- */
1016
1017 static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt)
1018 {
1019         FCurve *fcu= ked->fcu;
1020         char *map= ked->data;
1021         int i= ked->curIndex;
1022         
1023         /* if current is selected, just make sure it stays this way */
1024         if (BEZSELECTED(bezt)) {
1025                 map[i]= 1;
1026                 return 0;
1027         }
1028         
1029         /* if previous is selected, that means that selection should extend across */
1030         if (i > 0) {
1031                 BezTriple *prev= bezt - 1;
1032                 
1033                 if (BEZSELECTED(prev)) {
1034                         map[i]= 1;
1035                         return 0;
1036                 }
1037         }
1038         
1039         /* if next is selected, that means that selection should extend across */
1040         if (i < (fcu->totvert-1)) {
1041                 BezTriple *next= bezt + 1;
1042                 
1043                 if (BEZSELECTED(next)) {
1044                         map[i]= 1;
1045                         return 0;
1046                 }
1047         }
1048         
1049         return 0;
1050 }
1051
1052 static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
1053 {
1054         FCurve *fcu= ked->fcu;
1055         char *map= ked->data;
1056         int i= ked->curIndex;
1057         
1058         /* if current is selected, check the left/right keyframes
1059          * since it might need to be deselected (but otherwise no)
1060          */
1061         if (BEZSELECTED(bezt)) {
1062                 /* if previous is not selected, we're on the tip of an iceberg */
1063                 if (i > 0) {
1064                         BezTriple *prev= bezt - 1;
1065                         
1066                         if (BEZSELECTED(prev) == 0)
1067                                 return 0;
1068                 }
1069                 else if (i == 0) {
1070                         /* current keyframe is selected at an endpoint, so should get deselected */
1071                         return 0;
1072                 }
1073                 
1074                 /* if next is not selected, we're on the tip of an iceberg */
1075                 if (i < (fcu->totvert-1)) {
1076                         BezTriple *next= bezt + 1;
1077                         
1078                         if (BEZSELECTED(next) == 0)
1079                                 return 0;
1080                 }
1081                 else if (i == (fcu->totvert-1)) {
1082                         /* current keyframe is selected at an endpoint, so should get deselected */
1083                         return 0;
1084                 }
1085                 
1086                 /* if we're still here, that means that keyframe should remain untouched */
1087                 map[i]= 1;
1088         }
1089         
1090         return 0;
1091 }
1092
1093 /* Get callback for building selection map */
1094 KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
1095 {
1096         switch (mode) {
1097                 case SELMAP_LESS: /* less */
1098                         return selmap_build_bezier_less;
1099                 
1100                 case SELMAP_MORE: /* more */
1101                 default:
1102                         return selmap_build_bezier_more;
1103         }
1104 }
1105
1106 /* ----------- */
1107
1108 /* flush selection map values to the given beztriple */
1109 short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
1110 {
1111         char *map= ked->data;
1112         short on= map[ked->curIndex];
1113         
1114         /* select or deselect based on whether the map allows it or not */
1115         if (on) {
1116                 BEZ_SEL(bezt);
1117         }
1118         else {
1119                 BEZ_DESEL(bezt);
1120         }
1121         
1122         return 0;
1123 }
1124