Commit: 200a114e159695760cb5cb1d87fc5790b718971d Author: Christoph Lendenfeld Date: Thu Jan 5 10:39:39 2023 +0100 Branches: master https://developer.blender.org/rB200a114e159695760cb5cb1d87fc5790b718971d
Fix T87548: Propagate Pose, Next Keyframe Change the logic for propagating poses such that it checks keyframes on all selected bones to determine the frame on which a pose should be propagated to. It then adds keyframes if they don't exist on whatever frame the pose should be propagated to. Reviewd by: Sybren A. Stüvel Differential Revision: https://developer.blender.org/D16654 Ref: D16654 =================================================================== M source/blender/editors/armature/pose_slide.c =================================================================== diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 14b3451bd80..85af4e25454 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -48,6 +48,7 @@ #include "BKE_layer.h" #include "BKE_object.h" #include "BKE_report.h" +#include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_unit.h" @@ -64,6 +65,7 @@ #include "ED_armature.h" #include "ED_keyframes_keylist.h" +#include "ED_keyframing.h" #include "ED_markers.h" #include "ED_numinput.h" #include "ED_screen.h" @@ -1768,18 +1770,6 @@ typedef enum ePosePropagate_Termination { POSE_PROPAGATE_SELECTED_MARKERS, } ePosePropagate_Termination; -/** - * Termination data needed for some modes - - * assumes only one of these entries will be needed at a time. - */ -typedef union tPosePropagate_ModeData { - /** Smart holds + before frame: frame number to stop on. */ - float end_frame; - - /** Selected markers: listbase for CfraElem's marking these frames. */ - ListBase sel_markers; -} tPosePropagate_ModeData; - /* --------------------------------- */ /** @@ -1862,80 +1852,11 @@ static float pose_propagate_get_boneHoldEndFrame(tPChanFCurveLink *pfl, float st return endFrame; } -/** - * Get reference value from F-Curve using RNA. - */ -static bool pose_propagate_get_refVal(Object *ob, FCurve *fcu, float *value) -{ - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - bool found = false; - - /* Base pointer is always the `object -> id_ptr`. */ - RNA_id_pointer_create(&ob->id, &id_ptr); - - /* Resolve the property. */ - if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) { - if (RNA_property_array_check(prop)) { - /* Array. */ - if (fcu->array_index < RNA_property_array_length(&ptr, prop)) { - found = true; - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - *value = (float)RNA_property_boolean_get_index(&ptr, prop, fcu->array_index); - break; - case PROP_INT: - *value = (float)RNA_property_int_get_index(&ptr, prop, fcu->array_index); - break; - case PROP_FLOAT: - *value = RNA_property_float_get_index(&ptr, prop, fcu->array_index); - break; - default: - found = false; - break; - } - } - } - else { - /* Not an array. */ - found = true; - switch (RNA_property_type(prop)) { - case PROP_BOOLEAN: - *value = (float)RNA_property_boolean_get(&ptr, prop); - break; - case PROP_INT: - *value = (float)RNA_property_int_get(&ptr, prop); - break; - case PROP_ENUM: - *value = (float)RNA_property_enum_get(&ptr, prop); - break; - case PROP_FLOAT: - *value = RNA_property_float_get(&ptr, prop); - break; - default: - found = false; - break; - } - } - } - - return found; -} - /** * Propagate just works along each F-Curve in turn. */ -static void pose_propagate_fcurve( - wmOperator *op, Object *ob, FCurve *fcu, float startFrame, tPosePropagate_ModeData modeData) +static void pose_propagate_fcurve(FCurve *fcu, float start_frame, const float end_frame) { - const int mode = RNA_enum_get(op->ptr, "mode"); - - BezTriple *bezt; - float refVal = 0.0f; - bool keyExists; - int i; - bool first = true; - /* Skip if no keyframes to edit. */ if ((fcu->bezt == NULL) || (fcu->totvert < 2)) { return; @@ -1944,84 +1865,155 @@ static void pose_propagate_fcurve( /* Find the reference value from bones directly, which means that the user * doesn't need to firstly keyframe the pose (though this doesn't mean that * they can't either). */ - if (!pose_propagate_get_refVal(ob, fcu, &refVal)) { - return; - } + float refVal = evaluate_fcurve(fcu, start_frame); /* Find the first keyframe to start propagating from: * - if there's a keyframe on the current frame, we probably want to save this value there too * since it may be as of yet un-keyed * - if starting before the starting frame, don't touch the key, as it may have had some valid * values - * - if only doing selected keyframes, start from the first one */ - if (mode != POSE_PROPAGATE_SELECTED_KEYS) { - const int match = BKE_fcurve_bezt_binarysearch_index( - fcu->bezt, startFrame, fcu->totvert, &keyExists); + bool keyExists; + const int match = BKE_fcurve_bezt_binarysearch_index( + fcu->bezt, start_frame, fcu->totvert, &keyExists); - if (fcu->bezt[match].vec[1][0] < startFrame) { - i = match + 1; - } - else { - i = match; - } + int i; + if (fcu->bezt[match].vec[1][0] < start_frame) { + i = match + 1; } else { - /* Selected - start from first keyframe. */ - i = 0; + i = match; } + BezTriple *bezt; for (bezt = &fcu->bezt[i]; i < fcu->totvert; i++, bezt++) { /* Additional termination conditions based on the operator 'mode' property go here. */ - if (ELEM(mode, POSE_PROPAGATE_BEFORE_FRAME, POSE_PROPAGATE_SMART_HOLDS)) { - /* Stop if keyframe is outside the accepted range. */ - if (bezt->vec[1][0] > modeData.end_frame) { - break; - } - } - else if (mode == POSE_PROPAGATE_NEXT_KEY) { - /* Stop after the first keyframe has been processed. */ - if (first == false) { - break; - } + /* Stop if keyframe is outside the accepted range. */ + if (bezt->vec[1][0] > end_frame) { + break; } - else if (mode == POSE_PROPAGATE_LAST_KEY) { - /* Only affect this frame if it will be the last one. */ - if (i != (fcu->totvert - 1)) { - continue; + + /* Just flatten handles, since values will now be the same either side. */ + /* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */ + bezt->vec[0][1] = bezt->vec[1][1] = bezt->vec[2][1] = refVal; + + /* Select keyframe to indicate that it's been changed. */ + bezt->f2 |= SELECT; + } +} + +typedef struct FrameLink { + struct FrameLink *next, *prev; + float frame; +} FrameLink; + +static void propagate_curve_values(ListBase /*tPChanFCurveLink*/ *pflinks, + const float source_frame, + ListBase /*FrameLink*/ *target_frames) +{ + LISTBASE_FOREACH (tPChanFCurveLink *, pfl, pflinks) { + LISTBASE_FOREACH (LinkData *, ld, &pfl->fcurves) { + FCurve *fcu = (FCurve *)ld->data; + const float current_fcu_value = evaluate_fcurve(fcu, source_frame); + LISTBASE_FOREACH (FrameLink *, target_frame, target_frames) { + insert_vert_fcurve( + fcu, target_frame->frame, current_fcu_value, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NEEDED); } } - else if (mode == POSE_PROPAGATE_SELECTED_MARKERS) { - /* Only allow if there's a marker on this frame. */ - CfraElem *ce = NULL; - - /* Stop on matching marker if there is one. */ - for (ce = modeData.sel_markers.first; ce; ce = ce->next) { - if (ce->cfra == round_fl_to_int(bezt->vec[1][0])) { - break; - } - } + } +} - /* Skip this keyframe if no marker. */ - if (ce == NULL) { - continue; +static float find_next_key(ListBase *pflinks, const float start_frame) +{ + float target_frame = FLT_MAX; + LISTBASE_FOREACH (tPChanFCurveLink *, pfl, pflinks) { + LISTBASE_FOREACH (LinkData *, ld, &pfl->fcurves) { + FCurve *fcu = (FCurve *)ld->data; + bool replace; + int current_frame_index = BKE_fcurve_bezt_binarysearch_index( + fcu->bezt, start_frame, fcu->totvert, &replace); + if (replace) { + const int bezt_index = min_ii(current_frame_index + 1, fcu->totvert - 1); + target_frame = min_ff(target_frame, fcu->bezt[bezt_index].vec[1][0]); } - } - else if (mode == POSE_PROPAGATE_SELECTED_KEYS) { - /* Only allow if this keyframe is already selected - skip otherwise. */ - if (BEZT_ISSEL_ANY(bezt) == 0) { - continue; + else { + target_frame = min_ff(target_frame, fcu->bezt[current_frame_index].vec[1][0]); } } + } - /* Just flatten handles, since values will now be the same either side. */ - /* TODO: perhaps a fade-out modulation of the value is required here (optional once again)? */ - bezt->vec[0][1] = bezt->vec[1][1] = bezt->vec[2][1] = refVal; + return target_frame; +} - /* Select keyframe to indicate that it's been changed. */ - bezt->f2 |= SELECT; - first = false; +static float find_last_key(ListBase *pflinks) +{ + float target_frame = FLT_MIN; + LISTBASE_FOREACH (tPChanFCurveLink *, pfl, pflinks) { + LISTBASE_FOREACH (LinkData *, ld, &pfl->fcurves) { + FCurve *fcu = (FCurve *)ld->data; + target_frame = max_ff(target_frame, fcu->bezt[fcu->totvert - 1].vec[1][0]); + } + } + + return target_frame; +} + +static void get_selected_marker_positions(Scene *scene, ListBase /*FrameLink*/ *target_frames) +{ + ListBase selected_markers = {NULL, NULL}; + ED_markers_make_cfra_list(&scene->markers, &selected_markers, SELECT); + LISTBASE_FOREACH (CfraElem *, marker, &selected_markers) { + FrameLink *link = MEM_callocN(sizeof(FrameLink), "Marker Key Link"); + link->frame = marker->cfra; + BLI_addtail(target_frames, link); + } + BLI_freelistN(&selected_markers); +} + +static void get_keyed_frames_in_range(ListBase *pflinks, + const float start_frame, + const float end_frame, + ListBase /*FrameLink*/ *target_frames) +{ + struct AnimKeylist *keylist = ED_keylist_create(); + LISTBASE_FOREACH (tPChanFCurveLink *, pfl, pflinks) { + LISTBASE_FOREACH (LinkData *, ld, &pfl->fcurves) { + FCurve *fcu = (FCurve *)ld->data; + fcurve_to_keylist(NULL, fcu, keylist, 0); + } + } + LISTBASE_FOREACH (ActKeyColumn *, column, ED_keylist_listbase(keylist)) { + if (column->cfra <= start_frame) { + continue; + } + if (column->cfra > end_frame) { + break; + } + F @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
