Animation: Blend To Default Implementation

Add a new operator to the Graph Editor that blends selected keyframes
to their default value.
The operator can be accessed from
Key>Slider Operators>Blend To Default Value

Reviewed by: Sybren A. Stüvel
Differential Revision: https://developer.blender.org/D9376
Ref: D9367
This commit is contained in:
Christoph Lendenfeld 2022-03-18 20:07:16 +01:00
parent 63f9cb5a0b
commit 37b93b5df8
Notes: blender-bot 2023-02-14 11:01:33 +01:00
Referenced by issue #81785, Implementation: Modal Key Manipulation Operators
6 changed files with 195 additions and 0 deletions

View File

@ -332,6 +332,7 @@ class GRAPH_MT_slider(Menu):
layout.operator("graph.breakdown", text="Breakdown")
layout.operator("graph.blend_to_neighbor", text="Blend To Neighbor")
layout.operator("graph.blend_to_default", text="Blend To Default Value")
class GRAPH_MT_view_pie(Menu):

View File

@ -382,6 +382,68 @@ void blend_to_neighbor_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const
/* ---------------- */
float get_default_rna_value(FCurve *fcu, PropertyRNA *prop, PointerRNA *ptr)
{
const int len = RNA_property_array_length(ptr, prop);
float default_value = 0;
/* Find the default value of that property. */
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
if (len) {
default_value = RNA_property_boolean_get_default_index(ptr, prop, fcu->array_index);
}
else {
default_value = RNA_property_boolean_get_default(ptr, prop);
}
break;
case PROP_INT:
if (len) {
default_value = RNA_property_int_get_default_index(ptr, prop, fcu->array_index);
}
else {
default_value = RNA_property_int_get_default(ptr, prop);
}
break;
case PROP_FLOAT:
if (len) {
default_value = RNA_property_float_get_default_index(ptr, prop, fcu->array_index);
}
else {
default_value = RNA_property_float_get_default(ptr, prop);
}
break;
default:
break;
}
return default_value;
}
/* This function blends the selected keyframes to the default value of the property the fcurve
* drives. */
void blend_to_default_fcurve(PointerRNA *id_ptr, FCurve *fcu, const float factor)
{
PointerRNA ptr;
PropertyRNA *prop;
/* Check if path is valid. */
if (!RNA_path_resolve_property(id_ptr, fcu->rna_path, &ptr, &prop)) {
return;
}
const float default_value = get_default_rna_value(fcu, prop, &ptr);
/* Blend selected keys to default */
for (int i = 0; i < fcu->totvert; i++) {
if (fcu->bezt[i].f2 & SELECT) {
fcu->bezt[i].vec[1][1] = interpf(default_value, fcu->bezt[i].vec[1][1], factor);
}
}
}
/* ---------------- */
void breakdown_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
{
BezTriple left_bezt = fcurve_segment_start_get(fcu, segment->start_index);

View File

@ -382,6 +382,7 @@ void delete_fcurve_key(struct FCurve *fcu, int index, bool do_recalc);
bool delete_fcurve_keys(struct FCurve *fcu);
void clear_fcurve_keys(struct FCurve *fcu);
void duplicate_fcurve_keys(struct FCurve *fcu);
float get_default_rna_value(struct FCurve *fcu, struct PropertyRNA *prop, struct PointerRNA *ptr);
typedef struct FCurveSegment {
struct FCurveSegment *next, *prev;
@ -404,6 +405,7 @@ void blend_to_neighbor_fcurve_segment(struct FCurve *fcu,
float factor);
void breakdown_fcurve_segment(struct FCurve *fcu, struct FCurveSegment *segment, float factor);
bool decimate_fcurve(struct bAnimListElem *ale, float remove_ratio, float error_sq_max);
void blend_to_default_fcurve(struct PointerRNA *id_ptr, struct FCurve *fcu, float factor);
/**
* Use a weighted moving-means method to reduce intensity of fluctuations.
*/

View File

@ -113,6 +113,7 @@ void GRAPH_OT_clean(struct wmOperatorType *ot);
void GRAPH_OT_blend_to_neighbor(struct wmOperatorType *ot);
void GRAPH_OT_breakdown(struct wmOperatorType *ot);
void GRAPH_OT_decimate(struct wmOperatorType *ot);
void GRAPH_OT_blend_to_default(struct wmOperatorType *ot);
void GRAPH_OT_sample(struct wmOperatorType *ot);
void GRAPH_OT_bake(struct wmOperatorType *ot);
void GRAPH_OT_unbake(struct wmOperatorType *ot);

View File

@ -457,6 +457,7 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_decimate);
WM_operatortype_append(GRAPH_OT_blend_to_neighbor);
WM_operatortype_append(GRAPH_OT_breakdown);
WM_operatortype_append(GRAPH_OT_blend_to_default);
WM_operatortype_append(GRAPH_OT_euler_filter);
WM_operatortype_append(GRAPH_OT_delete);
WM_operatortype_append(GRAPH_OT_duplicate);

View File

@ -802,3 +802,131 @@ void GRAPH_OT_breakdown(wmOperatorType *ot)
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Blend To Default Value Operator
* \{ */
static void blend_to_default_graph_keys(bAnimContext *ac, const float factor)
{
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
FCurve *fcu = (FCurve *)ale->key_data;
/* Check if the curves actually have any points. */
if (fcu == NULL || fcu->bezt == NULL || fcu->totvert == 0) {
continue;
}
PointerRNA id_ptr;
RNA_id_pointer_create(ale->id, &id_ptr);
blend_to_default_fcurve(&id_ptr, fcu, factor);
ale->update |= ANIM_UPDATE_DEFAULT;
}
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
static void blend_to_default_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 Default Value"));
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_default_modal_update(bContext *C, wmOperator *op)
{
tGraphSliderOp *gso = op->customdata;
blend_to_default_draw_status_header(C, gso);
/* Set notifier that keyframes have changed. */
reset_bezts(gso);
const float factor = ED_slider_factor_get(gso->slider);
RNA_property_float_set(op->ptr, gso->factor_prop, factor);
blend_to_default_graph_keys(&gso->ac, factor);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
static int blend_to_default_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_default_modal_update;
gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
blend_to_default_draw_status_header(C, gso);
return invoke_result;
}
static int blend_to_default_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_default_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_default(wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Blend To Default Value";
ot->idname = "GRAPH_OT_blend_to_default";
ot->description = "Blend selected keys to their default value from their current position";
/* API callbacks. */
ot->invoke = blend_to_default_invoke;
ot->modal = graph_slider_modal;
ot->exec = blend_to_default_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,
"Factor",
"How much to blend to the default value",
0.0f,
1.0f);
}
/** \} */