Blender  V3.3
draw_cache_impl_gpencil.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2020 Blender Foundation. */
3 
8 #include "DNA_curve_types.h"
9 #include "DNA_gpencil_types.h"
10 #include "DNA_meshdata_types.h"
11 #include "DNA_screen_types.h"
12 
13 #include "BKE_deform.h"
14 #include "BKE_gpencil.h"
15 #include "BKE_gpencil_geom.h"
16 
17 #include "DRW_engine.h"
18 #include "DRW_render.h"
19 
20 #include "ED_gpencil.h"
21 #include "GPU_batch.h"
22 
23 #include "DEG_depsgraph_query.h"
24 
25 #include "BLI_hash.h"
26 #include "BLI_polyfill_2d.h"
27 
28 #include "draw_cache.h"
29 #include "draw_cache_impl.h"
30 
31 #include "../engines/gpencil/gpencil_defines.h"
32 
33 #define BEZIER_HANDLE (1 << 3)
34 #define COLOR_SHIFT 5
35 
36 /* -------------------------------------------------------------------- */
40 typedef struct GpencilBatchCache {
50 
59 
61  bool is_dirty;
65 
68 /* -------------------------------------------------------------------- */
72 static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
73 {
74  bool valid = true;
75 
76  if (cache == NULL) {
77  return false;
78  }
79 
80  if (cfra != cache->cache_frame) {
81  valid = false;
82  }
83  else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
84  valid = false;
85  }
86  else if (cache->is_dirty) {
87  valid = false;
88  }
89 
90  return valid;
91 }
92 
94 {
95  bGPdata *gpd = (bGPdata *)ob->data;
96 
98 
99  if (!cache) {
100  cache = gpd->runtime.gpencil_cache = MEM_callocN(sizeof(*cache), __func__);
101  }
102  else {
103  memset(cache, 0, sizeof(*cache));
104  }
105 
106  cache->is_dirty = true;
107  cache->cache_frame = cfra;
108 
109  return cache;
110 }
111 
113 {
114  if (!cache) {
115  return;
116  }
117 
124 
128 
132 
133  cache->is_dirty = true;
134 }
135 
137 {
138  bGPdata *gpd = (bGPdata *)ob->data;
139 
141  if (!gpencil_batch_cache_valid(cache, gpd, cfra)) {
143  return gpencil_batch_cache_init(ob, cfra);
144  }
145 
146  return cache;
147 }
148 
151 /* -------------------------------------------------------------------- */
156 {
158 }
159 
161 {
165 }
166 
169 /* -------------------------------------------------------------------- */
173 /* MUST match the format below. */
174 typedef struct gpStrokeVert {
177  float pos[3], thickness;
181 
183 {
184  static GPUVertFormat format = {0};
185  if (format.attr_len == 0) {
189  /* IMPORTANT: This means having only 4 attributes
190  * to fit into GPU module limit of 16 attributes. */
192  }
193  return &format;
194 }
195 
196 /* MUST match the format below. */
197 typedef struct gpEditVert {
199  float weight;
201 
203 {
204  static GPUVertFormat format = {0};
205  if (format.attr_len == 0) {
208  }
209  return &format;
210 }
211 
212 /* MUST match the format below. */
213 typedef struct gpEditCurveVert {
214  float pos[3];
217 
219 {
220  static GPUVertFormat format = {0};
221  if (format.attr_len == 0) {
222  /* initialize vertex formats */
225  }
226  return &format;
227 }
228 
229 /* MUST match the format below. */
230 typedef struct gpColorVert {
231  float vcol[4]; /* Vertex color */
232  float fcol[4]; /* Fill color */
234 
236 {
237  static GPUVertFormat format = {0};
238  if (format.attr_len == 0) {
241  /* IMPORTANT: This means having only 4 attributes
242  * to fit into GPU module limit of 16 attributes. */
244  }
245  return &format;
246 }
247 
250 /* -------------------------------------------------------------------- */
254 typedef struct gpIterData {
259  int vert_len;
260  int tri_len;
263 
265 {
267  return batch->verts[0];
268 }
269 
270 static int gpencil_stroke_is_cyclic(const bGPDstroke *gps)
271 {
272  return ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2);
273 }
274 
276 {
277  int32_t packed = 0;
278  /* Aspect uses 9 bits */
279  float asp_normalized = (asp > 1.0f) ? (1.0f / asp) : asp;
280  packed |= (int32_t)unit_float_to_uchar_clamp(asp_normalized);
281  /* Store if inversed in the 9th bit. */
282  if (asp > 1.0f) {
283  packed |= 1 << 8;
284  }
285  /* Rotation uses 9 bits */
286  /* Rotation are in [-90°..90°] range, so we can encode the sign of the angle + the cosine
287  * because the cosine will always be positive. */
288  packed |= (int32_t)unit_float_to_uchar_clamp(cosf(rot)) << 9;
289  /* Store sine sign in 9th bit. */
290  if (rot < 0.0f) {
291  packed |= 1 << 17;
292  }
293  /* Hardness uses 8 bits */
294  packed |= (int32_t)unit_float_to_uchar_clamp(hard) << 18;
295  return packed;
296 }
297 
299  gpColorVert *cols,
300  const bGPDstroke *gps,
301  const bGPDspoint *pt,
302  int v,
303  bool is_endpoint)
304 {
305  /* NOTE: we use the sign of strength and thickness to pass cap flag. */
306  const bool round_cap0 = (gps->caps[0] == GP_STROKE_CAP_ROUND);
307  const bool round_cap1 = (gps->caps[1] == GP_STROKE_CAP_ROUND);
308  gpStrokeVert *vert = &verts[v];
309  gpColorVert *col = &cols[v];
310  copy_v3_v3(vert->pos, &pt->x);
311  copy_v2_v2(vert->uv_fill, pt->uv_fill);
312  copy_v4_v4(col->vcol, pt->vert_color);
313  copy_v4_v4(col->fcol, gps->vert_color_fill);
314 
315  /* Encode fill opacity defined by opacity modifier in vertex color alpha. If
316  * no opacity modifier, the value will be always 1.0f. The opacity factor can be any
317  * value between 0.0f and 2.0f */
318  col->fcol[3] = (((int)(col->fcol[3] * 10000.0f)) * 10.0f) + gps->fill_opacity_fac;
319 
320  vert->strength = (round_cap0) ? pt->strength : -pt->strength;
321  vert->u_stroke = pt->uv_fac;
322  vert->stroke_id = gps->runtime.stroke_start;
323  vert->point_id = v;
324  vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0f : -1.0f);
325  /* Tag endpoint material to -1 so they get discarded by vertex shader. */
326  vert->mat = (is_endpoint) ? -1 : (gps->mat_nr % GPENCIL_MATERIAL_BUFFER_LEN);
327 
328  float aspect_ratio = gps->aspect_ratio[0] / max_ff(gps->aspect_ratio[1], 1e-8);
329 
331  pt->uv_rot, aspect_ratio, gps->hardeness);
332 }
333 
335  gpColorVert *cols,
336  const bGPDstroke *gps)
337 {
338  const bGPDspoint *pts = gps->points;
339  int pts_len = gps->totpoints;
341  int v = gps->runtime.stroke_start;
342 
343  /* First point for adjacency (not drawn). */
344  int adj_idx = (is_cyclic) ? (pts_len - 1) : min_ii(pts_len - 1, 1);
345  gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true);
346 
347  for (int i = 0; i < pts_len; i++) {
348  gpencil_buffer_add_point(verts, cols, gps, &pts[i], v++, false);
349  }
350  /* Draw line to first point to complete the loop for cyclic strokes. */
351  if (is_cyclic) {
352  gpencil_buffer_add_point(verts, cols, gps, &pts[0], v, false);
353  /* UV factor needs to be adjusted for the last point to not be equal to the UV factor of the
354  * first point. It should be the factor of the last point plus the distance from the last point
355  * to the first.
356  */
357  gpStrokeVert *vert = &verts[v];
358  vert->u_stroke = verts[v - 1].u_stroke + len_v3v3(&pts[pts_len - 1].x, &pts[0].x);
359  v++;
360  }
361  /* Last adjacency point (not drawn). */
362  adj_idx = (is_cyclic) ? 1 : max_ii(0, pts_len - 2);
363  gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true);
364 }
365 
367 {
368  int tri_len = gps->tot_triangles;
369  int v = gps->runtime.stroke_start;
370  for (int i = 0; i < tri_len; i++) {
371  uint *tri = gps->triangles[i].verts;
372  GPU_indexbuf_add_tri_verts(ibo, v + tri[0], v + tri[1], v + tri[2]);
373  }
374 }
375 
377  bGPDframe *UNUSED(gpf),
378  bGPDstroke *gps,
379  void *thunk)
380 {
381  gpIterData *iter = (gpIterData *)thunk;
382  gpencil_buffer_add_stroke(iter->verts, iter->cols, gps);
383  if (gps->tot_triangles > 0) {
384  gpencil_buffer_add_fill(&iter->ibo, gps);
385  }
386 }
387 
389  bGPDframe *UNUSED(gpf),
390  bGPDstroke *gps,
391  void *thunk)
392 {
393  gpIterData *iter = (gpIterData *)thunk;
394 
395  /* Store first index offset */
396  gps->runtime.stroke_start = iter->vert_len;
397  gps->runtime.fill_start = iter->tri_len;
398  iter->vert_len += gps->totpoints + 2 + gpencil_stroke_is_cyclic(gps);
399  iter->tri_len += gps->tot_triangles;
400 }
401 
402 static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra)
403 {
404  bGPdata *gpd = (bGPdata *)ob->data;
405 
406  if (cache->vbo == NULL) {
407  /* Should be discarded together. */
408  BLI_assert(cache->vbo == NULL && cache->ibo == NULL);
409  BLI_assert(cache->fill_batch == NULL && cache->stroke_batch == NULL);
410  /* TODO/PERF: Could be changed to only do it if needed.
411  * For now it's simpler to assume we always need it
412  * since multiple viewport could or could not need it.
413  * Ideally we should have a dedicated onion skin geom batch. */
414  /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */
415  bool do_onion = true;
416 
417  /* First count how many vertices and triangles are needed for the whole object. */
418  gpIterData iter = {
419  .gpd = gpd,
420  .verts = NULL,
421  .ibo = {0},
422  .vert_len = 1, /* Start at 1 for the gl_InstanceID trick to work (see vert shader). */
423  .tri_len = 0,
424  .curve_len = 0,
425  };
427  NULL, ob, NULL, gpencil_object_verts_count_cb, &iter, do_onion, cfra);
428 
429  /* Create VBOs. */
431  GPUVertFormat *format_col = gpencil_color_format();
433  cache->vbo_col = GPU_vertbuf_create_with_format(format_col);
434  /* Add extra space at the end of the buffer because of quad load. */
435  GPU_vertbuf_data_alloc(cache->vbo, iter.vert_len + 2);
436  GPU_vertbuf_data_alloc(cache->vbo_col, iter.vert_len + 2);
437  iter.verts = (gpStrokeVert *)GPU_vertbuf_get_data(cache->vbo);
438  iter.cols = (gpColorVert *)GPU_vertbuf_get_data(cache->vbo_col);
439  /* Create IBO. */
440  GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, iter.vert_len);
441 
442  /* Fill buffers with data. */
444  NULL, ob, NULL, gpencil_stroke_iter_cb, &iter, do_onion, cfra);
445 
446  /* Mark last 2 verts as invalid. */
447  for (int i = 0; i < 2; i++) {
448  iter.verts[iter.vert_len + i].mat = -1;
449  }
450  /* Also mark first vert as invalid. */
451  iter.verts[0].mat = -1;
452 
453  /* Finish the IBO. */
454  cache->ibo = GPU_indexbuf_build(&iter.ibo);
455 
456  /* Create the batches */
457  cache->fill_batch = GPU_batch_create(GPU_PRIM_TRIS, cache->vbo, cache->ibo);
458  GPU_batch_vertbuf_add(cache->fill_batch, cache->vbo_col);
460  GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo, 0);
461  GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo_col, 0);
462 
463  gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
464  cache->is_dirty = false;
465  }
466 }
467 
469 {
470  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
471  gpencil_batches_ensure(ob, cache, cfra);
472 
473  return cache->stroke_batch;
474 }
475 
477 {
478  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
479  gpencil_batches_ensure(ob, cache, cfra);
480 
481  return cache->fill_batch;
482 }
483 
485  bGPDframe *UNUSED(gpf),
486  bGPDstroke *gps,
487  void *thunk)
488 {
489  gpIterData *iter = (gpIterData *)thunk;
490  int pts_len = gps->totpoints + gpencil_stroke_is_cyclic(gps);
491 
492  int start = gps->runtime.stroke_start + 1;
493  int end = start + pts_len;
494  for (int i = start; i < end; i++) {
496  }
498 }
499 
501 {
502  const DRWContextState *draw_ctx = DRW_context_state_get();
503  int cfra = DEG_get_ctime(draw_ctx->depsgraph);
504 
505  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
506  gpencil_batches_ensure(ob, cache, cfra);
507 
508  if (cache->lines_batch == NULL) {
509  GPUVertBuf *vbo = cache->vbo;
510 
511  gpIterData iter = {
512  .gpd = ob->data,
513  .ibo = {0},
514  };
515 
516  uint vert_len = GPU_vertbuf_get_vertex_len(vbo);
517  GPU_indexbuf_init_ex(&iter.ibo, GPU_PRIM_LINE_STRIP, vert_len, vert_len);
518 
519  /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */
520  bool do_onion = true;
522  NULL, ob, NULL, gpencil_lines_indices_cb, &iter, do_onion, cfra);
523 
524  GPUIndexBuf *ibo = GPU_indexbuf_build(&iter.ibo);
525 
527  }
528  return cache->lines_batch;
529 }
530 
533 /* ---------------------------------------------------------------------- */
538 {
539  bGPdata *gpd = (bGPdata *)ob->data;
540  Brush *brush = gpd->runtime.sbuffer_brush;
541  /* Convert the sbuffer to a bGPDstroke. */
542  if (gpd->runtime.sbuffer_gps == NULL) {
543  bGPDstroke *gps = MEM_callocN(sizeof(*gps), "bGPDstroke sbuffer");
544  gps->totpoints = gpd->runtime.sbuffer_used;
545  gps->mat_nr = max_ii(0, gpd->runtime.matid - 1);
546  gps->flag = gpd->runtime.sbuffer_sflag;
547  gps->thickness = brush->size;
548  gps->hardeness = brush->gpencil_settings->hardeness;
549  copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio);
550 
551  /* Reduce slightly the opacity of fill to make easy fill areas while drawing. */
552  gps->fill_opacity_fac = 0.8f;
553 
554  gps->tot_triangles = max_ii(0, gpd->runtime.sbuffer_used - 2);
555  gps->caps[0] = gps->caps[1] = GP_STROKE_CAP_ROUND;
556  gps->runtime.stroke_start = 1; /* Add one for the adjacency index. */
558  /* Caps. */
559  gps->caps[0] = gps->caps[1] = (short)brush->gpencil_settings->caps_type;
560 
561  gpd->runtime.sbuffer_gps = gps;
562  }
563  return gpd->runtime.sbuffer_gps;
564 }
565 
566 static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_fill)
567 {
568  tGPspoint *tpoints = gpd->runtime.sbuffer;
569  bGPDstroke *gps = gpd->runtime.sbuffer_gps;
570  int vert_len = gpd->runtime.sbuffer_used;
571 
572  /* DRW_cache_gpencil_sbuffer_stroke_data_get need to have been called previously. */
573  BLI_assert(gps != NULL);
574 
575  if (do_stroke && (gpd->runtime.sbuffer_stroke_batch == NULL)) {
576  gps->points = MEM_mallocN(vert_len * sizeof(*gps->points), __func__);
577 
578  const DRWContextState *draw_ctx = DRW_context_state_get();
579  Scene *scene = draw_ctx->scene;
580  ARegion *region = draw_ctx->region;
581  Object *ob = draw_ctx->obact;
582 
583  BLI_assert(ob && (ob->type == OB_GPENCIL));
584 
585  /* Get origin to reproject points. */
586  float origin[3];
589 
590  for (int i = 0; i < vert_len; i++) {
591  ED_gpencil_tpoint_to_point(region, origin, &tpoints[i], &gps->points[i]);
592  mul_m4_v3(ob->imat, &gps->points[i].x);
593  bGPDspoint *pt = &gps->points[i];
594  copy_v4_v4(pt->vert_color, tpoints[i].vert_color);
595  }
596  /* Calc uv data along the stroke. */
598 
599  /* Create VBO. */
601  GPUVertFormat *format_color = gpencil_color_format();
603  GPUVertBuf *vbo_col = GPU_vertbuf_create_with_format(format_color);
604  /* Add extra space at the end (and start) of the buffer because of quad load and cyclic. */
605  GPU_vertbuf_data_alloc(vbo, 1 + vert_len + 1 + 2);
606  GPU_vertbuf_data_alloc(vbo_col, 1 + vert_len + 1 + 2);
608  gpColorVert *cols = (gpColorVert *)GPU_vertbuf_get_data(vbo_col);
609 
610  /* Fill buffers with data. */
611  gpencil_buffer_add_stroke(verts, cols, gps);
612 
614  GPU_batch_instbuf_add_ex(batch, vbo, true);
615  GPU_batch_instbuf_add_ex(batch, vbo_col, true);
616 
618 
619  MEM_freeN(gps->points);
620  }
621 
622  if (do_fill && (gpd->runtime.sbuffer_fill_batch == NULL)) {
623  /* Create IBO. */
624  GPUIndexBufBuilder ibo_builder;
625  GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, gps->tot_triangles, vert_len);
626 
627  if (gps->tot_triangles > 0) {
628  float(*tpoints2d)[2] = MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__);
629  /* Triangulate in 2D. */
630  for (int i = 0; i < vert_len; i++) {
631  copy_v2_v2(tpoints2d[i], tpoints[i].m_xy);
632  }
633  /* Compute directly inside the IBO data buffer. */
634  /* OPTI: This is a bottleneck if the stroke is very long. */
635  BLI_polyfill_calc(tpoints2d, (uint)vert_len, 0, (uint(*)[3])ibo_builder.data);
636  /* Add stroke start offset. */
637  for (int i = 0; i < gps->tot_triangles * 3; i++) {
638  ibo_builder.data[i] += gps->runtime.stroke_start;
639  }
640  /* HACK since we didn't use the builder API to avoid another malloc and copy,
641  * we need to set the number of indices manually. */
642  ibo_builder.index_len = gps->tot_triangles * 3;
643 
644  MEM_freeN(tpoints2d);
645  }
646 
647  GPUIndexBuf *ibo = GPU_indexbuf_build(&ibo_builder);
648  GPUVertBuf *vbo = gpd->runtime.sbuffer_stroke_batch->inst[0];
649  GPUVertBuf *vbo_col = gpd->runtime.sbuffer_stroke_batch->inst[1];
650 
652  GPU_batch_vertbuf_add(batch, vbo_col);
653 
655  }
656 }
657 
659 {
660  bGPdata *gpd = (bGPdata *)ob->data;
661  gpencil_sbuffer_stroke_ensure(gpd, true, false);
662 
663  return gpd->runtime.sbuffer_stroke_batch;
664 }
665 
667 {
668  bGPdata *gpd = (bGPdata *)ob->data;
669  /* Fill batch also need stroke batch to be created (vbo is shared). */
670  gpencil_sbuffer_stroke_ensure(gpd, true, true);
671 
672  return gpd->runtime.sbuffer_fill_batch;
673 }
674 
676 {
677  bGPdata *gpd = (bGPdata *)ob->data;
681 }
682 
685 /* -------------------------------------------------------------------- */
689 #define GP_EDIT_POINT_SELECTED (1 << 0)
690 #define GP_EDIT_STROKE_SELECTED (1 << 1)
691 #define GP_EDIT_MULTIFRAME (1 << 2)
692 #define GP_EDIT_STROKE_START (1 << 3)
693 #define GP_EDIT_STROKE_END (1 << 4)
694 #define GP_EDIT_POINT_DIMMED (1 << 5)
695 
696 typedef struct gpEditIterData {
698  int vgindex;
700 
701 typedef struct gpEditCurveIterData {
703  int vgindex;
705 
706 static uint32_t gpencil_point_edit_flag(const bool layer_lock,
707  const bGPDspoint *pt,
708  int v,
709  int v_len)
710 {
711  uint32_t sflag = 0;
712  SET_FLAG_FROM_TEST(sflag, (!layer_lock) && pt->flag & GP_SPOINT_SELECT, GP_EDIT_POINT_SELECTED);
714  SET_FLAG_FROM_TEST(sflag, v == (v_len - 1), GP_EDIT_STROKE_END);
716  return sflag;
717 }
718 
719 static float gpencil_point_edit_weight(const MDeformVert *dvert, int v, int vgindex)
720 {
721  return (dvert && dvert[v].dw) ? BKE_defvert_find_weight(&dvert[v], vgindex) : -1.0f;
722 }
723 
725  bGPDframe *gpf,
726  bGPDstroke *gps,
727  void *thunk)
728 {
729  gpEditIterData *iter = (gpEditIterData *)thunk;
730  const int v_len = gps->totpoints;
731  const int v = gps->runtime.stroke_start + 1;
732  MDeformVert *dvert = ((iter->vgindex > -1) && gps->dvert) ? gps->dvert : NULL;
733  gpEditVert *vert_ptr = iter->verts + v;
734 
735  const bool layer_lock = (gpl->flag & GP_LAYER_LOCKED);
736  uint32_t sflag = 0;
738  sflag, (!layer_lock) && gps->flag & GP_STROKE_SELECT, GP_EDIT_STROKE_SELECTED);
740 
741  for (int i = 0; i < v_len; i++) {
742  vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[i], i, v_len);
743  vert_ptr->weight = gpencil_point_edit_weight(dvert, i, iter->vgindex);
744  vert_ptr++;
745  }
746  /* Draw line to first point to complete the loop for cyclic strokes. */
747  vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[0], 0, v_len);
748  vert_ptr->weight = gpencil_point_edit_weight(dvert, 0, iter->vgindex);
749 }
750 
752  bGPDframe *UNUSED(gpf),
753  bGPDstroke *gps,
754  void *thunk)
755 {
756  if (gpl->flag & GP_LAYER_LOCKED) {
757  return;
758  }
759 
760  gpIterData *iter = (gpIterData *)thunk;
761 
762  if (gps->editcurve == NULL) {
763  return;
764  }
765 
766  /* Store first index offset */
767  gps->runtime.curve_start = iter->curve_len;
768  iter->curve_len += gps->editcurve->tot_curve_points * 4;
769 }
770 
772  char col_id,
773  bool handle_point,
774  const bool handle_selected)
775 {
776  uint32_t vflag = 0;
778  SET_FLAG_FROM_TEST(vflag, handle_point, BEZIER_HANDLE);
779  SET_FLAG_FROM_TEST(vflag, handle_selected, VFLAG_VERT_SELECTED_BEZT_HANDLE);
781 
782  /* Handle color id. */
783  vflag |= col_id << COLOR_SHIFT;
784  return vflag;
785 }
786 
788  bGPDframe *UNUSED(gpf),
789  bGPDstroke *gps,
790  void *thunk)
791 {
792  if (gpl->flag & GP_LAYER_LOCKED) {
793  return;
794  }
795 
796  if (gps->editcurve == NULL) {
797  return;
798  }
799  bGPDcurve *editcurve = gps->editcurve;
800  gpEditCurveIterData *iter = (gpEditCurveIterData *)thunk;
801  const int v = gps->runtime.curve_start;
802  gpEditCurveVert *vert_ptr = iter->verts + v;
803  /* Hide points when the curve is unselected. Passing the control point
804  * as handle produces the point shader skip it if you are not in ALL mode. */
805  const bool hide = !(editcurve->flag & GP_CURVE_SELECT);
806 
807  for (int i = 0; i < editcurve->tot_curve_points; i++) {
808  BezTriple *bezt = &editcurve->curve_points[i].bezt;
809  const bool handle_selected = BEZT_ISSEL_ANY(bezt);
810  const uint32_t vflag[3] = {
811  gpencil_beztriple_vflag_get(bezt->f1, bezt->h1, true, handle_selected),
812  gpencil_beztriple_vflag_get(bezt->f2, bezt->h1, hide, handle_selected),
813  gpencil_beztriple_vflag_get(bezt->f3, bezt->h2, true, handle_selected),
814  };
815 
816  /* First segment. */
817  mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[0]);
818  vert_ptr->data = vflag[0];
819  vert_ptr++;
820 
821  mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[1]);
822  vert_ptr->data = vflag[1];
823  vert_ptr++;
824 
825  /* Second segment. */
826  mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[1]);
827  vert_ptr->data = vflag[1];
828  vert_ptr++;
829 
830  mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[2]);
831  vert_ptr->data = vflag[2];
832  vert_ptr++;
833  }
834 }
835 
836 static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra)
837 {
838  bGPdata *gpd = (bGPdata *)ob->data;
839 
840  if (cache->edit_vbo == NULL) {
841  /* TODO/PERF: Could be changed to only do it if needed.
842  * For now it's simpler to assume we always need it
843  * since multiple viewport could or could not need it.
844  * Ideally we should have a dedicated onion skin geom batch. */
845  /* IMPORTANT: Keep in sync with gpencil_batches_ensure() */
846  bool do_onion = true;
847 
848  /* Vertex counting has already been done for cache->vbo. */
849  BLI_assert(cache->vbo);
850  int vert_len = GPU_vertbuf_get_vertex_len(cache->vbo);
851 
852  gpEditIterData iter;
853  iter.vgindex = gpd->vertex_group_active_index - 1;
854  if (!BLI_findlink(&gpd->vertex_group_names, iter.vgindex)) {
855  iter.vgindex = -1;
856  }
857 
858  /* Create VBO. */
861  /* Add extra space at the end of the buffer because of quad load. */
862  GPU_vertbuf_data_alloc(cache->edit_vbo, vert_len);
863  iter.verts = (gpEditVert *)GPU_vertbuf_get_data(cache->edit_vbo);
864 
865  /* Fill buffers with data. */
867  NULL, ob, NULL, gpencil_edit_stroke_iter_cb, &iter, do_onion, cfra);
868 
869  /* Create the batches */
872 
875  }
876 
877  /* Curve Handles and Points for Editing. */
878  if (cache->edit_curve_vbo == NULL) {
879  gpIterData iterdata = {
880  .gpd = gpd,
881  .verts = NULL,
882  .ibo = {0},
883  .vert_len = 0,
884  .tri_len = 0,
885  .curve_len = 0,
886  };
887 
888  /* Create VBO. */
891 
892  /* Count data. */
894  NULL, ob, NULL, gpencil_edit_curve_stroke_count_cb, &iterdata, false, cfra);
895 
896  gpEditCurveIterData iter;
897  int vert_len = iterdata.curve_len;
898  if (vert_len > 0) {
899 
900  GPU_vertbuf_data_alloc(cache->edit_curve_vbo, vert_len);
902 
903  /* Fill buffers with data. */
905  NULL, ob, NULL, gpencil_edit_curve_stroke_iter_cb, &iter, false, cfra);
906 
910 
914  }
915 
916  gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
917  cache->is_dirty = false;
918  }
919 }
920 
922 {
923  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
924  gpencil_batches_ensure(ob, cache, cfra);
925  gpencil_edit_batches_ensure(ob, cache, cfra);
926 
927  return cache->edit_lines_batch;
928 }
929 
931 {
932  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
933  gpencil_batches_ensure(ob, cache, cfra);
934  gpencil_edit_batches_ensure(ob, cache, cfra);
935 
936  return cache->edit_points_batch;
937 }
938 
940 {
941  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
942  gpencil_batches_ensure(ob, cache, cfra);
943  gpencil_edit_batches_ensure(ob, cache, cfra);
944 
945  return cache->edit_curve_handles_batch;
946 }
947 
949 {
950  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
951  gpencil_batches_ensure(ob, cache, cfra);
952  gpencil_edit_batches_ensure(ob, cache, cfra);
953 
954  return cache->edit_curve_points_batch;
955 }
956 
958 {
959  return max_ii(1, gpd->totcol);
960 }
961 
typedef float(TangentPoint)[2]
support for deformation groups and hooks.
float BKE_defvert_find_weight(const struct MDeformVert *dvert, int defgroup)
Definition: deform.c:704
void BKE_gpencil_visible_stroke_advanced_iter(struct ViewLayer *view_layer, struct Object *ob, gpIterCb layer_cb, gpIterCb stroke_cb, void *thunk, bool do_onion, int cfra)
Definition: gpencil.c:2430
void BKE_gpencil_stroke_uv_update(struct bGPDstroke *gps)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void BLI_polyfill_calc(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3])
Definition: polyfill_2d.c:875
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
float DEG_get_ctime(const Depsgraph *graph)
#define BEZT_ISSEL_ANY(bezt)
@ GP_CURVE_SELECT
@ GP_STROKE_CAP_ROUND
@ GP_STROKE_SELECT
@ GP_STROKE_CYCLIC
@ GP_LAYER_LOCKED
@ GP_DATA_CACHE_IS_DIRTY
@ GP_SPOINT_SELECT
@ OB_GPENCIL
GPUBatch
Definition: GPU_batch.h:78
#define GPU_batch_create(prim, verts, elem)
Definition: GPU_batch.h:95
#define GPU_batch_vertbuf_add(batch, verts)
Definition: GPU_batch.h:124
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition: GPU_batch.h:216
int GPU_batch_instbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo)
Definition: gpu_batch.cc:148
GPUBatch * GPU_batch_create_ex(GPUPrimType prim, GPUVertBuf *vert, GPUIndexBuf *elem, eGPUBatchFlag owns_flag)
Definition: gpu_batch.cc:43
@ GPU_BATCH_OWNS_INDEX
Definition: GPU_batch.h:39
struct GPUIndexBuf GPUIndexBuf
#define GPU_INDEXBUF_DISCARD_SAFE(elem)
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *)
GPUIndexBuf * GPU_indexbuf_build(GPUIndexBufBuilder *)
void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *, uint v)
void GPU_indexbuf_init_ex(GPUIndexBufBuilder *, GPUPrimType, uint index_len, uint vertex_len)
void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3)
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:20
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:19
@ GPU_PRIM_LINE_STRIP
Definition: GPU_primitive.h:22
@ GPU_PRIM_TRI_STRIP
Definition: GPU_primitive.h:24
@ GPU_PRIM_TRIS
Definition: GPU_primitive.h:21
uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts)
#define GPU_vertbuf_create_with_format(format)
struct GPUVertBuf GPUVertBuf
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len)
void * GPU_vertbuf_get_data(const GPUVertBuf *verts)
#define GPU_VERTBUF_DISCARD_SAFE(verts)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count)
@ GPU_COMP_F32
@ GPU_COMP_I32
@ GPU_COMP_U32
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define cosf(x)
Definition: cuda/compat.h:101
#define SELECT
Scene scene
GPUBatch * DRW_gpencil_dummy_buffer_get(void)
Definition: draw_cache.c:776
@ VFLAG_VERT_SELECTED_BEZT_HANDLE
@ VFLAG_VERT_SELECTED
@ VFLAG_VERT_GPENCIL_BEZT_HANDLE
static void gpencil_buffer_add_point(gpStrokeVert *verts, gpColorVert *cols, const bGPDstroke *gps, const bGPDspoint *pt, int v, bool is_endpoint)
struct gpEditCurveVert gpEditCurveVert
void DRW_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
GPUBatch * DRW_cache_gpencil_edit_lines_get(Object *ob, int cfra)
GPUBatch * DRW_cache_gpencil_edit_points_get(Object *ob, int cfra)
static GPUVertFormat * gpencil_edit_stroke_format(void)
GPUBatch * DRW_cache_gpencil_strokes_get(Object *ob, int cfra)
void DRW_gpencil_batch_cache_free(bGPdata *gpd)
struct gpColorVert gpColorVert
static void gpencil_buffer_add_stroke(gpStrokeVert *verts, gpColorVert *cols, const bGPDstroke *gps)
static uint32_t gpencil_point_edit_flag(const bool layer_lock, const bGPDspoint *pt, int v, int v_len)
static void gpencil_object_verts_count_cb(bGPDlayer *UNUSED(gpl), bGPDframe *UNUSED(gpf), bGPDstroke *gps, void *thunk)
static void gpencil_edit_stroke_iter_cb(bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, void *thunk)
GPUBatch * DRW_cache_gpencil_sbuffer_stroke_get(Object *ob)
struct gpEditCurveIterData gpEditCurveIterData
static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
GPUBatch * DRW_cache_gpencil_sbuffer_fill_get(Object *ob)
static uint32_t gpencil_beztriple_vflag_get(char flag, char col_id, bool handle_point, const bool handle_selected)
struct gpIterData gpIterData
static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
static GPUVertFormat * gpencil_stroke_format(void)
BLI_INLINE int32_t pack_rotation_aspect_hardness(float rot, float asp, float hard)
struct gpEditIterData gpEditIterData
struct gpEditVert gpEditVert
static GPUVertBuf * gpencil_dummy_buffer_get(void)
GPUBatch * DRW_cache_gpencil_fills_get(Object *ob, int cfra)
#define COLOR_SHIFT
int DRW_gpencil_material_count_get(bGPdata *gpd)
static GPUVertFormat * gpencil_color_format(void)
static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra)
static GpencilBatchCache * gpencil_batch_cache_get(Object *ob, int cfra)
static void gpencil_edit_curve_stroke_iter_cb(bGPDlayer *gpl, bGPDframe *UNUSED(gpf), bGPDstroke *gps, void *thunk)
void DRW_cache_gpencil_sbuffer_clear(Object *ob)
struct GpencilBatchCache GpencilBatchCache
GPUBatch * DRW_cache_gpencil_edit_curve_points_get(Object *ob, int cfra)
#define GP_EDIT_MULTIFRAME
static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_fill)
#define GP_EDIT_POINT_DIMMED
static void gpencil_lines_indices_cb(bGPDlayer *UNUSED(gpl), bGPDframe *UNUSED(gpf), bGPDstroke *gps, void *thunk)
static GPUVertFormat * gpencil_edit_curve_format(void)
static void gpencil_buffer_add_fill(GPUIndexBufBuilder *ibo, const bGPDstroke *gps)
GPUBatch * DRW_cache_gpencil_face_wireframe_get(Object *ob)
GPUBatch * DRW_cache_gpencil_edit_curve_handles_get(Object *ob, int cfra)
#define GP_EDIT_POINT_SELECTED
static GpencilBatchCache * gpencil_batch_cache_init(Object *ob, int cfra)
#define BEZIER_HANDLE
static void gpencil_edit_curve_stroke_count_cb(bGPDlayer *gpl, bGPDframe *UNUSED(gpf), bGPDstroke *gps, void *thunk)
static void gpencil_stroke_iter_cb(bGPDlayer *UNUSED(gpl), bGPDframe *UNUSED(gpf), bGPDstroke *gps, void *thunk)
static int gpencil_stroke_is_cyclic(const bGPDstroke *gps)
static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra)
#define GP_EDIT_STROKE_SELECTED
#define GP_EDIT_STROKE_END
struct gpStrokeVert gpStrokeVert
#define GP_EDIT_STROKE_START
static float gpencil_point_edit_weight(const MDeformVert *dvert, int v, int vgindex)
bGPDstroke * DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob)
const DRWContextState * DRW_context_state_get(void)
static bool is_cyclic(const Nurb *nu)
#define rot(x, k)
static float verts[][3]
#define GPENCIL_MATERIAL_BUFFER_LEN
void ED_gpencil_tpoint_to_point(ARegion *region, float origin[3], const tGPspoint *tpt, bGPDspoint *pt)
void ED_gpencil_drawing_reference_get(const Scene *scene, const Object *ob, char align_flag, float r_vec[3])
uint col
struct @653::@655 batch
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
unsigned int uint32_t
Definition: stdint.h:80
signed int int32_t
Definition: stdint.h:77
uint8_t h1
uint8_t f3
float vec[3][3]
uint8_t f1
uint8_t f2
uint8_t h2
struct Object * obact
Definition: DRW_render.h:983
struct Scene * scene
Definition: DRW_render.h:979
struct Depsgraph * depsgraph
Definition: DRW_render.h:987
struct ARegion * region
Definition: DRW_render.h:974
float imat[4][4]
void * data
struct ToolSettings * toolsettings
bGPDcurve_point * curve_points
bGPDframe_Runtime runtime
float layer_mat[4][4]
struct bGPDspoint * pt_orig
float uv_fill[2]
bGPDspoint_Runtime runtime
float vert_color[4]
bGPDspoint * points
float fill_opacity_fac
float aspect_ratio[2]
float vert_color_fill[4]
bGPDtriangle * triangles
bGPDstroke_Runtime runtime
struct bGPDcurve * editcurve
struct MDeformVert * dvert
unsigned int verts[3]
struct GpencilBatchCache * gpencil_cache
struct GPUBatch * sbuffer_stroke_batch
struct GPUBatch * sbuffer_fill_batch
struct bGPDstroke * sbuffer_gps
ListBase vertex_group_names
int vertex_group_active_index
bGPdata_Runtime runtime
gpStrokeVert * verts
gpColorVert * cols
GPUIndexBufBuilder ibo
float vert_color[4]
Definition: ED_gpencil.h:97