[Bf-blender-cvs] [b11699d36fe] temp-angavrilov-constraints: Animation: allow specifying a custom frame range for actions.

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


Commit: b11699d36fefff3be70af66a89599f1be11e48fc
Author: Alexander Gavrilov
Date:   Mon May 3 00:03:00 2021 +0300
Branches: temp-angavrilov-constraints
https://developer.blender.org/rBb11699d36fefff3be70af66a89599f1be11e48fc

Animation: allow specifying a custom frame range for actions.

Some operations, e.g. adding a new action strip to NLA, require
knowing the active frame range of an action, but currently it can
only be deduced by scanning the keyframes of the curves within it.
This is not ideal if e.g. curves are staggered for overlap.

As suggested by Nathan Vegdahl, this patch adds Action properties
that allow manually specifying its active frame range, and whether
it is intended to be cyclic. The settings are exposed in a popover
in Action Editor. When enabled, the range is highlighted in the
background using a striped fill to distinguish it from the solid
filled regular playback range.

When set, the frame range is used by NLA. In addition, the Cycle-Aware
Keying option automatically sets up F-Curves newly added to a cyclic
action to use cyclic extrapolation with the correct period.

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

M	release/scripts/startup/bl_ui/space_dopesheet.py
M	source/blender/blenkernel/BKE_action.h
M	source/blender/blenkernel/intern/action.c
M	source/blender/blenkernel/intern/nla.c
M	source/blender/editors/animation/anim_draw.c
M	source/blender/editors/animation/keyframing.c
M	source/blender/editors/include/ED_anim_api.h
M	source/blender/editors/space_action/action_data.c
M	source/blender/editors/space_action/space_action.c
M	source/blender/editors/space_nla/nla_edit.c
M	source/blender/makesdna/DNA_action_types.h
M	source/blender/makesrna/intern/rna_action.c
M	source/blender/makesrna/intern/rna_scene.c

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

diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index e7893b8c448..a7440ac09a8 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -251,6 +251,12 @@ class DOPESHEET_HT_editor_buttons:
 
             layout.template_ID(st, "action", new="action.new", unlink="action.unlink")
 
+            layout.popover(
+                panel="DOPESHEET_PT_action_range",
+                text="",
+                icon='PREVIEW_RANGE',
+            )
+
         # Layer management
         if st.mode == 'GPENCIL':
             ob = context.active_object
@@ -707,6 +713,33 @@ class LayersDopeSheetPanel:
         return False
 
 
+class DOPESHEET_PT_action_range(Panel):
+    bl_space_type = 'DOPESHEET_EDITOR'
+    bl_region_type = 'HEADER'
+    bl_label = "Custom Frame Range"
+    bl_description = "Explicitly specify the intended playback frame range of the action"
+
+    @classmethod
+    def poll(cls, context):
+        st = context.space_data
+        return st and st.mode in {'ACTION', 'SHAPEKEY'} and st.action
+
+    def draw(self, context):
+        layout = self.layout
+        action = context.space_data.action
+
+        layout.prop(action, "use_frame_range", text="Use Custom Range")
+
+        col = layout.column()
+        col.active = action.use_frame_range
+
+        row = col.row(align=True)
+        row.prop(action, "frame_start", text="Start")
+        row.prop(action, "frame_end", text="End")
+
+        col.prop(action, "is_cyclic")
+
+
 class DOPESHEET_PT_gpencil_mode(LayersDopeSheetPanel, Panel):
     # bl_space_type = 'DOPESHEET_EDITOR'
     # bl_region_type = 'UI'
