GPencil: Move modifiers evaluation logic to Depsgraph (wip)
authorAntonioya <blendergit@gmail.com>
Thu, 9 May 2019 11:27:41 +0000 (13:27 +0200)
committerAntonioya <blendergit@gmail.com>
Thu, 9 May 2019 11:27:41 +0000 (13:27 +0200)
This commits is the first step to move all logic for evaluating modifiers to depsgraph evaluation and remove from the draw manager.  This was coded in the draw manager because when new grease pencil modules were written, the depsgraph was not ready.

Move all to depsgraph reduces the complexity of draw manager, and follows the standards for evaluated data.

This allows to use the evaluated data in edition modes.

Now, it's only working in selection operators, but in the future the different tools will work with the evaluated version and not with the original version as it was before.

12 files changed:
source/blender/blenkernel/BKE_gpencil.h
source/blender/blenkernel/BKE_gpencil_modifier.h
source/blender/blenkernel/intern/gpencil_modifier.c
source/blender/blenkernel/intern/object_update.c
source/blender/draw/engines/gpencil/gpencil_cache_utils.c
source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
source/blender/draw/engines/gpencil/gpencil_draw_utils.c
source/blender/draw/engines/gpencil/gpencil_engine.h
source/blender/editors/gpencil/gpencil_intern.h
source/blender/editors/gpencil/gpencil_select.c
source/blender/makesdna/DNA_gpencil_types.h
source/blender/makesdna/DNA_object_types.h

index 993d4ee..3c84c99 100644 (file)
@@ -54,6 +54,23 @@ struct GPUVertBuf;
 struct GPUVertFormat;
 struct GpencilBatchGroup;
 
+#define GP_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE))
+#define GP_SIMPLIFY_ONPLAY(playing) \
+  (((playing == true) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ON_PLAY)) || \
+   ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ON_PLAY) == 0))
+#define GP_SIMPLIFY_FILL(scene, playing) \
+  ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && \
+    (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FILL)))
+#define GP_SIMPLIFY_MODIF(scene, playing) \
+  ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && \
+    (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER)))
+#define GP_SIMPLIFY_FX(scene, playing) \
+  ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && \
+    (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FX)))
+#define GP_SIMPLIFY_BLEND(scene, playing) \
+  ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && \
+    (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_BLEND)))
+
 /* GPUBatch Cache Element */
 typedef struct GpencilBatchCacheElem {
   struct GPUBatch *batch;
@@ -106,9 +123,6 @@ typedef struct GpencilBatchCache {
   int grp_used;                        /* total groups in arrays */
   int grp_size;                        /* max size of the array */
   struct GpencilBatchGroup *grp_cache; /* array of elements */
-
-  int tot_layers;
-  struct bGPDframe *derived_array; /* runtime data created by modifiers */
 } GpencilBatchCache;
 
 /* ------------ Grease-Pencil API ------------------ */
index 4655abf..63b1f25 100644 (file)
@@ -325,4 +325,8 @@ int BKE_gpencil_time_modifier(struct Depsgraph *depsgraph,
 void BKE_gpencil_lattice_init(struct Object *ob);
 void BKE_gpencil_lattice_clear(struct Object *ob);
 
+void BKE_gpencil_modifiers_calc(struct Depsgraph *depsgraph,
+                                struct Scene *scene,
+                                struct Object *ob);
+
 #endif /* __BKE_GPENCIL_MODIFIER_H__ */
index c8a45a9..f0bcceb 100644 (file)
@@ -781,6 +781,7 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag)
       pt_final->strength = pt->strength;
       pt_final->time = pt->time;
       pt_final->flag = pt->flag;
+      pt_final->runtime.pt_orig = pt->runtime.pt_orig;
 
       if (gps->dvert != NULL) {
         dvert = &temp_dverts[i];
@@ -803,6 +804,7 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag)
       pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
       CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
       pt_final->time = interpf(pt->time, next->time, 0.5f);
+      pt_final->runtime.pt_orig = NULL;
 
       if (gps->dvert != NULL) {
         dvert = &temp_dverts[i];
@@ -848,3 +850,125 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag)
     }
   }
 }
