4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20 * The Original Code is Copyright (C) 2008 Blender Foundation
22 * Contributor(s): Joshua Leung
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/editors/animation/keyframes_edit.c
28 * \ingroup edanimation
37 #include "MEM_guardedalloc.h"
39 #include "BLI_blenlib.h"
41 #include "BLI_utildefines.h"
43 #include "DNA_anim_types.h"
44 #include "DNA_armature_types.h"
45 #include "DNA_camera_types.h"
46 #include "DNA_key_types.h"
47 #include "DNA_lamp_types.h"
48 #include "DNA_lattice_types.h"
49 #include "DNA_mesh_types.h"
50 #include "DNA_material_types.h"
51 #include "DNA_object_types.h"
52 #include "DNA_meta_types.h"
53 #include "DNA_node_types.h"
54 #include "DNA_particle_types.h"
55 #include "DNA_scene_types.h"
56 #include "DNA_world_types.h"
58 #include "BKE_fcurve.h"
60 #include "BKE_material.h"
63 #include "ED_anim_api.h"
64 #include "ED_keyframes_edit.h"
65 #include "ED_markers.h"
67 /* This file defines an API and set of callback-operators for non-destructive editing of keyframe data.
69 * Two API functions are defined for actually performing the operations on the data:
70 * ANIM_fcurve_keyframes_loop()
71 * which take the data they operate on, a few callbacks defining what operations to perform.
73 * As operators which work on keyframes usually apply the same operation on all BezTriples in
74 * every channel, the code has been optimised providing a set of functions which will get the
75 * appropriate bezier-modify function to set. These functions (ANIM_editkeyframes_*) will need
76 * to be called before getting any channels.
78 * A set of 'validation' callbacks are provided for checking if a BezTriple should be operated on.
79 * These should only be used when using a 'general' BezTriple editor (i.e. selection setters which
80 * don't check existing selection status).
82 * - Joshua Leung, Dec 2008
85 /* ************************************************************************** */
86 /* Keyframe Editing Loops - Exposed API */
88 /* --------------------------- Base Functions ------------------------------------ */
90 /* This function is used to loop over BezTriples in the given F-Curve, applying a given
91 * operation on them, and optionally applies an F-Curve validation function afterwards.
93 // TODO: make this function work on samples too...
94 short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
101 if (ELEM(NULL, fcu, fcu->bezt))
104 /* set the F-Curve into the editdata so that it can be accessed */
111 /* if function to apply to bezier curves is set, then loop through executing it on beztriples */
113 /* if there's a validation func, include that check in the loop
114 * (this is should be more efficient than checking for it in every loop)
117 for (bezt=fcu->bezt, i=0; i < fcu->totvert; bezt++, i++) {
119 /* advance the index, and reset the ok flags (to not influence the result) */
124 /* Only operate on this BezTriple if it fullfills the criteria of the validation func */
125 if ( (ok = key_ok(ked, bezt)) ) {
126 if (ked) ked->curflags= ok;
128 /* Exit with return-code '1' if function returns positive
129 * This is useful if finding if some BezTriple satisfies a condition.
131 if (key_cb(ked, bezt)) return 1;
136 for (bezt=fcu->bezt, i=0; i < fcu->totvert; bezt++, i++) {
137 if (ked) ked->curIndex= i;
139 /* Exit with return-code '1' if function returns positive
140 * This is useful if finding if some BezTriple satisfies a condition.
142 if (key_cb(ked, bezt)) return 1;
147 /* unset the F-Curve from the editdata now that it's done */
154 /* if fcu_cb (F-Curve post-editing callback) has been specified then execute it */
162 /* -------------------------------- Further Abstracted (Not Exposed Directly) ----------------------------- */
164 /* This function is used to loop over the keyframe data in an Action Group */
165 static short agrp_keyframes_loop(KeyframeEditData *ked, bActionGroup *agrp, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
173 /* only iterate over the F-Curves that are in this group */
174 for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next) {
175 if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb))
182 /* This function is used to loop over the keyframe data in an Action */
183 static short act_keyframes_loop(KeyframeEditData *ked, bAction *act, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
191 /* just loop through all F-Curves */
192 for (fcu= act->curves.first; fcu; fcu= fcu->next) {
193 if (ANIM_fcurve_keyframes_loop(ked, fcu, key_ok, key_cb, fcu_cb))
200 /* This function is used to loop over the keyframe data in an Object */
201 static short ob_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Object *ob, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
203 bAnimContext ac = {NULL};
204 ListBase anim_data = {NULL, NULL};
209 bAnimListElem dummychan = {0};
210 Base dummybase = {0};
215 /* create a dummy wrapper data to work with */
216 dummybase.object = ob;
218 dummychan.type = ANIMTYPE_OBJECT;
219 dummychan.data = &dummybase;
220 dummychan.id = &ob->id;
221 dummychan.adt = ob->adt;
224 ac.data = &dummychan;
225 ac.datatype = ANIMCONT_CHANNEL;
227 /* get F-Curves to take keyframes from */
228 filter= ANIMFILTER_DATA_VISIBLE; // curves only
229 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
231 /* loop through each F-Curve, applying the operation as required, but stopping on the first one */
232 for (ale= anim_data.first; ale; ale= ale->next) {
233 if (ANIM_fcurve_keyframes_loop(ked, (FCurve*)ale->data, key_ok, key_cb, fcu_cb)) {
239 BLI_freelistN(&anim_data);
241 /* return return code - defaults to zero if nothing happened */
245 /* This function is used to loop over the keyframe data in a Scene */
246 static short scene_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Scene *sce, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
248 bAnimContext ac = {NULL};
249 ListBase anim_data = {NULL, NULL};
254 bAnimListElem dummychan = {0};
259 /* create a dummy wrapper data to work with */
260 dummychan.type = ANIMTYPE_SCENE;
261 dummychan.data = sce;
262 dummychan.id = &sce->id;
263 dummychan.adt = sce->adt;
266 ac.data = &dummychan;
267 ac.datatype = ANIMCONT_CHANNEL;
269 /* get F-Curves to take keyframes from */
270 filter= ANIMFILTER_DATA_VISIBLE; // curves only
271 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
273 /* loop through each F-Curve, applying the operation as required, but stopping on the first one */
274 for (ale= anim_data.first; ale; ale= ale->next) {
275 if (ANIM_fcurve_keyframes_loop(ked, (FCurve*)ale->data, key_ok, key_cb, fcu_cb)) {
281 BLI_freelistN(&anim_data);
283 /* return return code - defaults to zero if nothing happened */
287 /* This function is used to loop over the keyframe data in a DopeSheet summary */
288 static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
290 ListBase anim_data = {NULL, NULL};
292 int filter, ret_code=0;
298 /* get F-Curves to take keyframes from */
299 filter= ANIMFILTER_DATA_VISIBLE;
300 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
302 /* loop through each F-Curve, working on the keyframes until the first curve aborts */
303 for (ale= anim_data.first; ale; ale= ale->next) {
304 ret_code= ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb);
310 BLI_freelistN(&anim_data);
317 /* This function is used to apply operation to all keyframes, regardless of the type */
318 short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, bAnimListElem *ale, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
324 /* method to use depends on the type of keyframe data */
325 switch (ale->datatype) {
326 /* direct keyframe data (these loops are exposed) */
327 case ALE_FCURVE: /* F-Curve */
328 return ANIM_fcurve_keyframes_loop(ked, ale->key_data, key_ok, key_cb, fcu_cb);
330 /* indirect 'summaries' (these are not exposed directly)
331 * NOTE: must keep this code in sync with the drawing code and also the filtering code!
333 case ALE_GROUP: /* action group */
334 return agrp_keyframes_loop(ked, (bActionGroup *)ale->data, key_ok, key_cb, fcu_cb);
335 case ALE_ACT: /* action */
336 return act_keyframes_loop(ked, (bAction *)ale->key_data, key_ok, key_cb, fcu_cb);
338 case ALE_OB: /* object */
339 return ob_keyframes_loop(ked, ads, (Object *)ale->key_data, key_ok, key_cb, fcu_cb);
340 case ALE_SCE: /* scene */
341 return scene_keyframes_loop(ked, ads, (Scene *)ale->data, key_ok, key_cb, fcu_cb);
342 case ALE_ALL: /* 'all' (DopeSheet summary) */
343 return summary_keyframes_loop(ked, (bAnimContext *)ale->data, key_ok, key_cb, fcu_cb);
349 /* This function is used to apply operation to all keyframes, regardless of the type without needed an AnimListElem wrapper */
350 short ANIM_animchanneldata_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, void *data, int keytype, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
356 /* method to use depends on the type of keyframe data */
358 /* direct keyframe data (these loops are exposed) */
359 case ALE_FCURVE: /* F-Curve */
360 return ANIM_fcurve_keyframes_loop(ked, data, key_ok, key_cb, fcu_cb);
362 /* indirect 'summaries' (these are not exposed directly)
363 * NOTE: must keep this code in sync with the drawing code and also the filtering code!
365 case ALE_GROUP: /* action group */
366 return agrp_keyframes_loop(ked, (bActionGroup *)data, key_ok, key_cb, fcu_cb);
367 case ALE_ACT: /* action */
368 return act_keyframes_loop(ked, (bAction *)data, key_ok, key_cb, fcu_cb);
370 case ALE_OB: /* object */
371 return ob_keyframes_loop(ked, ads, (Object *)data, key_ok, key_cb, fcu_cb);
372 case ALE_SCE: /* scene */
373 return scene_keyframes_loop(ked, ads, (Scene *)data, key_ok, key_cb, fcu_cb);
374 case ALE_ALL: /* 'all' (DopeSheet summary) */
375 return summary_keyframes_loop(ked, (bAnimContext *)data, key_ok, key_cb, fcu_cb);
381 /* ************************************************************************** */
382 /* Keyframe Integrity Tools */
384 /* Rearrange keyframes if some are out of order */
385 // used to be recalc_*_ipos() where * was object or action
386 void ANIM_editkeyframes_refresh(bAnimContext *ac)
388 ListBase anim_data = {NULL, NULL};
392 /* filter animation data */
393 filter= ANIMFILTER_DATA_VISIBLE;
394 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
396 /* loop over F-Curves that are likely to have been edited, and check them */
397 for (ale= anim_data.first; ale; ale= ale->next) {
398 FCurve *fcu= ale->key_data;
400 /* make sure keyframes in F-Curve are all in order, and handles are in valid positions */
401 sort_time_fcurve(fcu);
402 testhandles_fcurve(fcu);
406 BLI_freelistN(&anim_data);
409 /* ************************************************************************** */
410 /* BezTriple Validation Callbacks */
412 /* ------------------------ */
413 /* Some macros to make this easier... */
415 /* run the given check on the 3 handles
416 * - check should be a macro, which takes the handle index as its single arg, which it substitutes later
417 * - requires that a var, of type short, is named 'ok', and has been initialized to 0
419 #define KEYFRAME_OK_CHECKS(check) \
422 ok |= KEYFRAME_OK_KEY; \
424 if (ked && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) { \
426 ok |= KEYFRAME_OK_H1; \
428 ok |= KEYFRAME_OK_H2; \
432 /* ------------------------ */
434 static short ok_bezier_frame(KeyframeEditData *ked, BezTriple *bezt)
438 /* frame is stored in f1 property (this float accuracy check may need to be dropped?) */
439 #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][0], ked->f1)
440 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
443 /* return ok flags */
447 static short ok_bezier_framerange(KeyframeEditData *ked, BezTriple *bezt)
451 /* frame range is stored in float properties */
452 #define KEY_CHECK_OK(_index) ((bezt->vec[_index][0] > ked->f1) && (bezt->vec[_index][0] < ked->f2))
453 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
456 /* return ok flags */
460 static short ok_bezier_selected(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
462 /* this macro checks all beztriple handles for selection...
463 * only one of the verts has to be selected for this to be ok...
465 if (BEZSELECTED(bezt))
466 return KEYFRAME_OK_ALL;
471 static short ok_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
475 /* value is stored in f1 property
476 * - this float accuracy check may need to be dropped?
477 * - should value be stored in f2 instead so that we won't have conflicts when using f1 for frames too?
479 #define KEY_CHECK_OK(_index) IS_EQF(bezt->vec[_index][1], ked->f1)
480 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
483 /* return ok flags */
487 static short ok_bezier_valuerange(KeyframeEditData *ked, BezTriple *bezt)
491 /* value range is stored in float properties */
492 #define KEY_CHECK_OK(_index) ((bezt->vec[_index][1] > ked->f1) && (bezt->vec[_index][1] < ked->f2))
493 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
496 /* return ok flags */
500 static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt)
502 /* rect is stored in data property (it's of type rectf, but may not be set) */
506 #define KEY_CHECK_OK(_index) BLI_in_rctf(ked->data, bezt->vec[_index][0], bezt->vec[_index][1])
507 KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
510 /* return ok flags */
518 KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
520 /* eEditKeyframes_Validate */
522 case BEZT_OK_FRAME: /* only if bezt falls on the right frame (float) */
523 return ok_bezier_frame;
524 case BEZT_OK_FRAMERANGE: /* only if bezt falls within the specified frame range (floats) */
525 return ok_bezier_framerange;
526 case BEZT_OK_SELECTED: /* only if bezt is selected (self) */
527 return ok_bezier_selected;
528 case BEZT_OK_VALUE: /* only if bezt value matches (float) */
529 return ok_bezier_value;
530 case BEZT_OK_VALUERANGE: /* only if bezier falls within the specified value range (floats) */
531 return ok_bezier_valuerange;
532 case BEZT_OK_REGION: /* only if bezier falls within the specified rect (data -> rectf) */
533 return ok_bezier_region;
534 default: /* nothing was ok */
539 /* ******************************************* */
540 /* Assorted Utility Functions */
542 /* helper callback for <animeditor>_cfrasnap_exec() -> used to help get the average time of all selected beztriples */
543 short bezt_calc_average(KeyframeEditData *ked, BezTriple *bezt)
545 /* only if selected */
546 if (bezt->f2 & SELECT) {
547 /* store average time in float 1 (only do rounding at last step) */
548 ked->f1 += bezt->vec[1][0];
550 /* store average value in float 2 (only do rounding at last step)
551 * - this isn't always needed, but some operators may also require this
553 ked->f2 += bezt->vec[1][1];
555 /* increment number of items */
562 /* helper callback for columnselect_<animeditor>_keys() -> populate list CfraElems with frame numbers from selected beztriples */
563 short bezt_to_cfraelem(KeyframeEditData *ked, BezTriple *bezt)
565 /* only if selected */
566 if (bezt->f2 & SELECT) {
567 CfraElem *ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
568 BLI_addtail(&ked->list, ce);
570 ce->cfra= bezt->vec[1][0];
576 /* used to remap times from one range to another
577 * requires: ked->data = KeyframeEditCD_Remap
579 void bezt_remap_times(KeyframeEditData *ked, BezTriple *bezt)
581 KeyframeEditCD_Remap *rmap= (KeyframeEditCD_Remap*)ked->data;
582 const float scale = (rmap->newMax - rmap->newMin) / (rmap->oldMax - rmap->oldMin);
584 /* perform transform on all three handles unless indicated otherwise */
585 // TODO: need to include some checks for that
587 bezt->vec[0][0]= scale*(bezt->vec[0][0] - rmap->oldMin) + rmap->newMin;
588 bezt->vec[1][0]= scale*(bezt->vec[1][0] - rmap->oldMin) + rmap->newMin;
589 bezt->vec[2][0]= scale*(bezt->vec[2][0] - rmap->oldMin) + rmap->newMin;
592 /* ******************************************* */
595 /* snaps the keyframe to the nearest frame */
596 static short snap_bezier_nearest(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
598 if (bezt->f2 & SELECT)
599 bezt->vec[1][0]= (float)(floorf(bezt->vec[1][0]+0.5f));
603 /* snaps the keyframe to the neares second */
604 static short snap_bezier_nearestsec(KeyframeEditData *ked, BezTriple *bezt)
606 const Scene *scene= ked->scene;
607 const float secf = (float)FPS;
609 if (bezt->f2 & SELECT)
610 bezt->vec[1][0]= ((float)floor(bezt->vec[1][0]/secf + 0.5f) * secf);
614 /* snaps the keyframe to the current frame */
615 static short snap_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
617 const Scene *scene= ked->scene;
618 if (bezt->f2 & SELECT)
619 bezt->vec[1][0]= (float)CFRA;
623 /* snaps the keyframe time to the nearest marker's frame */
624 static short snap_bezier_nearmarker(KeyframeEditData *ked, BezTriple *bezt)
626 if (bezt->f2 & SELECT)
627 bezt->vec[1][0]= (float)ED_markers_find_nearest_marker_time(&ked->list, bezt->vec[1][0]);
631 /* make the handles have the same value as the key */
632 static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
634 if (bezt->f2 & SELECT) {
635 bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
637 if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN;
638 if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN;
643 /* value to snap to is stored in the custom data -> first float value slot */
644 static short snap_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
646 if (bezt->f2 & SELECT)
647 bezt->vec[1][1]= ked->f1;
651 KeyframeEditFunc ANIM_editkeyframes_snap(short type)
653 /* eEditKeyframes_Snap */
655 case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
656 return snap_bezier_nearest;
657 case SNAP_KEYS_CURFRAME: /* snap to current frame */
658 return snap_bezier_cframe;
659 case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
660 return snap_bezier_nearmarker;
661 case SNAP_KEYS_NEARSEC: /* snap to nearest second */
662 return snap_bezier_nearestsec;
663 case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */
664 return snap_bezier_horizontal;
665 case SNAP_KEYS_VALUE: /* snap to given value */
666 return snap_bezier_value;
667 default: /* just in case */
668 return snap_bezier_nearest;
674 static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
676 const Scene *scene= ked->scene;
679 if (bezt->f2 & SELECT) {
680 diff= ((float)CFRA - bezt->vec[1][0]);
681 bezt->vec[1][0]= ((float)CFRA + diff);
687 static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
691 if (bezt->f2 & SELECT) {
692 diff= (0.0f - bezt->vec[1][0]);
693 bezt->vec[1][0]= (0.0f + diff);
699 static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
703 if (bezt->f2 & SELECT) {
704 diff= (0.0f - bezt->vec[1][1]);
705 bezt->vec[1][1]= (0.0f + diff);
711 static short mirror_bezier_marker(KeyframeEditData *ked, BezTriple *bezt)
713 /* mirroring time stored in f1 */
714 if (bezt->f2 & SELECT) {
715 const float diff= (ked->f1 - bezt->vec[1][0]);
716 bezt->vec[1][0]= (ked->f1 + diff);
722 static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
726 /* value to mirror over is stored in the custom data -> first float value slot */
727 if (bezt->f2 & SELECT) {
728 diff= (ked->f1 - bezt->vec[1][1]);
729 bezt->vec[1][1]= (ked->f1 + diff);
735 /* Note: for markers and 'value', the values to use must be supplied as the first float value */
736 // calchandles_fcurve
737 KeyframeEditFunc ANIM_editkeyframes_mirror(short type)
740 case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
741 return mirror_bezier_cframe;
742 case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
743 return mirror_bezier_yaxis;
744 case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
745 return mirror_bezier_xaxis;
746 case MIRROR_KEYS_MARKER: /* mirror over marker */
747 return mirror_bezier_marker;
748 case MIRROR_KEYS_VALUE: /* mirror over given value */
749 return mirror_bezier_value;
750 default: /* just in case */
751 return mirror_bezier_yaxis;
756 /* ******************************************* */
759 /* standard validation step for a few of these (implemented as macro for inlining without fn-call overhead):
760 * "if the handles are not of the same type, set them to type free"
762 #define ENSURE_HANDLES_MATCH(bezt) \
763 if (bezt->h1 != bezt->h2) { \
764 if ELEM3(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM) bezt->h1= HD_FREE; \
765 if ELEM3(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM) bezt->h2= HD_FREE; \
768 /* Sets the selected bezier handles to type 'auto' */
769 static short set_bezier_auto(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
771 if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
772 if (bezt->f1 & SELECT) bezt->h1= HD_AUTO;
773 if (bezt->f3 & SELECT) bezt->h2= HD_AUTO;
775 ENSURE_HANDLES_MATCH(bezt);
780 /* Sets the selected bezier handles to type 'auto-clamped'
781 * NOTE: this is like auto above, but they're handled a bit different
783 static short set_bezier_auto_clamped(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
785 if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
786 if (bezt->f1 & SELECT) bezt->h1= HD_AUTO_ANIM;
787 if (bezt->f3 & SELECT) bezt->h2= HD_AUTO_ANIM;
789 ENSURE_HANDLES_MATCH(bezt);
794 /* Sets the selected bezier handles to type 'vector' */
795 static short set_bezier_vector(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
797 if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
798 if (bezt->f1 & SELECT) bezt->h1= HD_VECT;
799 if (bezt->f3 & SELECT) bezt->h2= HD_VECT;
801 ENSURE_HANDLES_MATCH(bezt);
806 /* Queries if the handle should be set to 'free' or 'align' */
807 // NOTE: this was used for the 'toggle free/align' option
808 // currently this isn't used, but may be restored later
809 static short bezier_isfree(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
811 if ((bezt->f1 & SELECT) && (bezt->h1)) return 1;
812 if ((bezt->f3 & SELECT) && (bezt->h2)) return 1;
816 /* Sets selected bezier handles to type 'align' */
817 static short set_bezier_align(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
819 if (bezt->f1 & SELECT) bezt->h1= HD_ALIGN;
820 if (bezt->f3 & SELECT) bezt->h2= HD_ALIGN;
824 /* Sets selected bezier handles to type 'free' */
825 static short set_bezier_free(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
827 if (bezt->f1 & SELECT) bezt->h1= HD_FREE;
828 if (bezt->f3 & SELECT) bezt->h2= HD_FREE;
832 /* Set all selected Bezier Handles to a single type */
833 // calchandles_fcurve
834 KeyframeEditFunc ANIM_editkeyframes_handles(short code)
837 case HD_AUTO: /* auto */
838 return set_bezier_auto;
839 case HD_AUTO_ANIM: /* auto clamped */
840 return set_bezier_auto_clamped;
842 case HD_VECT: /* vector */
843 return set_bezier_vector;
844 case HD_FREE: /* free */
845 return set_bezier_free;
846 case HD_ALIGN: /* align */
847 return set_bezier_align;
849 default: /* check for toggle free or align? */
850 return bezier_isfree;
856 static short set_bezt_constant(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
858 if (bezt->f2 & SELECT)
859 bezt->ipo= BEZT_IPO_CONST;
863 static short set_bezt_linear(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
865 if (bezt->f2 & SELECT)
866 bezt->ipo= BEZT_IPO_LIN;
870 static short set_bezt_bezier(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
872 if (bezt->f2 & SELECT)
873 bezt->ipo= BEZT_IPO_BEZ;
877 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
878 // ANIM_editkeyframes_ipocurve_ipotype() !
879 KeyframeEditFunc ANIM_editkeyframes_ipo(short code)
882 case BEZT_IPO_CONST: /* constant */
883 return set_bezt_constant;
884 case BEZT_IPO_LIN: /* linear */
885 return set_bezt_linear;
886 default: /* bezier */
887 return set_bezt_bezier;
893 static short set_keytype_keyframe(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
895 if (bezt->f2 & SELECT)
896 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_KEYFRAME;
900 static short set_keytype_breakdown(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
902 if (bezt->f2 & SELECT)
903 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_BREAKDOWN;
907 static short set_keytype_extreme(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
909 if (bezt->f2 & SELECT)
910 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_EXTREME;
914 static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
916 if (bezt->f2 & SELECT)
917 BEZKEYTYPE(bezt)= BEZT_KEYTYPE_JITTER;
921 /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
922 KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
925 case BEZT_KEYTYPE_BREAKDOWN: /* breakdown */
926 return set_keytype_breakdown;
928 case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */
929 return set_keytype_extreme;
931 case BEZT_KEYTYPE_JITTER: /* jitter keyframe */
932 return set_keytype_jitter;
934 case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */
936 return set_keytype_keyframe;
940 /* ******************************************* */
943 static short select_bezier_add(KeyframeEditData *ked, BezTriple *bezt)
945 /* if we've got info on what to select, use it, otherwise select all */
946 if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) {
947 if (ked->curflags & KEYFRAME_OK_KEY)
949 if (ked->curflags & KEYFRAME_OK_H1)
951 if (ked->curflags & KEYFRAME_OK_H2)
961 static short select_bezier_subtract(KeyframeEditData *ked, BezTriple *bezt)
963 /* if we've got info on what to deselect, use it, otherwise deselect all */
964 if ((ked) && (ked->iterflags & KEYFRAME_ITER_INCL_HANDLES)) {
965 if (ked->curflags & KEYFRAME_OK_KEY)
967 if (ked->curflags & KEYFRAME_OK_H1)
969 if (ked->curflags & KEYFRAME_OK_H2)
979 static short select_bezier_invert(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
981 /* Invert the selection for the whole bezier triple */
983 if (bezt->f2 & SELECT) {
994 KeyframeEditFunc ANIM_editkeyframes_select(short selectmode)
996 switch (selectmode) {
997 case SELECT_ADD: /* add */
998 return select_bezier_add;
999 case SELECT_SUBTRACT: /* subtract */
1000 return select_bezier_subtract;
1001 case SELECT_INVERT: /* invert */
1002 return select_bezier_invert;
1003 default: /* replace (need to clear all, then add) */
1004 return select_bezier_add;
1008 /* ******************************************* */
1009 /* Selection Maps */
1011 /* Selection maps are simply fancy names for char arrays that store on/off
1012 * info for whether the selection status. The main purpose for these is to
1013 * allow extra info to be tagged to the keyframes without influencing their
1014 * values or having to be removed later.
1019 static short selmap_build_bezier_more(KeyframeEditData *ked, BezTriple *bezt)
1021 FCurve *fcu= ked->fcu;
1022 char *map= ked->data;
1023 int i= ked->curIndex;
1025 /* if current is selected, just make sure it stays this way */
1026 if (BEZSELECTED(bezt)) {
1031 /* if previous is selected, that means that selection should extend across */
1033 BezTriple *prev= bezt - 1;
1035 if (BEZSELECTED(prev)) {
1041 /* if next is selected, that means that selection should extend across */
1042 if (i < (fcu->totvert-1)) {
1043 BezTriple *next= bezt + 1;
1045 if (BEZSELECTED(next)) {
1054 static short selmap_build_bezier_less(KeyframeEditData *ked, BezTriple *bezt)
1056 FCurve *fcu= ked->fcu;
1057 char *map= ked->data;
1058 int i= ked->curIndex;
1060 /* if current is selected, check the left/right keyframes
1061 * since it might need to be deselected (but otherwise no)
1063 if (BEZSELECTED(bezt)) {
1064 /* if previous is not selected, we're on the tip of an iceberg */
1066 BezTriple *prev= bezt - 1;
1068 if (BEZSELECTED(prev) == 0)
1072 /* current keyframe is selected at an endpoint, so should get deselected */
1076 /* if next is not selected, we're on the tip of an iceberg */
1077 if (i < (fcu->totvert-1)) {
1078 BezTriple *next= bezt + 1;
1080 if (BEZSELECTED(next) == 0)
1083 else if (i == (fcu->totvert-1)) {
1084 /* current keyframe is selected at an endpoint, so should get deselected */
1088 /* if we're still here, that means that keyframe should remain untouched */
1095 /* Get callback for building selection map */
1096 KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode)
1099 case SELMAP_LESS: /* less */
1100 return selmap_build_bezier_less;
1102 case SELMAP_MORE: /* more */
1104 return selmap_build_bezier_more;
1110 /* flush selection map values to the given beztriple */
1111 short bezt_selmap_flush(KeyframeEditData *ked, BezTriple *bezt)
1113 char *map= ked->data;
1114 short on= map[ked->curIndex];
1116 /* select or deselect based on whether the map allows it or not */