[Bf-blender-cvs] [226feb52eca] master: Cleanup: Animation, refactor Euler filter

Sybren A. Stüvel noreply at git.blender.org
Thu Nov 19 12:57:45 CET 2020


Commit: 226feb52eca303c31bc799034ec5eb7598383391
Author: Sybren A. Stüvel
Date:   Thu Nov 19 12:03:09 2020 +0100
Branches: master
https://developer.blender.org/rB226feb52eca303c31bc799034ec5eb7598383391

Cleanup: Animation, refactor Euler filter

Split up the Euler filter function into two more functions. The Euler
filter operator works in two stages (find channels that define the X/Y/Z
Euler rotations, and perform filtering on those channels), and each
stage now has its own function. This makes it clearer which data are
used in which part of the code, and makes future improvements easier.

No functional changes.

===================================================================

M	source/blender/editors/space_graph/graph_edit.c

===================================================================

diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index ae15b651059..bf76d4a632a 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -2610,39 +2610,18 @@ typedef struct tEulerFilter {
   const char *rna_path;
 } tEulerFilter;
 
-static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
+/* Find groups of `rotation_euler` channels. */
+static ListBase /*tEulerFilter*/ euler_filter_group_channels(
+    const ListBase /*bAnimListElem*/ *anim_data, ReportList *reports, int *r_num_groups)
 {
-  bAnimContext ac;
-
-  ListBase anim_data = {NULL, NULL};
-  bAnimListElem *ale;
-  int filter;
-
-  ListBase eulers = {NULL, NULL};
-  tEulerFilter *euf = NULL;
-  int groups = 0, failed = 0;
-
-  /* Get editor data. */
-  if (ANIM_animdata_get_context(C, &ac) == 0) {
-    return OPERATOR_CANCELLED;
-  }
-
-  /* The process is done in two passes:
-   * 1) Sets of three related rotation curves are identified from the selected channels,
-   *    and are stored as a single 'operation unit' for the next step.
-   * 2) Each set of three F-Curves is processed for each keyframe, with the values being
-   *    processed as necessary.
-   */
-
-  /* Step 1: extract only the rotation f-curves. */
-  filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE |
-            ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
-  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+  ListBase euler_groups = {NULL, NULL};
+  tEulerFilter *euf;
+  *r_num_groups = 0;
 
-  for (ale = anim_data.first; ale; ale = ale->next) {
-    FCurve *fcu = (FCurve *)ale->data;
+  LISTBASE_FOREACH (bAnimListElem *, ale, anim_data) {
+    FCurve *const fcu = (FCurve *)ale->data;
 
-    /* Check if this is an appropriate F-Curve
+    /* Check if this is an appropriate F-Curve:
      * - Only rotation curves.
      * - For pchan curves, make sure we're only using the euler curves.
      */
@@ -2650,7 +2629,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
       continue;
     }
     if (ELEM(fcu->array_index, 0, 1, 2) == 0) {
-      BKE_reportf(op->reports,
+      BKE_reportf(reports,
                   RPT_WARNING,
                   "Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)",
                   (ale->id) ? ale->id->name : TIP_("<No ID>"),
@@ -2659,6 +2638,10 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
       continue;
     }
 
+    /* Assume that this animation channel will be touched by the Euler filter. Doing this here
+     * saves another loop over the animation data. */
+    ale->update |= ANIM_UPDATE_DEFAULT;
+
     /* Optimization: assume that xyz curves will always be stored consecutively,
      * so if the paths or the ID's don't match up, then a curve needs to be added
      * to a new group.
@@ -2666,40 +2649,34 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
     if ((euf) && (euf->id == ale->id) && (STREQ(euf->rna_path, fcu->rna_path))) {
       /* This should be fine to add to the existing group then. */
       euf->fcurves[fcu->array_index] = fcu;
-    }
-    else {
-      /* Just add to a new block. */
-      euf = MEM_callocN(sizeof(tEulerFilter), "tEulerFilter");
-      BLI_addtail(&eulers, euf);
-      groups++;
-
-      euf->id = ale->id;
-      /* This should be safe, since we're only using it for a short time. */
-      euf->rna_path = fcu->rna_path;
-      euf->fcurves[fcu->array_index] = fcu;
+      continue;
     }
 
-    ale->update |= ANIM_UPDATE_DEFAULT;
-  }
+    /* Just add to a new block. */
+    euf = MEM_callocN(sizeof(tEulerFilter), "tEulerFilter");
+    BLI_addtail(&euler_groups, euf);
+    ++*r_num_groups;
 
-  if (groups == 0) {
-    ANIM_animdata_freelist(&anim_data);
-    BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up");
-    return OPERATOR_CANCELLED;
+    euf->id = ale->id;
+    /* This should be safe, since we're only using it for a short time. */
+    euf->rna_path = fcu->rna_path;
+    euf->fcurves[fcu->array_index] = fcu;
   }
 
-  /* Step 2: go through each set of curves, processing the values at each keyframe.
-   * - It is assumed that there must be a full set of keyframes at each keyframe position.
-   */
-  for (euf = eulers.first; euf; euf = euf->next) {
-    int f;
+  return euler_groups;
+}
+
+static int euler_filter_perform_filter(ListBase /*tEulerFilter*/ *eulers, ReportList *reports)
+{
+  int failed = 0;
 
+  LISTBASE_FOREACH (tEulerFilter *, euf, eulers) {
     /* Sanity check: ensure that there are enough F-Curves to work on in this group. */
     /* TODO: also enforce assumption that there be a full set of keyframes
      * at each position by ensuring that totvert counts are same? (Joshua Leung 2011) */
     if (ELEM(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) {
       /* Report which components are missing. */
-      BKE_reportf(op->reports,
+      BKE_reportf(reports,
                   RPT_WARNING,
                   "Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'",
                   (euf->fcurves[0] == NULL) ? "X" : "",
@@ -2717,7 +2694,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
      * keys of greater than 180 degrees as being a flip. */
     /* FIXME: there are more complicated methods that
      * will be needed to fix more cases than just some */
-    for (f = 0; f < 3; f++) {
+    for (int f = 0; f < 3; f++) {
       FCurve *fcu = euf->fcurves[f];
       BezTriple *bezt, *prev;
       uint i;
@@ -2732,21 +2709,62 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
       for (i = 1, prev = fcu->bezt, bezt = fcu->bezt + 1; i < fcu->totvert; i++, prev = bezt++) {
         const float sign = (prev->vec[1][1] > bezt->vec[1][1]) ? 1.0f : -1.0f;
 
-        /* > 180 degree flip? */
-        if ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) {
-          /* 360 degrees to add/subtract frame value until difference
-           * is acceptably small that there's no more flip. */
-          const float fac = sign * 2.0f * (float)M_PI;
+        /* >= 180 degree flip? */
+        if ((sign * (prev->vec[1][1] - bezt->vec[1][1])) < (float)M_PI) {
+          continue;
+        }
 
-          while ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) {
-            bezt->vec[0][1] += fac;
-            bezt->vec[1][1] += fac;
-            bezt->vec[2][1] += fac;
-          }
+        /* 360 degrees to add/subtract frame value until difference
+         * is acceptably small that there's no more flip. */
+        const float fac = sign * 2.0f * (float)M_PI;
+
+        while ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) {
+          bezt->vec[0][1] += fac;
+          bezt->vec[1][1] += fac;
+          bezt->vec[2][1] += fac;
         }
       }
     }
   }
+
+  return failed;
+}
+
+static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
+{
+  /* Get editor data. */
+  bAnimContext ac;
+  if (ANIM_animdata_get_context(C, &ac) == 0) {
+    return OPERATOR_CANCELLED;
+  }
+
+  /* The process is done in two passes:
+   * 1) Sets of three related rotation curves are identified from the selected channels,
+   *    and are stored as a single 'operation unit' for the next step.
+   * 2) Each set of three F-Curves is processed for each keyframe, with the values being
+   *    processed as necessary.
+   */
+
+  /* Step 1: extract only the rotation f-curves. */
+  const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE |
+                      ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+  ListBase anim_data = {NULL, NULL};
+  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+  int groups = 0;
+  ListBase eulers = euler_filter_group_channels(&anim_data, op->reports, &groups);
+  BLI_assert(BLI_listbase_count(&eulers) == groups);
+
+  if (groups == 0) {
+    ANIM_animdata_freelist(&anim_data);
+    BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up");
+    return OPERATOR_CANCELLED;
+  }
+
+  /* Step 2: go through each set of curves, processing the values at each keyframe.
+   * - It is assumed that there must be a full set of keyframes at each keyframe position.
+   */
+  const int failed = euler_filter_perform_filter(&eulers, op->reports);
   BLI_freelistN(&eulers);
 
   ANIM_animdata_update(&ac, &anim_data);



More information about the Bf-blender-cvs mailing list