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:
parent
63f9cb5a0b
commit
37b93b5df8
Notes:
blender-bot
2023-02-14 11:01:33 +01:00
Referenced by issue #81785, Implementation: Modal Key Manipulation Operators
|
@ -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):
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
/** \} */
|
||||
|
|
Loading…
Reference in New Issue