+
+/* Copy frame but do not assign new memory */
+static void gpencil_copy_frame(bGPDframe *gpf, bGPDframe *derived_gpf)
+{
+  derived_gpf->prev = gpf->prev;
+  derived_gpf->next = gpf->next;
+  derived_gpf->framenum = gpf->framenum;
+  derived_gpf->flag = gpf->flag;
+  derived_gpf->key_type = gpf->key_type;
+  derived_gpf->runtime = gpf->runtime;
+  copy_m4_m4(derived_gpf->runtime.viewmatrix, gpf->runtime.viewmatrix);
+
+  /* copy strokes */
+  BLI_listbase_clear(&derived_gpf->strokes);
+  for (bGPDstroke *gps_src = gpf->strokes.first; gps_src; gps_src = gps_src->next) {
+    /* make copy of source stroke */
+    bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
+
+    /* Save original pointers for using in edit and select operators. */
+    gps_dst->runtime.gps_orig = gps_src;
+    for (int i = 0; i < gps_src->totpoints; i++) {
+      bGPDspoint *pt_dst = &gps_dst->points[i];
+      pt_dst->runtime.pt_orig = &gps_src->points[i];
+    }
+
+    BLI_addtail(&derived_gpf->strokes, gps_dst);
+  }
+}
+
+/* Ensure there is a derived frame */
+static void gpencil_ensure_derived_frame(
+    int idx, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bGPDframe **derived_gpf)
+{
+  /* create derived frames array data or expand */
+  bGPDframe *derived_frames = ob->runtime.derived_frames;
+  *derived_gpf = &derived_frames[idx];
+
+  /* if derived frame create a new one */
+  if (*derived_gpf != NULL) {
+    /* first clear temp data */
+    BKE_gpencil_free_frame_runtime_data(*derived_gpf);
+  }
+  /* copy data (do not assign new memory)*/
+  gpencil_copy_frame(gpf, *derived_gpf);
+}
+
+/* Calculate gpencil modifiers */
+void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+  /* use original data to set reference pointers to original data */
+  Object *ob_orig = DEG_get_original_object(ob);
+  bGPdata *gpd = (bGPdata *)ob_orig->data;
+  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+  const bool simplify_modif = GP_SIMPLIFY_MODIF(scene, false);
+  const bool is_render = (bool)(DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+  const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
+  int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+  /* Create array of derived frames equal to number of layers. */
+  ob->runtime.tot_layers = BLI_listbase_count(&gpd->layers);
+  CLAMP_MIN(ob->runtime.tot_layers, 1);
+  if (ob->runtime.derived_frames == NULL) {
+    ob->runtime.derived_frames = MEM_callocN(sizeof(struct bGPDframe) * ob->runtime.tot_layers,
+                                             __func__);
+  }
+  else {
+    ob->runtime.derived_frames = MEM_reallocN(ob->runtime.derived_frames,
+                                              sizeof(struct bGPDframe) * ob->runtime.tot_layers);
+  }
+
+  /* Init general modifiers data. */
+  if (ob->greasepencil_modifiers.first) {
+    BKE_gpencil_lattice_init(ob);
+  }
+
+  /* *****************************************************************
+   * Loop all layers, duplicate data and apply modifiers.
+   *
+   * ******************************************************************/
+  int idx = 0;
+  for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+    /* Remap frame (Time modifier) */
+    int remap_cfra = cfra_eval;
+    if ((time_remap) && (!simplify_modif)) {
+      remap_cfra = BKE_gpencil_time_modifier(depsgraph, scene, ob, gpl, cfra_eval, is_render);
+    }
+    bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV);
+
+    if (gpf == NULL) {
+      idx++;
+      continue;
+    }
+
+    /* Create a duplicate data set of stroke to modify. */
+    bGPDframe *derived_gpf = NULL;
+    gpencil_ensure_derived_frame(idx, ob, gpl, gpf, &derived_gpf);
+
+    /* Skip all if some disable flag is enabled. */
+    if ((ob->greasepencil_modifiers.first == NULL) || (is_multiedit) || (simplify_modif)) {
+      idx++;
+      continue;
+    }
+
+    /* Apply geometry modifiers (create new geometry). */
+    if (BKE_gpencil_has_geometry_modifiers(ob)) {
+      BKE_gpencil_geometry_modifiers(depsgraph, ob, gpl, derived_gpf, is_render);
+    }
+
+    /* Loop all strokes and deform them. */
+    for (bGPDstroke *gps = derived_gpf->strokes.first; gps; gps = gps->next) {
+      /* Apply modifiers that only deform geometry */
+      BKE_gpencil_stroke_modifiers(depsgraph, ob, gpl, derived_gpf, gps, is_render);
+    }
+
+    idx++;
+  }
+
+  /* Clear any lattice data. */
+  if (ob->greasepencil_modifiers.first) {
+    BKE_gpencil_lattice_clear(ob);
+  }
+}
index 183bc96..0e6f338 100644 (file)
@@ -42,6 +42,7 @@
 #include "BKE_displist.h"
 #include "BKE_editmesh.h"
 #include "BKE_effect.h"
+#include "BKE_gpencil_modifier.h"
 #include "BKE_image.h"
 #include "BKE_key.h"
 #include "BKE_layer.h"
@@ -209,6 +210,9 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
     case OB_LATTICE:
       BKE_lattice_modifiers_calc(depsgraph, scene, ob);
       break;
+    case OB_GPENCIL:
+      BKE_gpencil_modifiers_calc(depsgraph, scene, ob);
+      break;
   }
 
   /* particles */
index 9b833a9..b060834 100644 (file)
@@ -274,11 +274,6 @@ static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
 
   cache->cache_frame = cfra;
 
