[Bf-blender-cvs] [200a114e159] master: Fix T87548: Propagate Pose, Next Keyframe
Christoph Lendenfeld
noreply at git.blender.org
Thu Jan 5 10:39:50 CET 2023
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. @@
More information about the Bf-blender-cvs
mailing list