[Bf-blender-cvs] [8a1cc77fdd1] greasepencil-refactor: GPencil: Refactor: Implement sbuffer stroke drawing

Clément Foucault noreply at git.blender.org
Fri Jan 3 22:28:29 CET 2020


Commit: 8a1cc77fdd1ca724906499221822f245305158e4
Author: Clément Foucault
Date:   Fri Jan 3 03:51:53 2020 +0100
Branches: greasepencil-refactor
https://developer.blender.org/rB8a1cc77fdd1ca724906499221822f245305158e4

GPencil: Refactor: Implement sbuffer stroke drawing

This is to be able to view strokes currently being drawn.

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

M	source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
M	source/blender/draw/engines/gpencil/gpencil_engine.c
M	source/blender/draw/engines/gpencil/gpencil_engine.h
M	source/blender/editors/gpencil/gpencil_paint.c
M	source/blender/editors/gpencil/gpencil_primitive.c
M	source/blender/editors/gpencil/gpencil_utils.c
M	source/blender/makesdna/DNA_gpencil_types.h

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

diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
index 457965f050c..32c7d393955 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
@@ -24,6 +24,8 @@
 #include "BLI_polyfill_2d.h"
 #include "BLI_math_color.h"
 
+#include "DEG_depsgraph_query.h"
+
 #include "DNA_meshdata_types.h"
 #include "DNA_gpencil_types.h"
 #include "DNA_screen_types.h"