-  /* create array of derived frames equal to number of layers */
-  cache->tot_layers = BLI_listbase_count(&gpd->layers);
-  CLAMP_MIN(cache->tot_layers, 1);
-  cache->derived_array = MEM_callocN(sizeof(struct bGPDframe) * cache->tot_layers, "Derived GPF");
-
   return cache;
 }
 
@@ -311,15 +306,6 @@ static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
   MEM_SAFE_FREE(cache->grp_cache);
   cache->grp_size = 0;
   cache->grp_used = 0;
-
-  /* clear all frames derived data */
-  for (int i = 0; i < cache->tot_layers; i++) {
-    bGPDframe *derived_gpf = &cache->derived_array[i];
-    BKE_gpencil_free_frame_runtime_data(derived_gpf);
-    derived_gpf = NULL;
-  }
-  cache->tot_layers = 0;
-  MEM_SAFE_FREE(cache->derived_array);
 }
 
 /* get cache */
@@ -362,4 +348,14 @@ void DRW_gpencil_freecache(struct Object *ob)
       gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
     }
   }
+
+  /* clear all frames derived data */
+  for (int i = 0; i < ob->runtime.tot_layers; i++) {
+    bGPDframe *derived_gpf = &ob->runtime.derived_frames[i];
+    BKE_gpencil_free_frame_runtime_data(derived_gpf);
+    derived_gpf = NULL;
+  }
+
+  ob->runtime.tot_layers = 0;
+  MEM_SAFE_FREE(ob->runtime.derived_frames);
 }
index 9849c23..11cdcc7 100644 (file)
@@ -734,6 +734,9 @@ void DRW_gpencil_get_edit_geom(struct GpencilBatchCacheElem *be,
   UI_GetThemeColor3fv(TH_GP_VERTEX, unselectColor);
   unselectColor[3] = alpha;
 
+  float linecolor[4];
+  copy_v4_v4(linecolor, gpd->line_color);
+
   if (be->vbo == NULL) {
     gpencil_elem_format_ensure(be);
     be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
@@ -778,6 +781,12 @@ void DRW_gpencil_get_edit_geom(struct GpencilBatchCacheElem *be,
         ARRAY_SET_ITEMS(fcolor, 1.0f, 0.0f, 0.0f, 1.0f);
         fsize = vsize + 1;
       }
+      else if (pt->runtime.pt_orig == NULL) {
+        ARRAY_SET_ITEMS(fcolor, linecolor[0], linecolor[1], linecolor[2], selectColor[3]);
+        mul_v4_fl(fcolor, 0.9f);
+        copy_v4_v4(fcolor, fcolor);
+        fsize = vsize * 0.8f;
+      }
       else if (pt->flag & GP_SPOINT_SELECT) {
         copy_v4_v4(fcolor, selectColor);
         fsize = vsize;
index 4b6c913..b500899 100644 (file)
 #define TEXTURE 4
 #define PATTERN 5
 
-#define GP_SET_SRC_GPS(src_gps) \
-  if (src_gps) \
-  src_gps = src_gps->next
-
 /* Get number of vertex for using in GPU VBOs */
 static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
                                 tGPencilObjectCache *cache_ob,
@@ -88,16 +84,17 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
   const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
                         main_onion && DRW_gpencil_onion_active(gpd) && !playing;
 
-  const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
   const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
 
   cache_ob->tot_vertex = 0;
   cache_ob->tot_triangles = 0;
+  int derived_idx = 0;
 
   for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
     bGPDframe *init_gpf = NULL;
     const bool is_onion = ((do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN));
     if (gpl->flag & GP_LAYER_HIDE) {
+      derived_idx++;
       continue;
     }
 
@@ -106,15 +103,7 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
       init_gpf = gpl->frames.first;
     }
     else {
-      /* verify time modifiers */
-      if ((time_remap) && (!stl->storage->simplify_modif)) {
-        int remap_cfra = BKE_gpencil_time_modifier(
-            draw_ctx->depsgraph, draw_ctx->scene, ob, gpl, cfra_eval, stl->storage->is_render);
-        init_gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV);
-      }
-      else {
-        init_gpf = gpl->actframe;
-      }
+      init_gpf = &ob->runtime.derived_frames[derived_idx];
     }
 
     if (init_gpf == NULL) {
@@ -130,6 +119,7 @@ static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
         break;
       }
     }
+    derived_idx++;
   }
 
   cache->b_fill.tot_vertex = cache_ob->tot_triangles * 3;
@@ -1007,8 +997,7 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
                                  Object *ob,
                                  bGPdata *gpd,
                                  bGPDlayer *gpl,
-                                 bGPDframe *src_gpf,
-                                 bGPDframe *derived_gpf,
+                                 bGPDframe *gpf,
                                  const float opacity,
                                  const float tintcolor[4],
                                  const bool custonion,
@@ -1019,7 +1008,7 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
   const DRWContextState *draw_ctx = DRW_context_state_get();
   Scene *scene = draw_ctx->scene;
   View3D *v3d = draw_ctx->v3d;