@@ -778,6 +811,7 @@ classes = (
     DOPESHEET_MT_channel_context_menu,
     DOPESHEET_MT_snap_pie,
     DOPESHEET_PT_filters,
+    DOPESHEET_PT_action_range,
     DOPESHEET_PT_gpencil_mode,
     DOPESHEET_PT_gpencil_layer_masks,
     DOPESHEET_PT_gpencil_layer_transform,
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 3d81fcba37d..5c87e8f70a4 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -91,9 +91,15 @@ short action_get_item_transforms(struct bAction *act,
 /* Some kind of bounding box operation on the action */
 void calc_action_range(const struct bAction *act, float *start, float *end, short incl_modifiers);
 
+/* Retrieve the frame range, using the custom range if set. */
+void BKE_action_get_frame_range(const struct bAction *act, float *start, float *end);
+
 /* Does action have any motion data at all? */
 bool action_has_motion(const struct bAction *act);
 
+/* Is the action configured as cyclic. */
+bool BKE_action_is_cyclic(const struct bAction *act);
+
 /* Action Groups API ----------------- */
 
 /* Get the active action-group for an Action */
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 04c3441cb9f..ae74a715b2d 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -1496,6 +1496,28 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
   }
 }
 
+/* Retrieve the frame range, using the custom range if set. */
+void BKE_action_get_frame_range(const struct bAction *act, float *start, float *end)
+{
+  if (act && (act->flag & ACT_FRAME_RANGE)) {
+    *start = act->frame_start;
+    *end = act->frame_end;
+
+    if (act->frame_start == act->frame_end) {
+      *end += 1.0f;
+    }
+  }
+  else {
+    calc_action_range(act, start, end, 0);
+  }
+}
+
+/* Is the action configured as cyclic. */
+bool BKE_action_is_cyclic(const struct bAction *act)
+{
+  return act && (act->flag & ACT_FRAME_RANGE) && (act->flag & ACT_CYCLIC);
+}
+
 /* Return flags indicating which transforms the given object/posechannel has
  * - if 'curves' is provided, a list of links to these curves are also returned
  */
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 92e21183acb..433aaed4c1c 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -397,7 +397,11 @@ NlaStrip *BKE_nlastrip_new(bAction *act)
   /* determine initial range
    * - strip length cannot be 0... ever...
    */
-  calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+  BKE_action_get_frame_range(strip->act, &strip->actstart, &strip->actend);
+
+  if (BKE_action_is_cyclic(strip->act)) {
+    strip->flag |= NLASTRIP_FLAG_USR_TIME_CYCLIC;
+  }
 
   strip->start = strip->actstart;
   strip->end = (IS_EQF(strip->actstart, strip->actend)) ? (strip->actstart + 1.0f) :
@@ -1444,7 +1448,7 @@ void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip)
 
   prev_actstart = strip->actstart;
 
-  calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+  BKE_action_get_frame_range(strip->act, &strip->actstart, &strip->actend);
 
   /* Set start such that key's do not visually move, to preserve the overall animation result. */
   strip->start += (strip->actstart - prev_actstart) * strip->scale;
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index aca332ff0fe..b09beb42d44 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -167,6 +167,55 @@ void ANIM_draw_framerange(Scene *scene, View2D *v2d)
   immUnbindProgram();
 }
 
+/**
+ * Draw custom action frame range guides in the background.
+ */
+void ANIM_draw_custom_framerange(View2D *v2d, float sfra, float efra)
+{
+  /* Diagonal stripe filled area outside of the frame range. */
+  GPU_blend(GPU_BLEND_ALPHA);
+
+  GPUVertFormat *format = immVertexFormat();
+  uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+  immBindBuiltinProgram(GPU_SHADER_2D_DIAG_STRIPES);
+
+  float color[4];
+  UI_GetThemeColorShadeAlpha4fv(TH_BACK, -35, -50, color);
+
+  immUniform4f("color1", color[0], color[1], color[2], color[3]);
+  immUniform4f("color2", 0.0f, 0.0f, 0.0f, 0.0f);
+  immUniform1i("size1", 2);
+  immUniform1i("size2", 4);
+
+  if (sfra < efra) {
+    immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, sfra, v2d->cur.ymax);
+    immRectf(pos, efra, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+  }
+  else {
+    immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+  }
+
+  immUnbindProgram();
+
+  GPU_blend(GPU_BLEND_NONE);
+
+  /* Thin lines where the actual frames are. */
+  immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+  immUniformThemeColorShade(TH_BACK, -60);
+
+  immBegin(GPU_PRIM_LINES, 4);
+
+  immVertex2f(pos, sfra, v2d->cur.ymin);
+  immVertex2f(pos, sfra, v2d->cur.ymax);
+
+  immVertex2f(pos, efra, v2d->cur.ymin);
+  immVertex2f(pos, efra, v2d->cur.ymax);
+
+  immEnd();
+  immUnbindProgram();
+}
+
 /* *************************************************** */
 /* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes)  */
 
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index f229d48b4eb..517c95d7916 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -35,6 +35,7 @@
 
 #include "BLT_translation.h"
 
