[Bf-blender-cvs] [a78558a2ee4] temp-angavrilov-constraints: Animation: support filtering for curves with a cycle period mismatch.

Alexander Gavrilov noreply at git.blender.org
Sat Jun 5 17:46:34 CEST 2021


Commit: a78558a2ee41d83f1ed6fdd4002fff3d5bdca374
Author: Alexander Gavrilov
Date:   Mon May 3 17:27:53 2021 +0300
Branches: temp-angavrilov-constraints
https://developer.blender.org/rBa78558a2ee41d83f1ed6fdd4002fff3d5bdca374

Animation: support filtering for curves with a cycle period mismatch.

Since the looping behavior is defined per curve rather than at
action level, it is possible for curve loop periods to get out of
sync with each other. This commit adds an option to compare curves
against the frame range specified in the action, and treat those
with a mismatch as errors for the purpose of F-Curve filtering.

When enabled, the check verifies that curves within the action
have valid cyclic extrapolation, and the action period evenly
divides by the curve period (since a curve looping at e.g. half
of the action period length still repeats in sync with the action).

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

M	release/scripts/startup/bl_ui/space_dopesheet.py
M	source/blender/editors/animation/anim_filter.c
M	source/blender/makesdna/DNA_action_types.h
M	source/blender/makesrna/intern/rna_action.c

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

diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index a7440ac09a8..66861c631b8 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -737,7 +737,11 @@ class DOPESHEET_PT_action_range(Panel):
         row.prop(action, "frame_start", text="Start")
         row.prop(action, "frame_end", text="End")
 
-        col.prop(action, "is_cyclic")
+        row = col.row()
+        row.prop(action, "is_cyclic")
+        row = row.row()
+        row.active = action.is_cyclic
+        row.prop(action, "use_cyclic_errors", icon="ERROR", text="", toggle=True)
 
 
 class DOPESHEET_PT_gpencil_mode(LayersDopeSheetPanel, Panel):
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index a03f19d0111..e81161366cc 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -40,6 +40,7 @@
  * -- Joshua Leung, Dec 2008 (Last revision July 2009)
  */
 
+#include <math.h>
 #include <string.h>
 
 #include "DNA_anim_types.h"
@@ -1217,7 +1218,7 @@ static bool skip_fcurve_with_name(
  *
  * \return true if F-Curve has errors/is disabled
  */
-static bool fcurve_has_errors(FCurve *fcu)
+static bool fcurve_has_errors(FCurve *fcu, bAction *act)
 {
   /* F-Curve disabled - path eval error */
   if (fcu->flag & FCURVE_DISABLED) {
@@ -1249,6 +1250,37 @@ static bool fcurve_has_errors(FCurve *fcu)
     }
   }
 
+  /* Check cycle errors. */
+  const int cyclic_error_mask = ACT_FRAME_RANGE | ACT_CYCLIC | ACT_CYCLIC_ERRORS;
+
+  if (act && (act->flag & cyclic_error_mask) == cyclic_error_mask) {
+    /* Check if the curve has enough points. */
+    if (fcu->totvert < 2 || !fcu->bezt) {
+      return true;
+    }
+
+    /* Check if it is cyclic. */
+    FModifier *fmod = fcu->modifiers.first;
+    if (!fmod || fmod->type != FMODIFIER_TYPE_CYCLES) {
+      return true;
+    }
+
+    /* Check that it has a nonzero period length. */
+    float curve_period = fcu->bezt[fcu->totvert - 1].vec[1][0] - fcu->bezt[0].vec[1][0];
+
+    if (curve_period < 0.01f) {
+      return true;
+    }
+
+    /* Check that the action period is divisible by the curve period. */
+    float action_period = act->frame_end - act->frame_start;
+    float gap = action_period - roundf(action_period / curve_period) * curve_period;
+
+    if (fabsf(gap) > 0.01f) {
+      return true;
+    }
+  }
+
   /* no errors found */
   return false;
 }
