[Bf-blender-cvs] [589a889d232] greasepencil-refactor: GPencil: Refactor: Implement Onion skinning back

Clément Foucault noreply at git.blender.org
Tue Dec 31 19:31:23 CET 2019


Commit: 589a889d2320d976f71df2afeeaf22f6c6ea1f39
Author: Clément Foucault
Date:   Tue Dec 31 19:16:53 2019 +0100
Branches: greasepencil-refactor
https://developer.blender.org/rB589a889d2320d976f71df2afeeaf22f6c6ea1f39

GPencil: Refactor: Implement Onion skinning back

This new implementation changes a few things:
- The alpha is not dependent on the number of frames you choose to draw.
- The loop option affects more than one frame.
- The next frames are drawn on top of the active frame (TODO)

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

M	source/blender/draw/engines/gpencil/gpencil_draw_utils.c
M	source/blender/draw/engines/gpencil/gpencil_engine.c
M	source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
M	source/blender/makesdna/DNA_gpencil_types.h

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

diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
index 2a572885ff8..d109e1b6cf2 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -66,107 +66,118 @@ void gpencil_object_visible_stroke_iter(Object *ob,
                                         void *thunk)
 {
   bGPdata *gpd = (bGPdata *)ob->data;
-  const bool main_onion = false; /* TODO */  // stl->storage->is_main_onion;
-  const bool playing = false; /* TODO */     // stl->storage->is_playing;
-  const bool overlay = false; /* TODO */     // stl->storage->is_main_overlay;
-  const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
-                        main_onion && !playing && gpencil_onion_active(gpd);
+  const bool main_onion = true; /* TODO */  // stl->storage->is_main_onion;
+  const bool playing = false; /* TODO */    // stl->storage->is_playing;
+  const bool overlay = true; /* TODO */     // stl->storage->is_main_overlay;
+  const bool do_onion = ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay && main_onion &&
+                        !playing && gpencil_onion_active(gpd);
   const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
 
   /* Onion skinning. */
-  const int step = gpd->gstep;
-  const int mode = gpd->onion_mode;
+  const bool onion_mode_abs = (gpd->onion_mode == GP_ONION_MODE_ABSOLUTE);
+  const bool onion_mode_sel = (gpd->onion_mode == GP_ONION_MODE_SELECTED);
+  const bool onion_loop = (gpd->onion_flag & GP_ONION_LOOP) != 0;
   const short onion_keytype = gpd->onion_keytype;
+  int ctime = 0;
+  if (onion_mode_abs) {
+    const DRWContextState *draw_ctx = DRW_context_state_get();
+    ctime = DEG_get_ctime(draw_ctx->depsgraph);
+  }
 
   int idx_eval = 0;
 
   LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
-    bGPDframe *init_gpf = NULL;
+    bGPDframe *act_gpf = gpl->actframe;
+    bGPDframe *sta_gpf = act_gpf;
+    bGPDframe *end_gpf = act_gpf ? act_gpf->next : NULL;
     const bool is_onion = (do_onion && (gpl->onion_flag & GP_LAYER_ONIONSKIN));
     if (gpl->flag & GP_LAYER_HIDE) {
       idx_eval++;
       continue;
     }
 
-    /* Relative onion mode needs to find the frame range before. */
-    int frame_from = -INT_MAX;
-    int frame_to = INT_MAX;
-    if (is_onion && (mode == GP_ONION_MODE_RELATIVE)) {
-      /* 1) Found first Frame. */
-      int idx = 0;
-      if (gpl->actframe) {
-        for (bGPDframe *gf = gpl->actframe->prev; gf; gf = gf->prev) {
-          idx++;
-          frame_from = gf->framenum;
-          if (idx >= step) {
-            break;
-          }
+    if (is_onion) {
+      if (act_gpf) {
+        bGPDframe *last_gpf = gpl->frames.last;
+
+        int frame_len = 0;
+        LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+          gpf->runtime.frameid = frame_len++;
         }
-        /* 2) Found last Frame. */
-        idx = 0;
-        for (bGPDframe *gf = gpl->actframe->next; gf; gf = gf->next) {
-          idx++;
-          frame_to = gf->framenum;
-          if (idx >= gpd->gstep_next) {
-            break;
+
+        LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+          bool is_wrong_keytype = (onion_keytype > -1) && (gpf->key_type != onion_keytype);
+          bool is_in_range;
+          int delta = (onion_mode_abs) ? (gpf->framenum - ctime) :
+                                         (gpf->runtime.frameid - act_gpf->runtime.frameid);
+
+          if (onion_mode_sel) {
+            is_in_range = (gpf->flag & GP_FRAME_SELECT) != 0;
           }
+          else {
+            is_in_range = (-delta <= gpd->gstep) && (delta <= gpd->gstep_next);
+
+            if (onion_loop && !is_in_range) {
+              /* We wrap the value using the last frame and 0 as reference. */
+              /* FIXME: This might not be good for animations not starting at 0. */
+              int shift = (onion_mode_abs) ? last_gpf->framenum : last_gpf->runtime.frameid;
+              delta += (delta < 0) ? shift : -shift;
+              /* Test again with wrapped value. */
+              is_in_range = (-delta <= gpd->gstep) && (delta <= gpd->gstep_next);
+            }
+          }
+          /* Mask frames that have wrong keytype of are not in range. */
+          gpf->runtime.onion_id = (is_wrong_keytype || !is_in_range) ? INT_MAX : delta;
         }
+        /* Active frame is always shown. */
+        act_gpf->runtime.onion_id = 0;
       }
-    }
 
-    /* If multiedit or onion skin need to count all frames of the layer. */
-    if (is_multiedit || is_onion) {
-      init_gpf = gpl->frames.first;
+      sta_gpf = gpl->frames.first;
+      end_gpf = NULL;
+    }
+    else if (is_multiedit) {
+      sta_gpf = end_gpf = NULL;
+      /* Check the whole range and tag the editable frames. */
+      LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+        if (gpf == act_gpf || (gpf->flag & GP_FRAME_SELECT)) {
+          gpf->runtime.onion_id = 0;
+          if (sta_gpf == NULL) {
+            sta_gpf = gpf;
+          }
+          end_gpf = gpf->next;
+        }
+        else {
+          gpf->runtime.onion_id = INT_MAX;
+        }
+      }
     }
     else {
-      init_gpf = &ob->runtime.gpencil_evaluated_frames[idx_eval];
+      sta_gpf = &ob->runtime.gpencil_evaluated_frames[idx_eval];
+      if (sta_gpf) {
+        end_gpf = sta_gpf->next;
+        sta_gpf->runtime.onion_id = 0;
+      }
     }
 
-    if (init_gpf == NULL) {
+    if (sta_gpf == NULL) {
       continue;
     }
 
-    if (layer_cb) {
-      layer_cb(gpl, NULL, NULL, thunk);
-    }
-
-    for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
-      LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
-        if (!is_onion) {
-          if ((!is_multiedit) ||
-              (is_multiedit && ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)))) {
-            stroke_cb(gpl, gpf, gps, thunk);
-          }
-        }
-        else {
-          bool select = (is_multiedit &&
-                         ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)));
-
-          if (!select) {
-            bool is_wrong_keytype = (onion_keytype > -1) && (gpf->key_type != onion_keytype);
-            bool is_in_range;
-            if (mode == GP_ONION_MODE_ABSOLUTE) {
-              is_in_range = gpl->actframe && abs(gpl->actframe->framenum - gpf->framenum) <= step;
-            }
-            else if (mode == GP_ONION_MODE_RELATIVE) {
-              is_in_range = (gpf->framenum >= frame_from) && (gpf->framenum <= frame_to);
-            }
-            else /* GP_ONION_MODE_SELECTED */ {
-              is_in_range = (gpf->flag & GP_FRAME_SELECT) != 0;
-            }
+    for (bGPDframe *gpf = sta_gpf; gpf && gpf != end_gpf; gpf = gpf->next) {
+      if (gpf->runtime.onion_id == INT_MAX) {
+        continue;
+      }
 
-            if (is_wrong_keytype || !is_in_range) {
-              continue;
-            }
-          }
-          stroke_cb(gpl, gpf, gps, thunk);
-        }
+      if (layer_cb) {
+        layer_cb(gpl, gpf, NULL, thunk);
       }
-      /* If not multiframe nor Onion skin, don't need follow counting. */
-      if ((!is_multiedit) && (!is_onion)) {
-        break;
+
+      LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+        stroke_cb(gpl, gpf, gps, thunk);
       }
     }