@@ -138,7 +140,7 @@ static void gpencil_buffer_add_stroke(gpStrokeVert *verts, const bGPDstroke *gps
   int v = gps->runtime.stroke_start;
 
   /* First point for adjacency (not drawn). */
-  int adj_idx = (is_cyclic) ? (pts_len - 1) : 1;
+  int adj_idx = (is_cyclic) ? (pts_len - 1) : min_ii(pts_len - 1, 1);
   gpencil_buffer_add_point(verts, gps, &pts[adj_idx], v++, true);
 
   for (int i = 0; i < pts_len; i++) {
@@ -149,14 +151,13 @@ static void gpencil_buffer_add_stroke(gpStrokeVert *verts, const bGPDstroke *gps
     gpencil_buffer_add_point(verts, gps, &pts[0], v++, false);
   }
   /* Last adjacency point (not drawn). */
-  adj_idx = (is_cyclic) ? 1 : (pts_len - 2);
+  adj_idx = (is_cyclic) ? 1 : max_ii(0, pts_len - 2);
   gpencil_buffer_add_point(verts, gps, &pts[adj_idx], v++, true);
 }
 
 static void gpencil_buffer_add_fill(GPUIndexBufBuilder *ibo, const bGPDstroke *gps)
 {
   int tri_len = gps->tot_triangles;
-  /* Add one for the adjacency index. */
   int v = gps->runtime.stroke_start;
   for (int i = 0; i < tri_len; i++) {
     uint *tri = gps->triangles[i].verts;
@@ -255,6 +256,98 @@ GPUBatch *GPENCIL_batch_cache_fills(Object *ob, int cfra)
   return cache->fill_batch;
 }
 
+/* Return true if there is anything to draw. */
+bool GPENCIL_batch_from_sbuffer(Object *ob,
+                                GPUBatch **r_stroke_batch,
+                                GPUBatch **r_fill_batch,
+                                bGPDstroke **r_stroke)
+{
+  bGPdata *gpd = (bGPdata *)ob->data;
+  /* Current stroke data is stored in the original id. This is waiting refactor of the
+   * Depsgraph to support more granular update of the GPencil data.  */
+  bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
+  tGPspoint *tpoints = gpd_orig->runtime.sbuffer;
+  int vert_len = gpd_orig->runtime.sbuffer_used;
+
+  if (vert_len <= 0) {
+    *r_stroke_batch = NULL;
+    *r_fill_batch = NULL;
+    return false;
+  }
+
+  const DRWContextState *draw_ctx = DRW_context_state_get();
+  Scene *scene = draw_ctx->scene;
+  ARegion *ar = draw_ctx->ar;
+
+  /* Get origin to reproject points. */
+  float origin[3];
+  bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+  ToolSettings *ts = scene->toolsettings;
+  ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
+
+  /* Convert the sbuffer to a bGPDstroke. */
+  bGPDstroke *gps = *r_stroke = MEM_callocN(sizeof(*gps), "bGPDstroke sbuffer");
+  gps->totpoints = vert_len;
+  gps->mat_nr = gpd_orig->runtime.matid - 1;
+  gps->flag = gpd_orig->runtime.sbuffer_sflag;
+  gps->thickness = gpd_orig->runtime.brush_size;
+  gps->tot_triangles = max_ii(0, vert_len - 2);
+  gps->caps[0] = gps->caps[1] = GP_STROKE_CAP_ROUND;
+  gps->runtime.stroke_start = 1; /* Add one for the adjacency index. */
+  gps->points = MEM_mallocN(vert_len * sizeof(*gps->points), __func__);
+
+  for (int i = 0; i < vert_len; i++) {
+    ED_gpencil_tpoint_to_point(ar, origin, &tpoints[i], &gps->points[i]);
+    mul_m4_v3(ob->imat, &gps->points[i].x);
+  }
+
+  /* Create VBO. */
+  GPUVertFormat *format = gpencil_stroke_format();
+  GPUVertBuf *vbo = GPU_vertbuf_create_with_format(format);
+  /* Add extra space at the end (and start) of the buffer because of quad load and cyclic. */
+  GPU_vertbuf_data_alloc(vbo, 1 + vert_len + 1 + 2);
+  gpStrokeVert *verts = (gpStrokeVert *)vbo->data;
+  /* Create IBO. */
+  GPUIndexBufBuilder ibo_builder;
+  GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, gps->tot_triangles, vert_len);
+
+  /* Fill buffers with data. */
+  gpencil_buffer_add_stroke(verts, gps);
+
+  if (gps->tot_triangles > 0) {
+    float(*tpoints2d)[2] = MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__);
+    /* Triangulate in 2D. */
+    for (int i = 0; i < vert_len; i++) {
+      copy_v2_v2(tpoints2d[i], &tpoints[i].x);
+    }
+    /* Compute directly inside the IBO data buffer. */
+    BLI_polyfill_calc(tpoints2d, (uint)vert_len, 0, (uint(*)[3])ibo_builder.data);
+    /* Add stroke start offset. */
+    for (int i = 0; i < gps->tot_triangles * 3; i++) {
+      ibo_builder.data[i] += gps->runtime.stroke_start;
+    }
+    /* HACK since we didn't use the builder API to avoid another malloc and copy,
+     * we need to set the number of indices manually. */
+    ibo_builder.index_len = gps->tot_triangles * 3;
+
+    MEM_freeN(tpoints2d);
+  }
+
+  /* Finish the IBO. */
+  GPUIndexBuf *ibo = GPU_indexbuf_build(&ibo_builder);
+
+  /* Create the batches */
+  *r_stroke_batch = GPU_batch_create(GPU_PRIM_TRI_STRIP, gpencil_dummy_buffer_get(), NULL);
+  GPU_batch_instbuf_add_ex(*r_stroke_batch, vbo, 0);
+  /* NOTE/WARNING: We make the fill batch the owner of the vbo to make cleanup easier. */
+  *r_fill_batch = GPU_batch_create_ex(
+      GPU_PRIM_TRIS, vbo, ibo, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
+
+  MEM_SAFE_FREE(gps->points);
+
+  return true;
+}
+
 /* ----------- End of new code ----------- */
 
 /* Helper to add stroke point to vbo */
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index ecdbf24443e..59631b96114 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -466,6 +466,25 @@ static void GPENCIL_cache_init_new(void *ved)
     pd->do_onion = true;
   }
 
+  {
+    pd->sbuffer_stroke = NULL;
+    pd->sbuffer_gpd = NULL;
+    pd->sbuffer_layer = NULL;
+    pd->stroke_batch = NULL;
+    pd->fill_batch = NULL;
+    pd->do_stroke_fast_drawing = false;
+
+    Object *ob = draw_ctx->obact;
+    if (ob && ob->type == OB_GPENCIL) {
+      /* Check if active object has a temp stroke data. */
+      if (GPENCIL_batch_from_sbuffer(
+              ob, &pd->stroke_batch, &pd->fill_batch, &pd->sbuffer_stroke)) {
+        pd->sbuffer_gpd = (bGPdata *)ob->data;
+        pd->sbuffer_layer = BKE_gpencil_layer_getactive(pd->sbuffer_gpd);
+      }
+    }
+  }
+
   {
     DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM;
     DRW_PASS_CREATE(psl->composite_ps, state);
@@ -857,6 +876,8 @@ static void gpencil_add_draw_data(void *vedata, Object *ob)
   }
 }
 