-  bGPDstroke *gps, *src_gps;
+  bGPDstroke *gps;
   float viewmatrix[4][4];
   const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
   const bool playing = stl->storage->is_playing;
@@ -1035,42 +1024,23 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
 
   /* get parent matrix and save as static data */
   ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix);
-  copy_m4_m4(derived_gpf->runtime.viewmatrix, viewmatrix);
+  copy_m4_m4(gpf->runtime.viewmatrix, viewmatrix);
 
   if ((cache_ob != NULL) && (cache_ob->is_dup_ob)) {
-    copy_m4_m4(derived_gpf->runtime.viewmatrix, cache_ob->obmat);
-  }
-
-  /* apply geometry modifiers */
-  if ((cache->is_dirty) && (ob->greasepencil_modifiers.first) && (!is_multiedit)) {
-    if (!stl->storage->simplify_modif) {
-      if (BKE_gpencil_has_geometry_modifiers(ob)) {
-        BKE_gpencil_geometry_modifiers(depsgraph, ob, gpl, derived_gpf, stl->storage->is_render);
-      }
-    }
+    copy_m4_m4(gpf->runtime.viewmatrix, cache_ob->obmat);
   }
 
-  if (src_gpf) {
-    src_gps = src_gpf->strokes.first;
-  }
-  else {
-    src_gps = NULL;
-  }
-
-  for (gps = derived_gpf->strokes.first; gps; gps = gps->next) {
+  for (gps = gpf->strokes.first; gps; gps = gps->next) {
     MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
 
     /* check if stroke can be drawn */
     if (gpencil_can_draw_stroke(gp_style, gps, false, is_mat_preview) == false) {
-      GP_SET_SRC_GPS(src_gps);
       continue;
     }
 
     /* be sure recalc all cache in source stroke to avoid recalculation when frame change
      * and improve fps */
-    if (src_gps) {
-      DRW_gpencil_recalc_geometry_caches(ob, gpl, gp_style, src_gps);
-    }
+    DRW_gpencil_recalc_geometry_caches(ob, gpl, gp_style, gps->runtime.gps_orig);
 
     /* if the fill has any value, it's considered a fill and is not drawn if simplify fill is
      * enabled */
@@ -1079,32 +1049,22 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
       if ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
           (gp_style->fill_style > GP_STYLE_FILL_STYLE_SOLID) ||
           (gpl->blend_mode != eGplBlendMode_Normal)) {
-        GP_SET_SRC_GPS(src_gps);
         continue;
       }
     }
 
-    if ((gpl->actframe->framenum == derived_gpf->framenum) || (!is_multiedit) ||
-        (overlay_multiedit)) {
+    if ((gpl->actframe->framenum == gpf->framenum) || (!is_multiedit) || (overlay_multiedit)) {
       /* copy color to temp fields to apply temporal changes in the stroke */
       copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
       copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
 
-      /* apply modifiers (only modify geometry, but not create ) */
-      if ((cache->is_dirty) && (ob->greasepencil_modifiers.first) && (!is_multiedit)) {
-        if (!stl->storage->simplify_modif) {
-          BKE_gpencil_stroke_modifiers(
-              depsgraph, ob, gpl, derived_gpf, gps, stl->storage->is_render);
-        }
-      }
-
       /* hide any blend layer */
       if ((!stl->storage->simplify_blend) || (gpl->blend_mode == eGplBlendMode_Normal)) {
         /* fill */
         if ((gp_style->flag & GP_STYLE_FILL_SHOW) && (!stl->storage->simplify_fill) &&
             ((gps->flag & GP_STROKE_NOFILL) == 0)) {
           gpencil_add_fill_vertexdata(
-              cache, ob, gpl, derived_gpf, gps, opacity, tintcolor, false, custonion);
+              cache, ob, gpl, gpf, gps, opacity, tintcolor, false, custonion);
         }
         /* stroke */
         /* No fill strokes, must show stroke always */
@@ -1117,14 +1077,13 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
           }
 
           gpencil_add_stroke_vertexdata(
-              cache, ob, gpl, derived_gpf, gps, opacity, tintcolor, false, custonion);
+              cache, ob, gpl, gpf, gps, opacity, tintcolor, false, custonion);
         }
       }
     }
 
     /* edit points (only in edit mode and not play animation not render) */
-    if ((draw_ctx->obact == ob) && (src_gps) && (!playing) && (!is_render) &&
-        (!cache_ob->is_dup_ob)) {
+    if ((draw_ctx->obact == ob) && (!playing) && (!is_render) && (!cache_ob->is_dup_ob)) {
       if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
         if (!stl->g_data->shgrps_edit_line) {
           stl->g_data->shgrps_edit_line = DRW_shgroup_create(e_data->gpencil_line_sh,
@@ -1137,11 +1096,9 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
           DRW_shgroup_uniform_vec2(stl->g_data->shgrps_edit_point, "Viewport", viewport_size, 1);
         }
 
-        gpencil_add_editpoints_vertexdata(cache, ob, gpd, gpl, derived_gpf, src_gps);
+        gpencil_add_editpoints_vertexdata(cache, ob, gpd, gpl, gpf, gps);
       }
     }
-
-    GP_SET_SRC_GPS(src_gps);
   }
 }
 
@@ -1349,25 +1306,6 @@ static void gpencil_draw_onionskins(GpencilBatchCache *cache,
   }
 }
 
-static void gpencil_copy_frame(bGPDframe *gpf, bGPDframe *derived_gpf)
-{
-  derived_gpf->prev = gpf->prev;
-  derived_gpf->next = gpf->next;
-  derived_gpf->framenum = gpf->framenum;
-  derived_gpf->flag = gpf->flag;
-  derived_gpf->key_type = gpf->key_type;
-  derived_gpf->runtime = gpf->runtime;
-  copy_m4_m4(derived_gpf->runtime.viewmatrix, gpf->runtime.viewmatrix);
-
-  /* copy strokes */
-  BLI_listbase_clear(&derived_gpf->strokes);
-  for (bGPDstroke *gps_src = gpf->strokes.first; gps_src; gps_src = gps_src->next) {
-    /* make copy of source stroke */
-    bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
-    BLI_addtail(&derived_gpf->strokes, gps_dst);
-  }
-}
-
 /* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was
  * modified) */
 void DRW_gpencil_triangulate_stroke_fill(Object *ob, bGPDstroke *gps)
@@ -1878,7 +1816,6 @@ void DRW_gpencil_populate_multiedit(GPENCIL_e_data *e_data,
                                gpd,
                                gpl,
                                gpf,
-                               gpf,
                                gpl->opacity,
                                gpl->tintcolor,
                                false,
@@ -1896,7 +1833,6 @@ void DRW_gpencil_populate_multiedit(GPENCIL_e_data *e_data,
                              gpd,
                              gpl,
                              gpf,
-                             gpf,
                              gpl->opacity,
                              gpl->tintcolor,
                              false,
@@ -1912,28 +1848,6 @@ void DRW_gpencil_populate_multiedit(GPENCIL_e_data *e_data,
   cache->is_dirty = false;
 }
 
-/* ensure there is a derived frame */
-static void gpencil_ensure_derived_frame(bGPdata *gpd,
-                                         bGPDlayer *gpl,
-                                         bGPDframe *gpf,
-                                         GpencilBatchCache *cache,
-                                         bGPDframe **derived_gpf)
-{
-  /* create derived frames array data or expand */
-  int derived_idx = BLI_findindex(&gpd->layers, gpl);
-  *derived_gpf = &cache->derived_array[derived_idx];
-
-  /* if no derived frame or dirty cache, create a new one */
-  if ((*derived_gpf == NULL) || (cache->is_dirty)) {
-    if (*derived_gpf != NULL) {
-      /* first clear temp data */
-      BKE_gpencil_free_frame_runtime_data(*derived_gpf);
-    }
-    /* create new data (do not assign new memory)*/
-    gpencil_copy_frame(gpf, *derived_gpf);
-  }
-}
-
 /* helper for populate a complete grease pencil datablock */
 void DRW_gpencil_populate_datablock(GPENCIL_e_data *e_data,
                                     void *vedata,
@@ -1945,7 +1859,9 @@ void DRW_gpencil_populate_datablock(GPENCIL_e_data *e_data,
   const ViewLayer *view_layer = DEG_get_evaluated_view_layer(draw_ctx->depsgraph);
   Scene *scene = draw_ctx->scene;
 
-  bGPdata *gpd = (bGPdata *)ob->data;
+  /* Use original data to shared in edit/transform operators */
+  bGPdata *gpd_eval = (bGPdata *)ob->data;
+  bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id);
 
   View3D *v3d = draw_ctx->v3d;
   int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
@@ -1972,12 +1888,6 @@ void DRW_gpencil_populate_datablock(GPENCIL_e_data *e_data,
   /* calc max size of VBOs */
   gpencil_calc_vertex(stl, cache_ob, cache, gpd, cfra_eval);
 
-  /* init general modifiers data */
-  if (!stl->storage->simplify_modif) {
-    if ((cache->is_dirty) && (ob->greasepencil_modifiers.first)) {
-      BKE_gpencil_lattice_init(ob);
-    }
-  }
   /* draw normal strokes */
   for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
     /* don't draw layer if hidden */
@@ -2025,8 +1935,9 @@ void DRW_gpencil_populate_datablock(GPENCIL_e_data *e_data,
       opacity = opacity * v3d->overlay.gpencil_fade_layer;
     }
 
-    /* create derived frames array data or expand */
-    gpencil_ensure_derived_frame(gpd, gpl, gpf, cache, &derived_gpf);
+    /* Get derived frames array data */
+    int derived_idx = BLI_findindex(&gpd->layers, gpl);
+    derived_gpf = &ob->runtime.derived_frames[derived_idx];
 
     /* draw onion skins */
     if (!ID_IS_LINKED(&gpd->id)) {
@@ -2046,7 +1957,6 @@ void DRW_gpencil_populate_datablock(GPENCIL_e_data *e_data,
                          ob,
                          gpd,
                          gpl,
-                         gpf,
                          derived_gpf,
                          opacity,
                          gpl->tintcolor,
@@ -2054,11 +1964,6 @@ void DRW_gpencil_populate_datablock(GPENCIL_e_data *e_data,
                          cache_ob);
   }
 
-  /* clear any lattice data */
-  if ((cache->is_dirty) && (ob->greasepencil_modifiers.first)) {
-    BKE_gpencil_lattice_clear(ob);
-  }
-
   /* create batchs and shading groups */
   DRW_gpencil_create_batches(cache);
   DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
index 6c673e9..52688f3 100644 (file)
@@ -49,23 +49,6 @@ struct GpencilBatchGroup;
 #define GPENCIL_COLOR_TEXTURE 1
 #define GPENCIL_COLOR_PATTERN 2
 
-#define GP_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE))
-#define GP_SIMPLIFY_ONPLAY(playing) \
-  (((playing == true) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ON_PLAY)) || \
-   ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ON_PLAY) == 0))
-#define GP_SIMPLIFY_FILL(scene, playing) \
-  ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && \
-    (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FILL)))
-#define GP_SIMPLIFY_MODIF(scene, playing) \
-  ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && \
-    (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER)))
-#define GP_SIMPLIFY_FX(scene, playing) \
-  ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && \
-    (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FX)))
-#define GP_SIMPLIFY_BLEND(scene, playing) \
-  ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && \
-    (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_BLEND)))
-
 #define GP_IS_CAMERAVIEW ((rv3d != NULL) && (rv3d->persp == RV3D_CAMOB && v3d->camera))
 
 /* *********** OBJECTS CACHE *********** */