@@ -1258,6 +1290,7 @@ static FCurve *animfilter_fcurve_next(bDopeSheet *ads,
                                       FCurve *first,
                                       eAnim_ChannelType channel_type,
                                       int filter_mode,
+                                      bAction *act,
                                       void *owner,
                                       ID *owner_id)
 {
@@ -1309,7 +1342,7 @@ static FCurve *animfilter_fcurve_next(bDopeSheet *ads,
             /* error-based filtering... */
             if ((ads) && (ads->filterflag & ADS_FILTER_ONLY_ERRORS)) {
               /* skip if no errors... */
-              if (fcurve_has_errors(fcu) == false) {
+              if (fcurve_has_errors(fcu, act) == false) {
                 continue;
               }
             }
@@ -1331,6 +1364,7 @@ static size_t animfilter_fcurves(ListBase *anim_data,
                                  FCurve *first,
                                  eAnim_ChannelType fcurve_type,
                                  int filter_mode,
+                                 bAction *act,
                                  void *owner,
                                  ID *owner_id,
                                  ID *fcurve_owner_id)
@@ -1351,7 +1385,7 @@ static size_t animfilter_fcurves(ListBase *anim_data,
    *    Back to step 2 :)
    */
   for (fcu = first;
-       ((fcu = animfilter_fcurve_next(ads, fcu, fcurve_type, filter_mode, owner, owner_id)));
+       ((fcu = animfilter_fcurve_next(ads, fcu, fcurve_type, filter_mode, act, owner, owner_id)));
        fcu = fcu->next) {
     if (UNLIKELY(fcurve_type == ANIMTYPE_NLACURVE)) {
       /* NLA Control Curve - Basically the same as normal F-Curves,
@@ -1426,11 +1460,18 @@ static size_t animfilter_act_group(bAnimContext *ac,
         if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
           /* get first F-Curve which can be used here */
           FCurve *first_fcu = animfilter_fcurve_next(
-              ads, agrp->channels.first, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id);
+              ads, agrp->channels.first, ANIMTYPE_FCURVE, filter_mode, act, agrp, owner_id);
 
           /* filter list, starting from this F-Curve */
-          tmp_items += animfilter_fcurves(
-              &tmp_data, ads, first_fcu, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id, &act->id);
+          tmp_items += animfilter_fcurves(&tmp_data,
+                                          ads,
+                                          first_fcu,
+                                          ANIMTYPE_FCURVE,
+                                          filter_mode,
+                                          act,
+                                          agrp,
+                                          owner_id,
+                                          &act->id);
         }
       }
     }
@@ -1495,7 +1536,7 @@ static size_t animfilter_action(bAnimContext *ac,
   if (!(filter_mode & ANIMFILTER_ACTGROUPED)) {
     FCurve *firstfcu = (lastchan) ? (lastchan->next) : (act->curves.first);
     items += animfilter_fcurves(
-        anim_data, ads, firstfcu, ANIMTYPE_FCURVE, filter_mode, NULL, owner_id, &act->id);
+        anim_data, ads, firstfcu, ANIMTYPE_FCURVE, filter_mode, act, NULL, owner_id, &act->id);
   }
 
   /* return the number of items added to the list */
@@ -1628,6 +1669,7 @@ static size_t animfilter_nla_controls(
                                         strip->fcurves.first,
                                         ANIMTYPE_NLACURVE,
                                         filter_mode,
+                                        NULL,
                                         strip,
                                         owner_id,
                                         owner_id);
@@ -1684,8 +1726,15 @@ static size_t animfilter_block_data(
           items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id);
         },
         { /* Drivers */
-          items += animfilter_fcurves(
-              anim_data, ads, adt->drivers.first, ANIMTYPE_FCURVE, filter_mode, NULL, id, id);
+          items += animfilter_fcurves(anim_data,
+                                      ads,
+                                      adt->drivers.first,
+                                      ANIMTYPE_FCURVE,
+                                      filter_mode,
+                                      NULL,
+                                      NULL,
+                                      id,
+                                      id);
         },
         { /* NLA Control Keyframes */
           items += animfilter_nla_controls(anim_data, ads, adt, filter_mode, id);
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 684fcacaf2f..e2e7c8ee5b8 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -701,6 +701,8 @@ typedef enum eAction_Flags {
   ACT_FRAME_RANGE = (1 << 12),
   /** The action is cyclic (requires ACT_FRAME_RANGE). */
   ACT_CYCLIC = (1 << 13),
+  /** Treat cycle length or extrapolation mismatch as a curve error. */
+  ACT_CYCLIC_ERRORS = (1 << 14),
 } eAction_Flags;
 
 /* ************************************************ */
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index 528d191e78e..d166d73c01a 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -885,6 +885,15 @@ static void rna_def_action(BlenderRNA *brna)
       "using Cycle-Aware Keying, newly added F-Curves will be automatically made cyclic");
   RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
 
+  prop = RNA_def_property(srna, "use_cyclic_errors", PROP_BOOLEAN, PROP_NONE);
+  RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+  RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_CYCLIC_ERRORS);
+  RNA_def_property_ui_text(prop,
+                           "Cyclic Errors",
+                           "Treat curves that aren't cyclic with the specified period as having "
+                           "errors for the purpose of filtering");
+  RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
   prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_TIME);
   RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
   RNA_def_property_float_sdna(prop, NULL, "frame_start");



More information about the Bf-blender-cvs mailing list