+
     idx_eval++;
   }
 }
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 1bd7465e9ce..0eeaf5b9b35 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -857,10 +857,11 @@ typedef struct gpIterPopulateData {
 } gpIterPopulateData;
 
 static void gp_layer_cache_populate(bGPDlayer *gpl,
-                                    bGPDframe *UNUSED(gpf),
+                                    bGPDframe *gpf,
                                     bGPDstroke *UNUSED(gps),
                                     void *thunk)
 {
+  DRWShadingGroup *grp;
   gpIterPopulateData *iter = (gpIterPopulateData *)thunk;
   bGPdata *gpd = (bGPdata *)iter->ob->data;
 
@@ -905,8 +906,27 @@ static void gp_layer_cache_populate(bGPDlayer *gpl,
   DRW_shgroup_uniform_float_copy(iter->grp, "thicknessOffset", (float)gpl->line_change);
   DRW_shgroup_uniform_float_copy(iter->grp, "thicknessWorldScale", thickness_scale);
   DRW_shgroup_uniform_float_copy(iter->grp, "vertexColorOpacity", gpl->vertex_paint_opacity);
-  DRW_shgroup_uniform_vec4_copy(iter->grp, "layerTint", gpl->tintcolor);
   DRW_shgroup_stencil_mask(iter->grp, 0xFF);
+
+  bool use_onion = gpf->runtime.onion_id != 0.0f;
+  if (use_onion) {
+    const bool use_onion_custom_col = (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) != 0;
+    const bool use_onion_fade = (gpd->onion_flag & GP_ONION_FADE) != 0;
+    const bool use_next_col = gpf->runtime.onion_id > 0.0f;
+    float *onion_col_custom = (use_next_col) ? gpd->gcolor_next : gpd->gcolor_prev;
+    onion_col_custom = (use_onion_custom_col) ? onion_col_custom : U.gpencil_new_layer_col;
+    float onion_col[4] = {UNPACK3(onion_col_custom), 1.0f};
+    float onion_alpha = use_onion_fade ? (1.0f / abs(gpf->runtime.onion_id)) : 0.5f;
+    onion_alpha += (gpd->onion_factor * 2.0f - 1.0f);
+    onion_alpha = max_ff(onion_alpha, 0.01f);
+
+    DRW_shgroup_uniform_vec4_copy(iter->grp, "layerTint", onion_col);
+    DRW_shgroup_uniform_float_copy(iter->grp, "layerOpacity", onion_alpha);
+  }
+  else {
+    DRW_shgroup_uniform_vec4_copy(iter->grp, "layerTint", gpl->tintcolor);
+    DRW_shgroup_uniform_float_copy(iter->grp, "layerOpacity", 1.0f);
+  }
 }
 
 static void gp_stroke_cache_populate(bGPDlayer *UNUSED(gpl),
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
index e3ab346c83f..370818fa809 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
@@ -14,6 +14,7 @@ uniform float thicknessWorldScale;
 uniform float thicknessOffset;
 uniform float vertexColorOpacit

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list