index c8d2547..896cb8d 100644 (file)
@@ -632,6 +632,59 @@ struct GP_EditableStrokes_Iter {
   } \
   (void)0
 
+/**
+ * Iterate over all editable strokes using derived data in the current context,
+ * stopping on each usable layer + stroke pair (i.e. gpl and gps)
+ * to perform some operations on the stroke.
+ *
+ * \param gpl: The identifier to use for the layer of the stroke being processed.
+ *                    Choose a suitable value to avoid name clashes.
+ * \param gps: The identifier to use for current stroke being processed.
+ *                    Choose a suitable value to avoid name clashes.
+ */
+#define GP_DERIVED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps) \
+  { \
+    struct GP_EditableStrokes_Iter gpstroke_iter = {{{0}}}; \
+    Depsgraph *depsgraph_ = CTX_data_depsgraph(C); \
+    Object *obact_ = CTX_data_active_object(C); \
+    Object *obeval_ = DEG_get_evaluated_object(depsgraph_, obact_); \
+    bGPdata *gpd_ = CTX_data_gpencil_data(C); \
+    const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \
+    int derived_idx = 0; \
+    for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { \
+      if (gpencil_layer_is_editable(gpl)) { \
+        bGPDframe *init_gpf_ = gpl->actframe; \
+        if (is_multiedit_) { \
+          init_gpf_ = gpl->frames.first; \
+        } \
+        for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \
+          if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \
+            ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \
+            /* get derived frame with modifiers applied */ \
+            bGPDframe *derived_gpf_ = &obeval_->runtime.derived_frames[derived_idx]; \
+            /* loop over strokes */ \
+            for (bGPDstroke *gps = derived_gpf_->strokes.first; gps; gps = gps->next) { \
+              /* skip strokes that are invalid for current view */ \
+              if (ED_gpencil_stroke_can_use(C, gps) == false) \
+                continue; \
+              /* check if the color is editable */ \
+              if (ED_gpencil_stroke_color_use(obact_, gpl, gps) == false) \
+                continue; \
+    /* ... Do Stuff With Strokes ...  */
+
+#define GP_DERIVED_STROKES_END(gpstroke_iter) \
+  } \
+  } \
+  if (!is_multiedit_) { \
+    break; \
+  } \
+  } \
+  } \
+  derived_idx++; \
+  } \
+  } \
+  (void)0
+
 /* ****************************************************** */
 
 #endif /* __GPENCIL_INTERN_H__ */
