Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Lendenfeld <chris.lend@gmx.at>2021-12-25 15:40:53 +0300
committerChristoph Lendenfeld <chris.lend@gmx.at>2021-12-25 15:40:53 +0300
commit9085b4a731fd5315eb97c00fc4bbf7c163698ebc (patch)
tree7d24710d413d7cea5ef1e808306a19fc8080ca4a
parente505957b47a9db99b958fa02325074120f129c94 (diff)
Blend To Neighbor Implementation
This patch adds the blend to neighbor operator to the Graph editor. The operator acts like the blend to neighbor operator for a pose context, just working on keyframes. Reviewed by: Sybren A. Stüvel Differential Revision: https://developer.blender.org/D9374 Ref: D9374
m---------release/scripts/addons0
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py11
-rw-r--r--source/blender/editors/animation/keyframes_general.c31
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h3
-rw-r--r--source/blender/editors/space_graph/graph_intern.h1
-rw-r--r--source/blender/editors/space_graph/graph_ops.c1
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c130
7 files changed, 177 insertions, 0 deletions
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject c60fef38175ad989ee0c45e924cb27e1417c866
+Subproject c08568cc376d2e4298710c4172fb0c74f0611de
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index 1562870d64f..497d68f88ca 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -298,6 +298,8 @@ class GRAPH_MT_key(Menu):
layout.operator("graph.decimate", text="Decimate (Allowed Change)").mode = 'ERROR'
layout.operator_context = operator_context
+ layout.menu("GRAPH_MT_slider", text="Slider Operators")
+
layout.operator("graph.clean").channels = False
layout.operator("graph.clean", text="Clean Channels").channels = True
layout.operator("graph.smooth")
@@ -337,6 +339,14 @@ class GRAPH_MT_key_snap(Menu):
layout.operator("graph.frame_jump", text="Cursor to Selection")
layout.operator("graph.snap_cursor_value", text="Cursor Value to Selection")
+class GRAPH_MT_slider(Menu):
+ bl_label = "Slider Operators"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator("graph.blend_to_neighbor", text="Blend To Neighbor")
+
class GRAPH_MT_view_pie(Menu):
bl_label = "View"
@@ -475,6 +485,7 @@ classes = (
GRAPH_MT_key,
GRAPH_MT_key_transform,
GRAPH_MT_key_snap,
+ GRAPH_MT_slider,
GRAPH_MT_delete,
GRAPH_MT_context_menu,
GRAPH_MT_channel_context_menu,
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 4fa5dee99a6..3c2e66d9367 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -367,6 +367,37 @@ ListBase find_fcurve_segments(FCurve *fcu)
return segments;
}
+static BezTriple fcurve_segment_start_get(FCurve *fcu, int index)
+{
+ BezTriple start_bezt = index - 1 >= 0 ? fcu->bezt[index - 1] : fcu->bezt[index];
+ return start_bezt;
+}
+
+static BezTriple fcurve_segment_end_get(FCurve *fcu, int index)
+{
+ BezTriple end_bezt = index < fcu->totvert ? fcu->bezt[index] : fcu->bezt[index - 1];
+ return end_bezt;
+}
+
+/* ---------------- */
+
+void blend_to_neighbor_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
+{
+ const float blend_factor = fabs(factor * 2 - 1);
+ BezTriple target_bezt;
+ /* Find which key to blend towards. */
+ if (factor < 0.5f) {
+ target_bezt = fcurve_segment_start_get(fcu, segment->start_index);
+ }
+ else {
+ target_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length);
+ }
+ /* Blend each key individually. */
+ for (int i = segment->start_index; i < segment->start_index + segment->length; i++) {
+ fcu->bezt[i].vec[1][1] = interpf(target_bezt.vec[1][1], fcu->bezt[i].vec[1][1], blend_factor);
+ }
+}
+
/* ---------------- */
/* Check if the keyframe interpolation type is supported */
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index 8a7831db0ea..084da038604 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -389,6 +389,9 @@ void clean_fcurve(struct bAnimContext *ac,
struct bAnimListElem *ale,
float thresh,
bool cleardefault);
+void blend_to_neighbor_fcurve_segment(struct FCurve *fcu,
+ struct FCurveSegment *segment,
+ const float factor);
bool decimate_fcurve(struct bAnimListElem *ale, float remove_ratio, float error_sq_max);
/**
* Use a weighted moving-means method to reduce intensity of fluctuations.
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 4db1eb5214e..ed52e684eb7 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -126,6 +126,7 @@ void GRAPH_OT_paste(struct wmOperatorType *ot);
void GRAPH_OT_duplicate(struct wmOperatorType *ot);
void GRAPH_OT_delete(struct wmOperatorType *ot);
void GRAPH_OT_clean(struct wmOperatorType *ot);
+void GRAPH_OT_blend_to_neighbor(struct wmOperatorType *ot);
void GRAPH_OT_decimate(struct wmOperatorType *ot);
void GRAPH_OT_sample(struct wmOperatorType *ot);
void GRAPH_OT_bake(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index ecafc75fc06..724d5351283 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -470,6 +470,7 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_smooth);
WM_operatortype_append(GRAPH_OT_clean);
WM_operatortype_append(GRAPH_OT_decimate);
+ WM_operatortype_append(GRAPH_OT_blend_to_neighbor);
WM_operatortype_append(GRAPH_OT_euler_filter);
WM_operatortype_append(GRAPH_OT_delete);
WM_operatortype_append(GRAPH_OT_duplicate);
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 30293f25332..a78e65aa3d6 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -551,3 +551,133 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend To Neighbor Operator
+ * \{ */
+
+static void blend_to_neighbor_graph_keys(bAnimContext *ac, float factor)
+{
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
+
+ bAnimListElem *ale;
+
+ /* Loop through filtered data and blend keys. */
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
+ blend_to_neighbor_fcurve_segment(fcu, segment, factor);
+ }
+ BLI_freelistN(&segments);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static void blend_to_neighbor_draw_status_header(bContext *C, tGraphSliderOp *gso)
+{
+ char status_str[UI_MAX_DRAW_STR];
+ char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
+
+ ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
+
+ strcpy(mode_str, TIP_("Blend To Neighbor"));
+
+ if (hasNumInput(&gso->num)) {
+ char str_ofs[NUM_STR_REP_LEN];
+
+ outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
+
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
+ }
+
+ ED_workspace_status_text(C, status_str);
+}
+
+static void blend_to_neighbor_modal_update(bContext *C, wmOperator *op)
+{
+ tGraphSliderOp *gso = op->customdata;
+
+ blend_to_neighbor_draw_status_header(C, gso);
+
+ /* Reset keyframe data to the state at invoke. */
+ reset_bezts(gso);
+
+ const float factor = ED_slider_factor_get(gso->slider);
+ RNA_property_float_set(op->ptr, gso->factor_prop, factor);
+ blend_to_neighbor_graph_keys(&gso->ac, factor);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
+
+static int blend_to_neighbor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const int invoke_result = graph_slider_invoke(C, op, event);
+
+ if (invoke_result == OPERATOR_CANCELLED) {
+ return invoke_result;
+ }
+
+ tGraphSliderOp *gso = op->customdata;
+ gso->modal_update = blend_to_neighbor_modal_update;
+ gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
+ blend_to_neighbor_draw_status_header(C, gso);
+
+ return invoke_result;
+}
+
+static int blend_to_neighbor_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const float factor = RNA_float_get(op->ptr, "factor");
+
+ blend_to_neighbor_graph_keys(&ac, factor);
+
+ /* Set notifier that keyframes have changed. */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_blend_to_neighbor(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Blend To Neighbor";
+ ot->idname = "GRAPH_OT_blend_to_neighbor";
+ ot->description = "Blend selected keyframes to their left or right neighbor";
+
+ /* API callbacks. */
+ ot->invoke = blend_to_neighbor_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = blend_to_neighbor_exec;
+ ot->poll = graphop_editable_keyframes_poll;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float_factor(ot->srna,
+ "factor",
+ 1.0f / 3.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Blend",
+ "The blend factor with 0.5 being the current frame",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */