Blender  V2.93
draw_cache_impl_gpencil.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2020, Blender Foundation
17  * This is a new part of Blender
18  */
19 
24 #include "DNA_curve_types.h"
25 #include "DNA_gpencil_types.h"
26 #include "DNA_meshdata_types.h"
27 #include "DNA_screen_types.h"
28 
29 #include "BKE_deform.h"
30 #include "BKE_gpencil.h"
31 #include "BKE_gpencil_geom.h"
32 
33 #include "DRW_engine.h"
34 #include "DRW_render.h"
35 
36 #include "ED_gpencil.h"
37 #include "GPU_batch.h"
38 
39 #include "DEG_depsgraph_query.h"
40 
41 #include "BLI_hash.h"
42 #include "BLI_polyfill_2d.h"
43 
44 #include "draw_cache.h"
45 #include "draw_cache_impl.h"
46 
47 #define BEZIER_HANDLE (1 << 3)
48 #define COLOR_SHIFT 5
49 
50 /* ---------------------------------------------------------------------- */
51 typedef struct GpencilBatchCache {
61 
70 
72  bool is_dirty;
76 
77 static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
78 {
79  bool valid = true;
80 
81  if (cache == NULL) {
82  return false;
83  }
84 
85  if (cfra != cache->cache_frame) {
86  valid = false;
87  }
88  else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
89  valid = false;
90  }
91  else if (cache->is_dirty) {
92  valid = false;
93  }
94 
95  return valid;
96 }
97 
99 {
100  bGPdata *gpd = (bGPdata *)ob->data;
101 
103 
104  if (!cache) {
105  cache = gpd->runtime.gpencil_cache = MEM_callocN(sizeof(*cache), __func__);
106  }
107  else {
108  memset(cache, 0, sizeof(*cache));
109  }
110 
111  cache->is_dirty = true;
112  cache->cache_frame = cfra;
113 
114  return cache;
115 }
116 
118 {
119  if (!cache) {
120  return;
121  }
122 
129 
133 
137 
138  cache->is_dirty = true;
139 }
140 
142 {
143  bGPdata *gpd = (bGPdata *)ob->data;
144 
146  if (!gpencil_batch_cache_valid(cache, gpd, cfra)) {
148  return gpencil_batch_cache_init(ob, cfra);
149  }
150 
151  return cache;
152 }
153 
155 {
157 }
158 
160 {
164 }
165 
168 /* -------------------------------------------------------------------- */
172 /* MUST match the format below. */
173 typedef struct gpStrokeVert {
176  float pos[3], thickness;
180 
182 {
183  static GPUVertFormat format = {0};
184  if (format.attr_len == 0) {
188  /* IMPORTANT: This means having only 4 attributes
189  * to fit into GPU module limit of 16 attributes. */
191  }
192  return &format;
193 }
194 
195 /* MUST match the format below. */
196 typedef struct gpEditVert {
198  float weight;
200 
202 {
203  static GPUVertFormat format = {0};
204  if (format.attr_len == 0) {
207  }
208  return &format;
209 }
210 
211 /* MUST match the format below. */
212 typedef struct gpEditCurveVert {
213  float pos[3];
216 
218 {
219  static GPUVertFormat format = {0};
220  if (format.attr_len == 0) {
221  /* initialize vertex formats */
224  }
225  return &format;
226 }
227 
228 /* MUST match the format below. */
229 typedef struct gpColorVert {
230  float vcol[4]; /* Vertex color */
231  float fcol[4]; /* Fill color */
233 
235 {
236  static GPUVertFormat format = {0};
237  if (format.attr_len == 0) {
240  /* IMPORTANT: This means having only 4 attributes
241  * to fit into GPU module limit of 16 attributes. */
243  }
244  return &format;
245 }
246 
249 /* -------------------------------------------------------------------- */
253 typedef struct gpIterData {
258  int vert_len;
259  int tri_len;
262 
264 {
266  return batch->verts[0];
267 }
268 
269 static int gpencil_stroke_is_cyclic(const bGPDstroke *gps)
270 {
271  return ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2);
272 }
273 
275 {
276  int32_t packed = 0;
277  /* Aspect uses 9 bits */
278  float asp_normalized = (asp > 1.0f) ? (1.0f / asp) : asp;
279  packed |= (int32_t)unit_float_to_uchar_clamp(asp_normalized);
280  /* Store if inversed in the 9th bit. */
281  if (asp > 1.0f) {
282  packed |= 1 << 8;
283  }
284  /* Rotation uses 9 bits */
285  /* Rotation are in [-90°..90°] range, so we can encode the sign of the angle + the cosine
286  * because the cosine will always be positive. */
287  packed |= (int32_t)unit_float_to_uchar_clamp(cosf(rot)) << 9;
288  /* Store sine sign in 9th bit. */
289  if (rot < 0.0f) {
290  packed |= 1 << 17;
291  }
292  /* Hardness uses 8 bits */
293  packed |= (int32_t)unit_float_to_uchar_clamp(hard) << 18;
294  return packed;
295 }
296 
298  gpColorVert *cols,
299  const bGPDstroke *gps,
300  const bGPDspoint *pt,
301  int v,
302  bool is_endpoint)
303 {
304  /* Note: we use the sign of strength and thickness to pass cap flag. */
305  const bool round_cap0 = (gps->caps[0] == GP_STROKE_CAP_ROUND);
306  const bool round_cap1 = (gps->caps[1] == GP_STROKE_CAP_ROUND);
307  gpStrokeVert *vert = &verts[v];
308  gpColorVert *col = &cols[v];
309  copy_v3_v3(vert->pos, &pt->x);
310  copy_v2_v2(vert->uv_fill, pt->uv_fill);
311  copy_v4_v4(col->vcol, pt->vert_color);
312  copy_v4_v4(col->fcol, gps->vert_color_fill);
313 
314  /* Encode fill opacity defined by opacity modifier in vertex color alpha. If
315  * no opacity modifier, the value will be always 1.0f. The opacity factor can be any
316  * value between 0.0f and 2.0f */
317  col->fcol[3] = (((int)(col->fcol[3] * 10000.0f)) * 10.0f) + gps->fill_opacity_fac;
318 
319  vert->strength = (round_cap0) ? pt->strength : -pt->strength;
320  vert->u_stroke = pt->uv_fac;
321  vert->stroke_id = gps->runtime.stroke_start;
322  vert->point_id = v;
323  vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0f : -1.0f);
324  /* Tag endpoint material to -1 so they get discarded by vertex shader. */
325  vert->mat = (is_endpoint) ? -1 : (gps->mat_nr % GP_MATERIAL_BUFFER_LEN);
326 
327  float aspect_ratio = gps->aspect_ratio[0] / max_ff(gps->aspect_ratio[1], 1e-8);
328 
330  pt->uv_rot, aspect_ratio, gps->hardeness);
331 }
332 
334  gpColorVert *cols,
335  const bGPDstroke *gps)
336 {
337  const bGPDspoint *pts = gps->points;
338  int pts_len = gps->totpoints;
339  bool is_cyclic = gpencil_stroke_is_cyclic(gps);
340  int v = gps->runtime.stroke_start;
341 
342  /* First point for adjacency (not drawn). */
343  int adj_idx = (is_cyclic) ? (pts_len - 1) : min_ii(pts_len - 1, 1);
344  gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true);
345 
346  for (int i = 0; i < pts_len; i++) {
347  gpencil_buffer_add_point(verts, cols, gps, &pts[i], v++, false);
348  }
349  /* Draw line to first point to complete the loop for cyclic strokes. */
350  if (is_cyclic) {
351  gpencil_buffer_add_point(verts, cols, gps, &pts[0], v++, false);
352  }
353  /* Last adjacency point (not drawn). */
354  adj_idx = (is_cyclic) ? 1 : max_ii(0, pts_len - 2);
355  gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true);
356 }
357 
359 {
360  int tri_len = gps->tot_triangles;
361  int v = gps->runtime.stroke_start;
362  for (int i = 0; i < tri_len; i++) {
363  uint *tri = gps->triangles[i].verts;
364  GPU_indexbuf_add_tri_verts(ibo, v + tri[0], v + tri[1], v + tri[2]);
365  }
366 }
367 
369  bGPDframe *UNUSED(gpf),
370  bGPDstroke *gps,
371  void *thunk)
372 {
373  gpIterData *iter = (gpIterData *)thunk;
374  gpencil_buffer_add_stroke(iter->verts, iter->cols, gps);
375  if (gps->tot_triangles > 0) {
376  gpencil_buffer_add_fill(&iter->ibo, gps);
377  }
378 }
379 
381  bGPDframe *UNUSED(gpf),
382  bGPDstroke *gps,
383  void *thunk)
384 {
385  gpIterData *iter = (gpIterData *)thunk;
386 
387  /* Store first index offset */
388  gps->runtime.stroke_start = iter->vert_len;
389  gps->runtime.fill_start = iter->tri_len;
390  iter->vert_len += gps->totpoints + 2 + gpencil_stroke_is_cyclic(gps);
391  iter->tri_len += gps->tot_triangles;
392 }
393 
394 static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra)
395 {
396  bGPdata *gpd = (bGPdata *)ob->data;
397 
398  if (cache->vbo == NULL) {
399  /* Should be discarded together. */
400  BLI_assert(cache->vbo == NULL && cache->ibo == NULL);
401  BLI_assert(cache->stroke_batch == NULL && cache->stroke_batch == NULL);
402  /* TODO/PERF: Could be changed to only do it if needed.
403  * For now it's simpler to assume we always need it
404  * since multiple viewport could or could not need it.
405  * Ideally we should have a dedicated onion skin geom batch. */
406  /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */
407  bool do_onion = true;
408 
409  /* First count how many vertices and triangles are needed for the whole object. */
410  gpIterData iter = {
411  .gpd = gpd,
412  .verts = NULL,
413  .ibo = {0},
414  .vert_len = 1, /* Start at 1 for the gl_InstanceID trick to work (see vert shader). */
415  .tri_len = 0,
416  .curve_len = 0,
417  };
419  NULL, ob, NULL, gpencil_object_verts_count_cb, &iter, do_onion, cfra);
420 
421  /* Create VBOs. */
423  GPUVertFormat *format_col = gpencil_color_format();
425  cache->vbo_col = GPU_vertbuf_create_with_format(format_col);
426  /* Add extra space at the end of the buffer because of quad load. */
427  GPU_vertbuf_data_alloc(cache->vbo, iter.vert_len + 2);
428  GPU_vertbuf_data_alloc(cache->vbo_col, iter.vert_len + 2);
429  iter.verts = (gpStrokeVert *)GPU_vertbuf_get_data(cache->vbo);
430  iter.cols = (gpColorVert *)GPU_vertbuf_get_data(cache->vbo_col);
431  /* Create IBO. */
432  GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, iter.vert_len);
433 
434  /* Fill buffers with data. */
435  BKE_gpencil_visible_stroke_iter(NULL, ob, NULL, gpencil_stroke_iter_cb, &iter, do_onion, cfra);
436 
437  /* Mark last 2 verts as invalid. */
438  for (int i = 0; i < 2; i++) {
439  iter.verts[iter.vert_len + i].mat = -1;
440  }
441 
442  /* Finish the IBO. */
443  cache->ibo = GPU_indexbuf_build(&iter.ibo);
444 
445  /* Create the batches */
446  cache->fill_batch = GPU_batch_create(GPU_PRIM_TRIS, cache->vbo, cache->ibo);
447  GPU_batch_vertbuf_add(cache->fill_batch, cache->vbo_col);
449  GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo, 0);
450  GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo_col, 0);
451 
452  gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
453  cache->is_dirty = false;
454  }
455 }
456 
458 {
459  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
460  gpencil_batches_ensure(ob, cache, cfra);
461 
462  return cache->stroke_batch;
463 }
464 
466 {
467  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
468  gpencil_batches_ensure(ob, cache, cfra);
469 
470  return cache->fill_batch;
471 }
472 
474  bGPDframe *UNUSED(gpf),
475  bGPDstroke *gps,
476  void *thunk)
477 {
478  gpIterData *iter = (gpIterData *)thunk;
479  int pts_len = gps->totpoints + gpencil_stroke_is_cyclic(gps);
480 
481  int start = gps->runtime.stroke_start + 1;
482  int end = start + pts_len;
483  for (int i = start; i < end; i++) {
485  }
487 }
488 
490 {
491  const DRWContextState *draw_ctx = DRW_context_state_get();
492  int cfra = DEG_get_ctime(draw_ctx->depsgraph);
493 
494  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
495  gpencil_batches_ensure(ob, cache, cfra);
496 
497  if (cache->lines_batch == NULL) {
498  GPUVertBuf *vbo = cache->vbo;
499 
500  gpIterData iter = {
501  .gpd = ob->data,
502  .ibo = {0},
503  };
504 
505  uint vert_len = GPU_vertbuf_get_vertex_len(vbo);
506  GPU_indexbuf_init_ex(&iter.ibo, GPU_PRIM_LINE_STRIP, vert_len, vert_len);
507 
508  /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */
509  bool do_onion = true;
511  NULL, ob, NULL, gpencil_lines_indices_cb, &iter, do_onion, cfra);
512 
513  GPUIndexBuf *ibo = GPU_indexbuf_build(&iter.ibo);
514 
516  }
517  return cache->lines_batch;
518 }
519 
522 /* ---------------------------------------------------------------------- */
527 {
528  bGPdata *gpd = (bGPdata *)ob->data;
529  Brush *brush = gpd->runtime.sbuffer_brush;
530  /* Convert the sbuffer to a bGPDstroke. */
531  if (gpd->runtime.sbuffer_gps == NULL) {
532  bGPDstroke *gps = MEM_callocN(sizeof(*gps), "bGPDstroke sbuffer");
533  gps->totpoints = gpd->runtime.sbuffer_used;
534  gps->mat_nr = max_ii(0, gpd->runtime.matid - 1);
535  gps->flag = gpd->runtime.sbuffer_sflag;
536  gps->thickness = brush->size;
537  gps->hardeness = brush->gpencil_settings->hardeness;
538  copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio);
539 
540  /* Reduce slightly the opacity of fill to make easy fill areas while drawing. */
541  gps->fill_opacity_fac = 0.8f;
542 
543  gps->tot_triangles = max_ii(0, gpd->runtime.sbuffer_used - 2);
544  gps->caps[0] = gps->caps[1] = GP_STROKE_CAP_ROUND;
545  gps->runtime.stroke_start = 1; /* Add one for the adjacency index. */
547  gpd->runtime.sbuffer_gps = gps;
548  }
549  return gpd->runtime.sbuffer_gps;
550 }
551 
552 static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_fill)
553 {
554  tGPspoint *tpoints = gpd->runtime.sbuffer;
555  bGPDstroke *gps = gpd->runtime.sbuffer_gps;
556  int vert_len = gpd->runtime.sbuffer_used;
557 
558  /* DRW_cache_gpencil_sbuffer_stroke_data_get need to have been called previously. */
559  BLI_assert(gps != NULL);
560 
561  if (do_stroke && (gpd->runtime.sbuffer_stroke_batch == NULL)) {
562  gps->points = MEM_mallocN(vert_len * sizeof(*gps->points), __func__);
563 
564  const DRWContextState *draw_ctx = DRW_context_state_get();
565  Scene *scene = draw_ctx->scene;
566  ARegion *region = draw_ctx->region;
567  Object *ob = draw_ctx->obact;
568 
569  BLI_assert(ob && (ob->type == OB_GPENCIL));
570 
571  /* Get origin to reproject points. */
572  float origin[3];
575 
576  for (int i = 0; i < vert_len; i++) {
577  ED_gpencil_tpoint_to_point(region, origin, &tpoints[i], &gps->points[i]);
578  mul_m4_v3(ob->imat, &gps->points[i].x);
579  bGPDspoint *pt = &gps->points[i];
580  copy_v4_v4(pt->vert_color, tpoints[i].vert_color);
581  }
582  /* Calc uv data along the stroke. */
584 
585  /* Create VBO. */
587  GPUVertFormat *format_color = gpencil_color_format();
589  GPUVertBuf *vbo_col = GPU_vertbuf_create_with_format(format_color);
590  /* Add extra space at the end (and start) of the buffer because of quad load and cyclic. */
591  GPU_vertbuf_data_alloc(vbo, 1 + vert_len + 1 + 2);
592  GPU_vertbuf_data_alloc(vbo_col, 1 + vert_len + 1 + 2);
594  gpColorVert *cols = (gpColorVert *)GPU_vertbuf_get_data(vbo_col);
595 
596  /* Fill buffers with data. */
597  gpencil_buffer_add_stroke(verts, cols, gps);
598 
600  GPU_batch_instbuf_add_ex(batch, vbo, true);
601  GPU_batch_instbuf_add_ex(batch, vbo_col, true);
602 
604 
605  MEM_freeN(gps->points);
606  }
607 
608  if (do_fill && (gpd->runtime.sbuffer_fill_batch == NULL)) {
609  /* Create IBO. */
610  GPUIndexBufBuilder ibo_builder;
611  GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, gps->tot_triangles, vert_len);
612 
613  if (gps->tot_triangles > 0) {
614  float(*tpoints2d)[2] = MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__);
615  /* Triangulate in 2D. */
616  for (int i = 0; i < vert_len; i++) {
617  copy_v2_v2(tpoints2d[i], &tpoints[i].x);
618  }
619  /* Compute directly inside the IBO data buffer. */
620  /* OPTI: This is a bottleneck if the stroke is very long. */
621  BLI_polyfill_calc(tpoints2d, (uint)vert_len, 0, (uint(*)[3])ibo_builder.data);
622  /* Add stroke start offset. */
623  for (int i = 0; i < gps->tot_triangles * 3; i++) {
624  ibo_builder.data[i] += gps->runtime.stroke_start;
625  }
626  /* HACK since we didn't use the builder API to avoid another malloc and copy,
627  * we need to set the number of indices manually. */
628  ibo_builder.index_len = gps->tot_triangles * 3;
629 
630  MEM_freeN(tpoints2d);
631  }
632 
633  GPUIndexBuf *ibo = GPU_indexbuf_build(&ibo_builder);
634  GPUVertBuf *vbo = gpd->runtime.sbuffer_stroke_batch->inst[0];
635  GPUVertBuf *vbo_col = gpd->runtime.sbuffer_stroke_batch->inst[1];
636 
638  GPU_batch_vertbuf_add(batch, vbo_col);
639 
641  }
642 }
643 
645 {
646  bGPdata *gpd = (bGPdata *)ob->data;
647  gpencil_sbuffer_stroke_ensure(gpd, true, false);
648 
649  return gpd->runtime.sbuffer_stroke_batch;
650 }
651 
653 {
654  bGPdata *gpd = (bGPdata *)ob->data;
655  /* Fill batch also need stroke batch to be created (vbo is shared). */
656  gpencil_sbuffer_stroke_ensure(gpd, true, true);
657 
658  return gpd->runtime.sbuffer_fill_batch;
659 }
660 
661 /* Sbuffer batches are temporary. We need to clear it after drawing */
663 {
664  bGPdata *gpd = (bGPdata *)ob->data;
668 }
669 
672 /* ---------------------------------------------------------------------- */
673 /* Edit GPencil Batches */
674 
675 #define GP_EDIT_POINT_SELECTED (1 << 0)
676 #define GP_EDIT_STROKE_SELECTED (1 << 1)
677 #define GP_EDIT_MULTIFRAME (1 << 2)
678 #define GP_EDIT_STROKE_START (1 << 3)
679 #define GP_EDIT_STROKE_END (1 << 4)
680 #define GP_EDIT_POINT_DIMMED (1 << 5)
681 
682 typedef struct gpEditIterData {
684  int vgindex;
686 
687 typedef struct gpEditCurveIterData {
689  int vgindex;
691 
692 static uint32_t gpencil_point_edit_flag(const bool layer_lock,
693  const bGPDspoint *pt,
694  int v,
695  int v_len)
696 {
697  uint32_t sflag = 0;
698  SET_FLAG_FROM_TEST(sflag, (!layer_lock) && pt->flag & GP_SPOINT_SELECT, GP_EDIT_POINT_SELECTED);
700  SET_FLAG_FROM_TEST(sflag, v == (v_len - 1), GP_EDIT_STROKE_END);
702  return sflag;
703 }
704 
705 static float gpencil_point_edit_weight(const MDeformVert *dvert, int v, int vgindex)
706 {
707  return (dvert && dvert[v].dw) ? BKE_defvert_find_weight(&dvert[v], vgindex) : -1.0f;
708 }
709 
711  bGPDframe *gpf,
712  bGPDstroke *gps,
713  void *thunk)
714 {
715  gpEditIterData *iter = (gpEditIterData *)thunk;
716  const int v_len = gps->totpoints;
717  const int v = gps->runtime.stroke_start + 1;
718  MDeformVert *dvert = ((iter->vgindex > -1) && gps->dvert) ? gps->dvert : NULL;
719  gpEditVert *vert_ptr = iter->verts + v;
720 
721  const bool layer_lock = (gpl->flag & GP_LAYER_LOCKED);
722  uint32_t sflag = 0;
724  sflag, (!layer_lock) && gps->flag & GP_STROKE_SELECT, GP_EDIT_STROKE_SELECTED);
726 
727  for (int i = 0; i < v_len; i++) {
728  vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[i], i, v_len);
729  vert_ptr->weight = gpencil_point_edit_weight(dvert, i, iter->vgindex);
730  vert_ptr++;
731  }
732  /* Draw line to first point to complete the loop for cyclic strokes. */
733  vert_ptr->vflag = sflag | gpencil_point_edit_flag(layer_lock, &gps->points[0], 0, v_len);
734  vert_ptr->weight = gpencil_point_edit_weight(dvert, 0, iter->vgindex);
735 }
736 
738  bGPDframe *UNUSED(gpf),
739  bGPDstroke *gps,
740  void *thunk)
741 {
742  if (gpl->flag & GP_LAYER_LOCKED) {
743  return;
744  }
745 
746  gpIterData *iter = (gpIterData *)thunk;
747 
748  if (gps->editcurve == NULL) {
749  return;
750  }
751 
752  /* Store first index offset */
753  gps->runtime.curve_start = iter->curve_len;
754  iter->curve_len += gps->editcurve->tot_curve_points * 4;
755 }
756 
758  char col_id,
759  bool handle_point,
760  const bool handle_selected)
761 {
762  uint32_t vflag = 0;
764  SET_FLAG_FROM_TEST(vflag, handle_point, BEZIER_HANDLE);
765  SET_FLAG_FROM_TEST(vflag, handle_selected, VFLAG_VERT_SELECTED_BEZT_HANDLE);
767 
768  /* Handle color id. */
769  vflag |= col_id << COLOR_SHIFT;
770  return vflag;
771 }
772 
774  bGPDframe *UNUSED(gpf),
775  bGPDstroke *gps,
776  void *thunk)
777 {
778  if (gpl->flag & GP_LAYER_LOCKED) {
779  return;
780  }
781 
782  if (gps->editcurve == NULL) {
783  return;
784  }
785  bGPDcurve *editcurve = gps->editcurve;
786  gpEditCurveIterData *iter = (gpEditCurveIterData *)thunk;
787  const int v = gps->runtime.curve_start;
788  gpEditCurveVert *vert_ptr = iter->verts + v;
789  /* Hide points when the curve is unselected. Passing the control point
790  * as handle produces the point shader skip it if you are not in ALL mode. */
791  const bool hide = !(editcurve->flag & GP_CURVE_SELECT);
792 
793  for (int i = 0; i < editcurve->tot_curve_points; i++) {
794  BezTriple *bezt = &editcurve->curve_points[i].bezt;
795  const bool handle_selected = BEZT_ISSEL_ANY(bezt);
796  const uint32_t vflag[3] = {
797  gpencil_beztriple_vflag_get(bezt->f1, bezt->h1, true, handle_selected),
798  gpencil_beztriple_vflag_get(bezt->f2, bezt->h1, hide, handle_selected),
799  gpencil_beztriple_vflag_get(bezt->f3, bezt->h2, true, handle_selected),
800  };
801 
802  /* First segment. */
803  mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[0]);
804  vert_ptr->data = vflag[0];
805  vert_ptr++;
806 
807  mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[1]);
808  vert_ptr->data = vflag[1];
809  vert_ptr++;
810 
811  /* Second segment. */
812  mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[1]);
813  vert_ptr->data = vflag[1];
814  vert_ptr++;
815 
816  mul_v3_m4v3(vert_ptr->pos, gpl->layer_mat, bezt->vec[2]);
817  vert_ptr->data = vflag[2];
818  vert_ptr++;
819  }
820 }
821 
822 static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra)
823 {
824  bGPdata *gpd = (bGPdata *)ob->data;
825 
826  if (cache->edit_vbo == NULL) {
827  /* TODO/PERF: Could be changed to only do it if needed.
828  * For now it's simpler to assume we always need it
829  * since multiple viewport could or could not need it.
830  * Ideally we should have a dedicated onion skin geom batch. */
831  /* IMPORTANT: Keep in sync with gpencil_batches_ensure() */
832  bool do_onion = true;
833 
834  /* Vertex counting has already been done for cache->vbo. */
835  BLI_assert(cache->vbo);
836  int vert_len = GPU_vertbuf_get_vertex_len(cache->vbo);
837 
838  gpEditIterData iter;
839  iter.vgindex = ob->actdef - 1;
840  if (!BLI_findlink(&ob->defbase, iter.vgindex)) {
841  iter.vgindex = -1;
842  }
843 
844  /* Create VBO. */
847  /* Add extra space at the end of the buffer because of quad load. */
848  GPU_vertbuf_data_alloc(cache->edit_vbo, vert_len);
849  iter.verts = (gpEditVert *)GPU_vertbuf_get_data(cache->edit_vbo);
850 
851  /* Fill buffers with data. */
853  NULL, ob, NULL, gpencil_edit_stroke_iter_cb, &iter, do_onion, cfra);
854 
855  /* Create the batches */
858 
861  }
862 
863  /* Curve Handles and Points for Editing. */
864  if (cache->edit_curve_vbo == NULL) {
865  gpIterData iterdata = {
866  .gpd = gpd,
867  .verts = NULL,
868  .ibo = {0},
869  .vert_len = 0,
870  .tri_len = 0,
871  .curve_len = 0,
872  };
873 
874  /* Create VBO. */
877 
878  /* Count data. */
880  NULL, ob, NULL, gpencil_edit_curve_stroke_count_cb, &iterdata, false, cfra);
881 
882  gpEditCurveIterData iter;
883  int vert_len = iterdata.curve_len;
884  if (vert_len > 0) {
885 
886  GPU_vertbuf_data_alloc(cache->edit_curve_vbo, vert_len);
888 
889  /* Fill buffers with data. */
891  NULL, ob, NULL, gpencil_edit_curve_stroke_iter_cb, &iter, false, cfra);
892 
896 
900  }
901 
902  gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
903  cache->is_dirty = false;
904  }
905 }
906 
908 {
909  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
910  gpencil_batches_ensure(ob, cache, cfra);
911  gpencil_edit_batches_ensure(ob, cache, cfra);
912 
913  return cache->edit_lines_batch;
914 }
915 
917 {
918  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
919  gpencil_batches_ensure(ob, cache, cfra);
920  gpencil_edit_batches_ensure(ob, cache, cfra);
921 
922  return cache->edit_points_batch;
923 }
924 
926 {
927  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
928  gpencil_batches_ensure(ob, cache, cfra);
929  gpencil_edit_batches_ensure(ob, cache, cfra);
930 
931  return cache->edit_curve_handles_batch;
932 }
933 
935 {
936  GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra);
937  gpencil_batches_ensure(ob, cache, cfra);
938  gpencil_edit_batches_ensure(ob, cache, cfra);
939 
940  return cache->edit_curve_points_batch;
941 }
942 
typedef float(TangentPoint)[2]
support for deformation groups and hooks.
float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
Definition: deform.c:632
void BKE_gpencil_visible_stroke_iter(struct ViewLayer *view_layer, struct Object *ob, gpIterCb layer_cb, gpIterCb stroke_cb, void *thunk, bool do_onion, int cfra)
Definition: gpencil.c:2637
void BKE_gpencil_stroke_uv_update(struct bGPDstroke *gps)
#define BLI_assert(a)
Definition: BLI_assert.h:58
#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:732
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
MINLINE void copy_v4_v4(float r[4], const float a[4])
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], const unsigned int coords_tot, const int coords_sign, unsigned int(*r_tris)[3])
Definition: polyfill_2d.c:905
unsigned int uint
Definition: BLI_sys_types.h:83
#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
#define GP_MATERIAL_BUFFER_LEN
@ GP_SPOINT_SELECT
@ OB_GPENCIL
GPUBatch
Definition: GPU_batch.h:93
#define GPU_batch_create(prim, verts, elem)
Definition: GPU_batch.h:107
#define GPU_batch_vertbuf_add(batch, verts)
Definition: GPU_batch.h:121
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition: GPU_batch.h:199
int GPU_batch_instbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo)
Definition: gpu_batch.cc:168
GPUBatch * GPU_batch_create_ex(GPUPrimType prim, GPUVertBuf *vert, GPUIndexBuf *elem, eGPUBatchFlag owns_flag)
Definition: gpu_batch.cc:60
@ GPU_BATCH_OWNS_INDEX
Definition: GPU_batch.h:54
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:36
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:35
@ GPU_PRIM_LINE_STRIP
Definition: GPU_primitive.h:38
@ GPU_PRIM_TRI_STRIP
Definition: GPU_primitive.h:40
@ GPU_PRIM_TRIS
Definition: GPU_primitive.h:37
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 SELECT
Scene scene
GPUBatch * DRW_gpencil_dummy_buffer_get(void)
Definition: draw_cache.c:779
@ 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
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)
GPUBatch * batch
Definition: drawnode.c:3779
#define rot(x, k)
static float verts[][3]
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
#define cosf(x)
format
Definition: logImageCore.h:47
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
unsigned int uint32_t
Definition: stdint.h:83
signed int int32_t
Definition: stdint.h:80
float vec[3][3]
struct Object * obact
Definition: DRW_render.h:749
struct Scene * scene
Definition: DRW_render.h:745
struct Depsgraph * depsgraph
Definition: DRW_render.h:753
struct ARegion * region
Definition: DRW_render.h:740
ListBase defbase
float imat[4][4]
unsigned short actdef
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
bGPdata_Runtime runtime
gpStrokeVert * verts
gpColorVert * cols
GPUIndexBufBuilder ibo
float vert_color[4]
Definition: ED_gpencil.h:113