index ba80602..53dbd02 100644 (file)
@@ -802,6 +802,7 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
 {
   bGPDspoint *pt1 = NULL;
   bGPDspoint *pt2 = NULL;
+  bGPDstroke *gps_orig = gps->runtime.gps_orig;
   int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
   int i;
   bool changed = false;
@@ -817,12 +818,12 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
       if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) {
         /* change selection */
         if (select) {
-          gps->points->flag |= GP_SPOINT_SELECT;
-          gps->flag |= GP_STROKE_SELECT;
+          gps_orig->points->flag |= GP_SPOINT_SELECT;
+          gps_orig->flag |= GP_STROKE_SELECT;
         }
         else {
-          gps->points->flag &= ~GP_SPOINT_SELECT;
-          gps->flag &= ~GP_STROKE_SELECT;
+          gps_orig->points->flag &= ~GP_SPOINT_SELECT;
+          gps_orig->flag &= ~GP_STROKE_SELECT;
         }
 
         return true;
@@ -862,15 +863,21 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
            */
           hit = true;
           if (select) {
-            pt1->flag |= GP_SPOINT_SELECT;
-            pt2->flag |= GP_SPOINT_SELECT;
-
+            if (pt1->runtime.pt_orig != NULL) {
+              pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+            }
+            if (pt2->runtime.pt_orig != NULL) {
+              pt2->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+            }
             changed = true;
           }
           else {
-            pt1->flag &= ~GP_SPOINT_SELECT;
-            pt2->flag &= ~GP_SPOINT_SELECT;
-
+            if (pt1->runtime.pt_orig != NULL) {
+              pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+            }
+            if (pt2->runtime.pt_orig != NULL) {
+              pt2->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+            }
             changed = true;
           }
         }
@@ -884,24 +891,28 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
     /* if stroke mode expand selection */
     if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
       for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) {
-        if (select) {
-          pt1->flag |= GP_SPOINT_SELECT;
-        }
-        else {
-          pt1->flag &= ~GP_SPOINT_SELECT;
+        if (pt1->runtime.pt_orig != NULL) {
+          if (select) {
+            pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+          }
+          else {
+            pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+          }
         }
       }
     }
 
     /* expand selection to segment */
-    if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select)) {
+    if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) &&
+        (pt1->runtime.pt_orig != NULL)) {
       float r_hita[3], r_hitb[3];
       bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT);
-      ED_gpencil_select_stroke_segment(gpl, gps, pt1, hit_select, false, scale, r_hita, r_hitb);
+      ED_gpencil_select_stroke_segment(
+          gpl, gps_orig, pt1->runtime.pt_orig, hit_select, false, scale, r_hita, r_hitb);
     }
 
     /* Ensure that stroke selection is in sync with its points */
-    BKE_gpencil_stroke_sync_selection(gps);
+    BKE_gpencil_stroke_sync_selection(gps_orig);
   }
 
   return changed;
@@ -955,11 +966,12 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
   rect.ymax = my + radius;
 
   /* find visible strokes, and select if hit */
-  GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+  GP_DERIVED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
+  {
     changed |= gp_stroke_do_circle_sel(
         gpl, gps, &gsc, mx, my, radius, select, &rect, gpstroke_iter.diff_mat, selectmode, scale);
   }
-  GP_EDITABLE_STROKES_END(gpstroke_iter);
+  GP_DERIVED_STROKES_END(gpstroke_iter);
 
   /* updates */
   if (changed) {
@@ -1057,28 +1069,39 @@ static int gpencil_generic_select_exec(bContext *C,
   }
 
   /* select/deselect points */
-  GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+  GP_DERIVED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
+  {
 
     bGPDspoint *pt;
     int i;
     bool hit = false;
     for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+      if (pt->runtime.pt_orig == NULL) {
+        continue;
+      }
+
       /* convert point coords to screenspace */
       const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
 
       if (strokemode == false) {
-        const bool is_select = (pt->flag & GP_SPOINT_SELECT) != 0;
+        const bool is_select = (pt->runtime.pt_orig->flag & GP_SPOINT_SELECT) != 0;
         const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
         if (sel_op_result != -1) {
-          SET_FLAG_FROM_TEST(pt->flag, sel_op_result, GP_SPOINT_SELECT);
+          SET_FLAG_FROM_TEST(pt->runtime.pt_orig->flag, sel_op_result, GP_SPOINT_SELECT);
           changed = true;
 
           /* expand selection to segment */
           if ((sel_op_result != -1) && (segmentmode)) {
-            bool hit_select = (bool)(pt->flag & GP_SPOINT_SELECT);
+            bool hit_select = (bool)(pt->runtime.pt_orig->flag & GP_SPOINT_SELECT);
             float r_hita[3], r_hitb[3];
-            ED_gpencil_select_stroke_segment(
-                gpl, gps, pt, hit_select, false, scale, r_hita, r_hitb);
+            ED_gpencil_select_stroke_segment(gpl,
+                                             gps->runtime.gps_orig,
+                                             pt->runtime.pt_orig,
+                                             hit_select,
+                                             false,
+                                             scale,
+                                             r_hita,
+                                             r_hitb);
           }
         }
       }
@@ -1092,16 +1115,19 @@ static int gpencil_generic_select_exec(bContext *C,
 
     /* if stroke mode expand selection */
     if (strokemode) {
-      const bool is_select = BKE_gpencil_stroke_select_check(gps);
+      const bool is_select = BKE_gpencil_stroke_select_check(gps->runtime.gps_orig);
       const bool is_inside = hit;
       const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
       if (sel_op_result != -1) {
         for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+          if (pt->runtime.pt_orig == NULL) {
+            continue;
+          }
           if (sel_op_result) {
-            pt->flag |= GP_SPOINT_SELECT;
+            pt->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
           }
           else {
-            pt->flag &= ~GP_SPOINT_SELECT;
+            pt->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
           }
         }
         changed = true;
@@ -1109,9 +1135,9 @@ static int gpencil_generic_select_exec(bContext *C,
     }
 
     /* Ensure that stroke selection is in sync with its points */
-    BKE_gpencil_stroke_sync_selection(gps);
+    BKE_gpencil_stroke_sync_selection(gps->runtime.gps_orig);
   }
-  GP_EDITABLE_STROKES_END(gpstroke_iter);
+  GP_DERIVED_STROKES_END(gpstroke_iter);
 
   /* if paint mode,delete selected points */
   if (gpd->flag & GP_DATA_STROKE_PAINTMODE) {
@@ -1328,13 +1354,17 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
 
   /* First Pass: Find stroke point which gets hit */
   /* XXX: maybe we should go from the top of the stack down instead... */
-  GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+  GP_DERIVED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
+  {
     bGPDspoint *pt;
     int i;
 
     /* firstly, check for hit-point */
     for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
       int xy[2];
+      if (pt->runtime.pt_orig == NULL) {
+        continue;
+      }
 
       bGPDspoint pt2;
       gp_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2);
@@ -1349,15 +1379,15 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
           /* only use this point if it is a better match than the current hit - T44685 */
           if (pt_distance < hit_distance) {
             hit_layer = gpl;
-            hit_stroke = gps;
-            hit_point = pt;
+            hit_stroke = gps->runtime.gps_orig;
+            hit_point = pt->runtime.pt_orig;
             hit_distance = pt_distance;
           }
         }
       }
     }
   }
