[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