diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_graph.py | 1 | ||||
-rw-r--r-- | source/blender/editors/animation/keyframes_edit.c | 55 | ||||
-rw-r--r-- | source/blender/editors/include/ED_keyframes_edit.h | 19 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_edit.c | 97 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_intern.h | 10 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_ops.c | 1 |
6 files changed, 183 insertions, 0 deletions
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index a9f2b9e9a36..db0020b7846 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -335,6 +335,7 @@ class GRAPH_MT_key_snap(Menu): layout.operator("graph.snap", text="Selection to Nearest Second").type = 'NEAREST_SECOND' layout.operator("graph.snap", text="Selection to Nearest Marker").type = 'NEAREST_MARKER' layout.operator("graph.snap", text="Flatten Handles").type = 'HORIZONTAL' + layout.operator("graph.equalize_handles", text="Equalize Handles").side = 'BOTH' layout.separator() layout.operator("graph.frame_jump", text="Cursor to Selection") layout.operator("graph.snap_cursor_value", text="Cursor Value to Selection") diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 145d67b7810..dfe6566df67 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -1283,6 +1283,61 @@ static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt) return 0; } +static void handle_flatten(float vec[3][3], const int idx, const float direction[2]) +{ + BLI_assert_msg(idx == 0 || idx == 2, "handle_flatten() expects a handle index"); + + add_v2_v2v2(vec[idx], vec[1], direction); +} + +static void handle_set_length(float vec[3][3], const int idx, const float handle_length) +{ + BLI_assert_msg(idx == 0 || idx == 2, "handle_set_length() expects a handle index"); + + float handle_direction[2]; + sub_v2_v2v2(handle_direction, vec[idx], vec[1]); + normalize_v2_length(handle_direction, handle_length); + add_v2_v2v2(vec[idx], vec[1], handle_direction); +} + +void ANIM_fcurve_equalize_keyframes_loop(FCurve *fcu, + const eEditKeyframes_Equalize mode, + const float handle_length, + const bool flatten) +{ + uint i; + BezTriple *bezt; + const float flat_direction_left[2] = {-handle_length, 0.f}; + const float flat_direction_right[2] = {handle_length, 0.f}; + + /* Loop through an F-Curves keyframes. */ + for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) { + if ((bezt->f2 & SELECT) == 0) { + continue; + } + + /* Perform handle equalization if mode is 'Both' or 'Left'. */ + if (mode & EQUALIZE_HANDLES_LEFT) { + if (flatten) { + handle_flatten(bezt->vec, 0, flat_direction_left); + } + else { + handle_set_length(bezt->vec, 0, handle_length); + } + } + + /* Perform handle equalization if mode is 'Both' or 'Right'. */ + if (mode & EQUALIZE_HANDLES_RIGHT) { + if (flatten) { + handle_flatten(bezt->vec, 2, flat_direction_right); + } + else { + handle_set_length(bezt->vec, 2, handle_length); + } + } + } +} + KeyframeEditFunc ANIM_editkeyframes_ipo(short mode) { switch (mode) { diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index c7e89030ee2..f006378658b 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -93,6 +93,13 @@ typedef enum eEditKeyframes_Snap { SNAP_KEYS_TIME, } eEditKeyframes_Snap; +/* equalizing tools */ +typedef enum eEditKeyframes_Equalize { + EQUALIZE_HANDLES_LEFT = (1 << 0), + EQUALIZE_HANDLES_RIGHT = (1 << 1), + EQUALIZE_HANDLES_BOTH = (EQUALIZE_HANDLES_LEFT | EQUALIZE_HANDLES_RIGHT), +} eEditKeyframes_Equalize; + /* mirroring tools */ typedef enum eEditKeyframes_Mirror { MIRROR_KEYS_CURFRAME = 1, @@ -259,6 +266,18 @@ short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb); /** + * Sets selected keyframes' bezier handles to an equal length and optionally makes + * the keyframes' handles horizontal. + * \param handle_length: Desired handle length, must be positive. + * \param flatten: Makes the keyframes' handles the same value as the keyframe, + * flattening the curve at that point. + */ +void ANIM_fcurve_equalize_keyframes_loop(struct FCurve *fcu, + eEditKeyframes_Equalize mode, + float handle_length, + bool flatten); + +/** * Function for working with any type (i.e. one of the known types) of animation channel. */ short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 2afee277847..9675901ead3 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -2353,6 +2353,103 @@ void GRAPH_OT_snap(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Equalize Handles Operator + * \{ */ + +/* Defines for equalize handles tool. */ +static const EnumPropertyItem prop_graphkeys_equalize_handles_sides[] = { + {GRAPHKEYS_EQUALIZE_LEFT, "LEFT", 0, "Left", "Equalize selected keyframes' left handles"}, + {GRAPHKEYS_EQUALIZE_RIGHT, "RIGHT", 0, "Right", "Equalize selected keyframes' right handles"}, + {GRAPHKEYS_EQUALIZE_BOTH, "BOTH", 0, "Both", "Equalize both of a keyframe's handles"}, + {0, NULL, 0, NULL, NULL}, +}; + +/* ------------------- */ + +/* Equalize selected keyframes' bezier handles. */ +static void equalize_graph_keys(bAnimContext *ac, int mode, float handle_length, bool flatten) +{ + /* Filter data. */ + const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | + ANIMFILTER_NODUPLIS); + ListBase anim_data = {NULL, NULL}; + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* Equalize keyframes. */ + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + ANIM_fcurve_equalize_keyframes_loop(ale->key_data, mode, handle_length, flatten); + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); +} + +static int graphkeys_equalize_handles_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + /* Get editor data. */ + if (ANIM_animdata_get_context(C, &ac) == 0) { + return OPERATOR_CANCELLED; + } + + /* Get equalize mode. */ + int mode = RNA_enum_get(op->ptr, "side"); + float handle_length = RNA_float_get(op->ptr, "handle_length"); + bool flatten = RNA_boolean_get(op->ptr, "flatten"); + + /* Equalize graph keyframes. */ + equalize_graph_keys(&ac, mode, handle_length, flatten); + + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GRAPH_OT_equalize_handles(wmOperatorType *ot) +{ + /* Identifiers */ + ot->name = "Equalize Handles"; + ot->idname = "GRAPH_OT_equalize_handles"; + ot->description = + "Ensure selected keyframes' handles have equal length, optionally making them horizontal"; + + /* API callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = graphkeys_equalize_handles_exec; + ot->poll = graphop_editable_keyframes_poll; + + /* Flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Properties */ + ot->prop = RNA_def_enum(ot->srna, + "side", + prop_graphkeys_equalize_handles_sides, + 0, + "Side", + "Side of the keyframes' bezier handles to affect"); + RNA_def_float(ot->srna, + "handle_length", + 5.0f, + 0.1f, + FLT_MAX, + "Handle Length", + "Length to make selected keyframes' bezier handles", + 1.0f, + 50.0f); + RNA_def_boolean( + ot->srna, + "flatten", + false, + "Flatten", + "Make the values of the selected keyframes' handles the same as their respective keyframes"); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Mirror Keyframes Operator * \{ */ diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index 243a4ee4b95..a59fb63dd22 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -144,6 +144,7 @@ void GRAPH_OT_easing_type(struct wmOperatorType *ot); void GRAPH_OT_frame_jump(struct wmOperatorType *ot); void GRAPH_OT_snap_cursor_value(struct wmOperatorType *ot); void GRAPH_OT_snap(struct wmOperatorType *ot); +void GRAPH_OT_equalize_handles(struct wmOperatorType *ot); void GRAPH_OT_mirror(struct wmOperatorType *ot); /* defines for snap keyframes @@ -158,6 +159,15 @@ enum eGraphKeys_Snap_Mode { GRAPHKEYS_SNAP_VALUE, }; +/* Defines for equalize keyframe handles. + * NOTE: Keep in sync with eEditKeyframes_Equalize (in ED_keyframes_edit.h). + */ +enum eGraphKeys_Equalize_Mode { + GRAPHKEYS_EQUALIZE_LEFT = 1, + GRAPHKEYS_EQUALIZE_RIGHT, + GRAPHKEYS_EQUALIZE_BOTH, +}; + /* defines for mirror keyframes * NOTE: keep in sync with eEditKeyframes_Mirror (in ED_keyframes_edit.h) */ diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index fe4cffcb3b8..7606dcc60cf 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -456,6 +456,7 @@ void graphedit_operatortypes(void) /* editing */ WM_operatortype_append(GRAPH_OT_snap); + WM_operatortype_append(GRAPH_OT_equalize_handles); WM_operatortype_append(GRAPH_OT_mirror); WM_operatortype_append(GRAPH_OT_frame_jump); WM_operatortype_append(GRAPH_OT_snap_cursor_value); |