+#include "DNA_action_types.h"
 #include "DNA_anim_types.h"
 #include "DNA_armature_types.h"
 #include "DNA_constraint_types.h"
@@ -373,6 +374,43 @@ static eFCU_Cycle_Type remap_cyclic_keyframe_location(FCurve *fcu, float *px, fl
   return type;
 }
 
+/* Used to make curves newly added to a cyclic Action cycle with the correct period. */
+static void make_new_fcurve_cyclic(const bAction *act, FCurve *fcu)
+{
+  /* The curve must contain one (newly-added) keyframe. */
+  if (fcu->totvert != 1 || !fcu->bezt) {
+    return;
+  }
+
+  float period = act->frame_end - act->frame_start;
+
+  if (period < 0.1f) {
+    return;
+  }
+
+  /* Move the keyframe into the range. */
+  float frame_offset = fcu->bezt[0].vec[1][0] - act->frame_start;
+  float fix = floorf(frame_offset / period) * period;
+
+  fcu->bezt[0].vec[0][0] -= fix;
+  fcu->bezt[0].vec[1][0] -= fix;
+  fcu->bezt[0].vec[2][0] -= fix;
+
+  /* Duplicate and offset the keyframe. */
+  fcu->bezt = MEM_reallocN(fcu->bezt, sizeof(BezTriple) * 2);
+  fcu->totvert = 2;
+
+  fcu->bezt[1] = fcu->bezt[0];
+  fcu->bezt[1].vec[0][0] += period;
+  fcu->bezt[1].vec[1][0] += period;
+  fcu->bezt[1].vec[2][0] += period;
+
+  /* Add the cycles modifier. */
+  if (!fcu->modifiers.first) {
+    add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, fcu);
+  }
+}
+
 /* -------------- BezTriple Insertion -------------------- */
 
 /* Change the Y position of a keyframe to match the input, adjusting handles. */
@@ -1350,8 +1388,10 @@ static bool insert_keyframe_fcurve_value(Main *bmain,
 
   /* we may not have a F-Curve when we're replacing only... */
   if (fcu) {
+    const bool is_new_curve = (fcu->totvert == 0);
+
     /* set color mode if the F-Curve is new (i.e. without any keyframes) */
-    if ((fcu->totvert == 0) && (flag & INSERTKEY_XYZ2RGB)) {
+    if (is_new_curve && (flag & INSERTKEY_XYZ2RGB)) {
       /* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor,
        * is determined by the array index for the F-Curve
        */
@@ -1368,8 +1408,15 @@ static bool insert_keyframe_fcurve_value(Main *bmain,
     update_autoflags_fcurve_direct(fcu, prop);
 
     /* insert keyframe */
-    return insert_keyframe_value(
+    bool rv = insert_keyframe_value(
         reports, ptr, prop, fcu, anim_eval_context, curval, keytype, flag);
+
+    /* If the curve is new, make it cyclic if appropriate. */
+    if (is_new_curve && (flag & INSERTKEY_CYCLE_AWARE) && BKE_action_is_cyclic(act)) {
+      make_new_fcurve_cyclic(act, fcu);
+    }
+
+    return rv;
   }
 
   return false;
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 4b440aa7367..2254b7a71e6 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -673,6 +673,9 @@ void A

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list