-  GP_EDITABLE_STROKES_END(gpstroke_iter);
+  GP_DERIVED_STROKES_END(gpstroke_iter);
 
   /* Abort if nothing hit... */
   if (ELEM(NULL, hit_stroke, hit_point)) {
index bb38311..82fca69 100644 (file)
@@ -51,6 +51,11 @@ typedef struct bGPDcontrolpoint {
   int size;
 } bGPDcontrolpoint;
 
+typedef struct bGPDspoint_Runtime {
+  /** Original point (used to dereference evaluated data) */
+  struct bGPDspoint *pt_orig;
+} bGPDspoint_Runtime;
+
 /* Grease-Pencil Annotations - 'Stroke Point'
  * -> Coordinates may either be 2d or 3d depending on settings at the time
  * -> Coordinates of point on stroke, in proportions of window size
@@ -72,6 +77,10 @@ typedef struct bGPDspoint {
   float uv_fac;
   /** Uv rotation for dot mode. */
   float uv_rot;
+
+  /** Runtime data */
+  char _pad2[4];
+  bGPDspoint_Runtime runtime;
 } bGPDspoint;
 
 /* bGPDspoint->flag */
@@ -157,15 +166,21 @@ typedef enum eGPDpalette_Flag {
 
 /* Runtime temp data for bGPDstroke */
 typedef struct bGPDstroke_Runtime {
-  /* runtime final colors (result of original colors and modifiers) */
+  /** runtime final colors (result of original colors and modifiers) */
   float tmp_stroke_rgba[4];
+
+  /** runtime final fill colors (result of original colors and modifiers) */
   float tmp_fill_rgba[4];
 
-  /* temporary layer name only used during copy/paste to put the stroke in the original layer */
+  /** temporary layer name only used during copy/paste to put the stroke in the original layer */
   char tmp_layerinfo[128];
 
   /** Runtime falloff factor (only for transform). */
   float multi_frame_falloff;
+  char _pad[4];
+
+  /** Original stroke (used to dereference evaluated data) */
+  struct bGPDstroke *gps_orig;
 } bGPDstroke_Runtime;
 
 /* Grease-Pencil Annotations - 'Stroke'
@@ -211,7 +226,6 @@ typedef struct bGPDstroke {
   void *_pad3;
 
   bGPDstroke_Runtime runtime;
-  char _pad2[4];
 } bGPDstroke;
 
 /* bGPDstroke->flag */
index 1aeb4a2..e53bc8f 100644 (file)
@@ -161,6 +161,10 @@ typedef struct Object_Runtime {
 
   /** Runtime grease pencil drawing data */
   struct GpencilBatchCache *gpencil_cache;
+  /** Runtime grease pencil derived data created by modifiers */
+  int tot_layers;
+  char _pad1[4];
+  struct bGPDframe *derived_frames;
 } Object_Runtime;
 
 typedef struct Object {