+#define DRAW_NOW 2
+
 typedef struct gpIterPopulateData {
   Object *ob;
   GPENCIL_tObject *tgp_ob;
@@ -871,8 +892,15 @@ typedef struct gpIterPopulateData {
   /* Last texture bound. */
   GPUTexture *tex_fill;
   GPUTexture *tex_stroke;
+  /* Is the sbuffer call need to be issued. */
+  int do_sbuffer_call;
 } gpIterPopulateData;
 
+static void gp_stroke_cache_populate(bGPDlayer *UNUSED(gpl),
+                                     bGPDframe *UNUSED(gpf),
+                                     bGPDstroke *gps,
+                                     void *thunk);
+
 static void gp_layer_cache_populate(bGPDlayer *gpl,
                                     bGPDframe *gpf,
                                     bGPDstroke *UNUSED(gps),
@@ -881,6 +909,15 @@ static void gp_layer_cache_populate(bGPDlayer *gpl,
   gpIterPopulateData *iter = (gpIterPopulateData *)thunk;
   bGPdata *gpd = (bGPdata *)iter->ob->data;
 
+  if (iter->do_sbuffer_call) {
+    iter->do_sbuffer_call = DRAW_NOW;
+    gp_stroke_cache_populate(NULL, NULL, iter->pd->sbuffer_stroke, thunk);
+    iter->do_sbuffer_call = 0;
+  }
+  else {
+    iter->do_sbuffer_call = (gpd == iter->pd->sbuffer_gpd) && (gpl == iter->pd->sbuffer_layer);
+  }
+
   GPENCIL_tLayer *tgp_layer_prev = iter->tgp_ob->layers.last;
   GPENCIL_tLayer *tgp_layer = gpencil_layer_cache_add_new(iter->pd, iter->ob, gpl);
   BLI_LINKS_APPEND(&iter->tgp_ob->layers, tgp_layer);
@@ -988,6 +1025,7 @@ static void gp_stroke_cache_populate(bGPDlayer *UNUSED(gpl),
 
   if (show_fill) {
     GPUBatch *geom = GPENCIL_batch_cache_fills(iter->ob, iter->pd->cfra);
+    geom = (iter->do_sbuffer_call == DRAW_NOW) ? iter->pd->fill_batch : geom;
     int vfirst = gps->runtime.fill_start * 3;
     int vcount = gps->tot_triangles * 3;
     DRW_shgroup_call_range(iter->grp, geom, vfirst, vcount);
@@ -995,6 +1033,7 @@ static void gp_stroke_cache_populate(bGPDlayer *UNUSED(gpl),
 
   if (show_stroke) {
     GPUBatch *geom = GPENCIL_batch_cache_strokes(iter->ob, iter->pd->cfra);
+    geom = (iter->do_sbuffer_call == DRAW_NOW) ? iter->pd->stroke_batch : geom;
     /* Start one vert before to have gl_InstanceID > 0 (see shader). */
     int vfirst = gps->runtime.stroke_start - 1;
     /* Include "potential" cyclic vertex and start adj vertex (see shader). */
@@ -1026,6 +1065,11 @@ static void GPENCIL_cache_populate_new(void *ved, Object *ob)
     gpencil_object_visible_stroke_iter(
         ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, pd->do_onion);
 
+    if (iter.do_sbuffer_call) {
+      iter.do_sbuffer_call = DRAW_NOW;
+      gp_stroke_cache_populate(NULL, NULL, iter.pd->sbuffer_stroke, &iter);
+    }
+
     gpencil_vfx_cache_populate(vedata, ob, iter.tgp_ob);
   }
 
@@ -1526,6 +1570,11 @@ static void GPENCIL_draw_scene_new(void *ved)
   }
 
   pd->gp_object_pool = pd->gp_layer_pool = pd->gp_vfx_pool = NULL;
+
+  /* Free temp stroke buffers. */
+  GPU_BATCH_DISCARD_SAFE(pd->stroke_batch);
+  GPU_BATCH_DISCARD_SAFE(pd->fill_batch);
+  MEM_SAFE_FREE(pd->sbuffer_stroke);
 }
 
 /* draw scene */
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 44df7f5329d..d62824c1da6 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -492,6 +492,19 @@ typedef struct GPENCIL_PrivateData {
   float dof_params[2];
   /* Used for DoF Setup. */
   Object *camera;
+
+  /* Object being in draw mode. */
+  struct bGPdata *sbuffer_gpd;
+  /* Layer to append

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list