Merge branch 'master' into greasepencil-object
[blender.git] / source / blender / draw / engines / gpencil / gpencil_draw_cache_impl.c
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) 2008, Blender Foundation
17  * This is a new part of Blender
18  */
19
20 /** \file
21  * \ingroup draw
22  */
23
24 #include "BLI_polyfill_2d.h"
25 #include "BLI_math_color.h"
26
27 #include "DNA_meshdata_types.h"
28 #include "DNA_gpencil_types.h"
29 #include "DNA_screen_types.h"
30 #include "DNA_view3d_types.h"
31
32 #include "BKE_deform.h"
33 #include "BKE_gpencil.h"
34
35 #include "DRW_render.h"
36
37 #include "ED_gpencil.h"
38 #include "ED_view3d.h"
39
40 #include "UI_resources.h"
41
42 #include "gpencil_engine.h"
43
44 /* Helper to add stroke point to vbo */
45 static void gpencil_set_stroke_point(GPUVertBuf *vbo,
46                                      const bGPDspoint *pt,
47                                      int idx,
48                                      uint pos_id,
49                                      uint color_id,
50                                      uint thickness_id,
51                                      uint uvdata_id,
52                                      short thickness,
53                                      const float ink[4])
54 {
55
56   float alpha = ink[3] * pt->strength;
57   CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
58   float col[4];
59   ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
60
61   GPU_vertbuf_attr_set(vbo, color_id, idx, col);
62
63   /* transfer both values using the same shader variable */
64   float uvdata[2] = {pt->uv_fac, pt->uv_rot};
65   GPU_vertbuf_attr_set(vbo, uvdata_id, idx, uvdata);
66
67   /* the thickness of the stroke must be affected by zoom, so a pixel scale is calculated */
68   float thick = max_ff(pt->pressure * thickness, 1.0f);
69   GPU_vertbuf_attr_set(vbo, thickness_id, idx, &thick);
70
71   GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
72 }
73
74 /* Helper to add buffer_stroke point to vbo */
75 static void gpencil_set_buffer_stroke_point(GPUVertBuf *vbo,
76                                             const bGPDspoint *pt,
77                                             int idx,
78                                             uint pos_id,
79                                             uint color_id,
80                                             uint thickness_id,
81                                             uint uvdata_id,
82                                             uint prev_pos_id,
83                                             float ref_pt[3],
84                                             short thickness,
85                                             const float ink[4])
86 {
87
88   float alpha = ink[3] * pt->strength;
89   CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
90   float col[4];
91   ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
92
93   GPU_vertbuf_attr_set(vbo, color_id, idx, col);
94
95   /* transfer both values using the same shader variable */
96   float uvdata[2] = {pt->uv_fac, pt->uv_rot};
97   GPU_vertbuf_attr_set(vbo, uvdata_id, idx, uvdata);
98
99   /* the thickness of the stroke must be affected by zoom, so a pixel scale is calculated */
100   float thick = max_ff(pt->pressure * thickness, 1.0f);
101   GPU_vertbuf_attr_set(vbo, thickness_id, idx, &thick);
102
103   GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
104   /* reference point to follow drawing path */
105   GPU_vertbuf_attr_set(vbo, prev_pos_id, idx, ref_pt);
106 }
107
108 /* Helper to add a new fill point and texture coordinates to vertex buffer */
109 static void gpencil_set_fill_point(GPUVertBuf *vbo,
110                                    int idx,
111                                    bGPDspoint *pt,
112                                    const float fcolor[4],
113                                    float uv[2],
114                                    uint pos_id,
115                                    uint color_id,
116                                    uint text_id)
117 {
118   GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
119   GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor);
120   GPU_vertbuf_attr_set(vbo, text_id, idx, uv);
121 }
122
123 static void gpencil_vbo_ensure_size(GpencilBatchCacheElem *be, int totvertex)
124 {
125   if (be->vbo->vertex_alloc <= be->vbo_len + totvertex) {
126     uint newsize = be->vbo->vertex_alloc +
127                    (((totvertex / GPENCIL_VBO_BLOCK_SIZE) + 1) * GPENCIL_VBO_BLOCK_SIZE);
128     GPU_vertbuf_data_resize(be->vbo, newsize);
129   }
130 }
131
132 static void gpencil_elem_format_ensure(GpencilBatchCacheElem *be)
133 {
134   if (be->format == NULL) {
135     be->format = MEM_callocN(sizeof(GPUVertFormat), __func__);
136   }
137 }
138
139 /* create batch geometry data for points stroke shader */
140 void DRW_gpencil_get_point_geom(GpencilBatchCacheElem *be,
141                                 bGPDstroke *gps,
142                                 short thickness,
143                                 const float ink[4])
144 {
145   int totvertex = gps->totpoints;
146   if (be->vbo == NULL) {
147     gpencil_elem_format_ensure(be);
148     be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
149     be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
150     be->thickness_id = GPU_vertformat_attr_add(
151         be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
152     be->uvdata_id = GPU_vertformat_attr_add(
153         be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
154     be->prev_pos_id = GPU_vertformat_attr_add(
155         be->format, "prev_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
156
157     be->vbo = GPU_vertbuf_create_with_format(be->format);
158     GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
159     be->vbo_len = 0;
160   }
161   gpencil_vbo_ensure_size(be, totvertex);
162
163   /* draw stroke curve */
164   const bGPDspoint *pt = gps->points;
165   float alpha;
166   float col[4];
167
168   for (int i = 0; i < gps->totpoints; i++, pt++) {
169     /* set point */
170     alpha = ink[3] * pt->strength;
171     CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
172     ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
173
174     float thick = max_ff(pt->pressure * thickness, 1.0f);
175
176     GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, col);
177     GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &thick);
178
179     /* transfer both values using the same shader variable */
180     float uvdata[2] = {pt->uv_fac, pt->uv_rot};
181     GPU_vertbuf_attr_set(be->vbo, be->uvdata_id, be->vbo_len, uvdata);
182
183     GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
184
185     /* use previous point to determine stroke direction */
186     bGPDspoint *pt2 = NULL;
187     float fpt[3];
188     if (i == 0) {
189       if (gps->totpoints > 1) {
190         /* extrapolate a point before first point */
191         pt2 = &gps->points[1];
192         interp_v3_v3v3(fpt, &pt2->x, &pt->x, 1.5f);
193         GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt);
194       }
195       else {
196         /* add small offset to get a vector */
197         copy_v3_v3(fpt, &pt->x);
198         fpt[0] += 0.00001f;
199         fpt[1] += 0.00001f;
200         GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt);
201       }
202     }
203     else {
204       pt2 = &gps->points[i - 1];
205       GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, &pt2->x);
206     }
207
208     be->vbo_len++;
209   }
210 }
211
212 /* create batch geometry data for stroke shader */
213 void DRW_gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be,
214                                  bGPDstroke *gps,
215                                  short thickness,
216                                  const float ink[4])
217 {
218   bGPDspoint *points = gps->points;
219   int totpoints = gps->totpoints;
220   /* if cyclic needs more vertex */
221   int cyclic_add = (gps->flag & GP_STROKE_CYCLIC) ? 1 : 0;
222   int totvertex = totpoints + cyclic_add + 2;
223
224   if (be->vbo == NULL) {
225     gpencil_elem_format_ensure(be);
226     be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
227     be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
228     be->thickness_id = GPU_vertformat_attr_add(
229         be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
230     be->uvdata_id = GPU_vertformat_attr_add(
231         be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
232
233     be->vbo = GPU_vertbuf_create_with_format(be->format);
234     GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
235     be->vbo_len = 0;
236   }
237   gpencil_vbo_ensure_size(be, totvertex);
238
239   /* draw stroke curve */
240   const bGPDspoint *pt = points;
241   for (int i = 0; i < totpoints; i++, pt++) {
242     /* first point for adjacency (not drawn) */
243     if (i == 0) {
244       if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
245         gpencil_set_stroke_point(be->vbo,
246                                  &points[totpoints - 1],
247                                  be->vbo_len,
248                                  be->pos_id,
249                                  be->color_id,
250                                  be->thickness_id,
251                                  be->uvdata_id,
252                                  thickness,
253                                  ink);
254         be->vbo_len++;
255       }
256       else {
257         gpencil_set_stroke_point(be->vbo,
258                                  &points[1],
259                                  be->vbo_len,
260                                  be->pos_id,
261                                  be->color_id,
262                                  be->thickness_id,
263                                  be->uvdata_id,
264                                  thickness,
265                                  ink);
266         be->vbo_len++;
267       }
268     }
269     /* set point */
270     gpencil_set_stroke_point(be->vbo,
271                              pt,
272                              be->vbo_len,
273                              be->pos_id,
274                              be->color_id,
275                              be->thickness_id,
276                              be->uvdata_id,
277                              thickness,
278                              ink);
279     be->vbo_len++;
280   }
281
282   if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
283     /* draw line to first point to complete the cycle */
284     gpencil_set_stroke_point(be->vbo,
285                              &points[0],
286                              be->vbo_len,
287                              be->pos_id,
288                              be->color_id,
289                              be->thickness_id,
290                              be->uvdata_id,
291                              thickness,
292                              ink);
293     be->vbo_len++;
294     /* now add adjacency point (not drawn) */
295     gpencil_set_stroke_point(be->vbo,
296                              &points[1],
297                              be->vbo_len,
298                              be->pos_id,
299                              be->color_id,
300                              be->thickness_id,
301                              be->uvdata_id,
302                              thickness,
303                              ink);
304     be->vbo_len++;
305   }
306   /* last adjacency point (not drawn) */
307   else {
308     gpencil_set_stroke_point(be->vbo,
309                              &points[totpoints - 2],
310                              be->vbo_len,
311                              be->pos_id,
312                              be->color_id,
313                              be->thickness_id,
314                              be->uvdata_id,
315                              thickness,
316                              ink);
317     be->vbo_len++;
318   }
319 }
320
321 /* create batch geometry data for stroke shader */
322 void DRW_gpencil_get_fill_geom(struct GpencilBatchCacheElem *be,
323                                Object *ob,
324                                bGPDstroke *gps,
325                                const float color[4])
326 {
327   BLI_assert(gps->totpoints >= 3);
328
329   /* Calculate triangles cache for filling area (must be done only after changes) */
330   if ((gps->flag & GP_STROKE_RECALC_GEOMETRY) || (gps->tot_triangles == 0) ||
331       (gps->triangles == NULL)) {
332     DRW_gpencil_triangulate_stroke_fill(ob, gps);
333   }
334
335   BLI_assert(gps->tot_triangles >= 1);
336   int totvertex = gps->tot_triangles * 3;
337
338   if (be->vbo == NULL) {
339     gpencil_elem_format_ensure(be);
340     be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
341     be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
342     be->uvdata_id = GPU_vertformat_attr_add(
343         be->format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
344
345     be->vbo = GPU_vertbuf_create_with_format(be->format);
346     GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
347     be->vbo_len = 0;
348   }
349   gpencil_vbo_ensure_size(be, totvertex);
350
351   /* Draw all triangles for filling the polygon (cache must be calculated before) */
352   bGPDtriangle *stroke_triangle = gps->triangles;
353   for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
354     for (int j = 0; j < 3; j++) {
355       gpencil_set_fill_point(be->vbo,
356                              be->vbo_len,
357                              &gps->points[stroke_triangle->verts[j]],
358                              color,
359                              stroke_triangle->uv[j],
360                              be->pos_id,
361                              be->color_id,
362                              be->uvdata_id);
363       be->vbo_len++;
364     }
365   }
366 }
367
368 /* create batch geometry data for current buffer stroke shader */
369 GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness)
370 {
371   const DRWContextState *draw_ctx = DRW_context_state_get();
372   Scene *scene = draw_ctx->scene;
373   ARegion *ar = draw_ctx->ar;
374   RegionView3D *rv3d = draw_ctx->rv3d;
375   ToolSettings *ts = scene->toolsettings;
376   Object *ob = draw_ctx->obact;
377
378   tGPspoint *points = gpd->runtime.sbuffer;
379   int totpoints = gpd->runtime.sbuffer_size;
380   /* if cyclic needs more vertex */
381   int cyclic_add = (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC) ? 1 : 0;
382   int totvertex = totpoints + cyclic_add + 2;
383
384   static GPUVertFormat format = {0};
385   static uint pos_id, color_id, thickness_id, uvdata_id;
386   if (format.attr_len == 0) {
387     pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
388     color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
389     thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
390     uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
391   }
392
393   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
394   GPU_vertbuf_data_alloc(vbo, totvertex);
395
396   /* draw stroke curve */
397   const tGPspoint *tpt = points;
398   bGPDspoint pt, pt2, pt3;
399   int idx = 0;
400
401   /* get origin to reproject point */
402   float origin[3];
403   bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
404   ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
405
406   for (int i = 0; i < totpoints; i++, tpt++) {
407     ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
408     ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
409
410     /* first point for adjacency (not drawn) */
411     if (i == 0) {
412       if (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC && totpoints > 2) {
413         ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 1], &pt2);
414         gpencil_set_stroke_point(vbo,
415                                  &pt2,
416                                  idx,
417                                  pos_id,
418                                  color_id,
419                                  thickness_id,
420                                  uvdata_id,
421                                  thickness,
422                                  gpd->runtime.scolor);
423         idx++;
424       }
425       else {
426         ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt2);
427         gpencil_set_stroke_point(vbo,
428                                  &pt2,
429                                  idx,
430                                  pos_id,
431                                  color_id,
432                                  thickness_id,
433                                  uvdata_id,
434                                  thickness,
435                                  gpd->runtime.scolor);
436         idx++;
437       }
438     }
439
440     /* set point */
441     gpencil_set_stroke_point(
442         vbo, &pt, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
443     idx++;
444   }
445
446   /* last adjacency point (not drawn) */
447   if (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC && totpoints > 2) {
448     /* draw line to first point to complete the cycle */
449     ED_gpencil_tpoint_to_point(ar, origin, &points[0], &pt2);
450     gpencil_set_stroke_point(
451         vbo, &pt2, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
452     idx++;
453     /* now add adjacency point (not drawn) */
454     ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt3);
455     gpencil_set_stroke_point(
456         vbo, &pt3, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
457     idx++;
458   }
459   /* last adjacency point (not drawn) */
460   else {
461     ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 2], &pt2);
462     gpencil_set_stroke_point(
463         vbo, &pt2, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
464     idx++;
465   }
466
467   return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO);
468 }
469
470 /* create batch geometry data for current buffer point shader */
471 GPUBatch *DRW_gpencil_get_buffer_point_geom(bGPdata *gpd, short thickness)
472 {
473   const DRWContextState *draw_ctx = DRW_context_state_get();
474   Scene *scene = draw_ctx->scene;
475   ARegion *ar = draw_ctx->ar;
476   RegionView3D *rv3d = draw_ctx->rv3d;
477   ToolSettings *ts = scene->toolsettings;
478   Object *ob = draw_ctx->obact;
479
480   tGPspoint *points = gpd->runtime.sbuffer;
481   int totpoints = gpd->runtime.sbuffer_size;
482
483   static GPUVertFormat format = {0};
484   static uint pos_id, color_id, thickness_id, uvdata_id, prev_pos_id;
485   if (format.attr_len == 0) {
486     pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
487     color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
488     thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
489     uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
490     prev_pos_id = GPU_vertformat_attr_add(&format, "prev_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
491   }
492
493   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
494   GPU_vertbuf_data_alloc(vbo, totpoints);
495
496   /* draw stroke curve */
497   const tGPspoint *tpt = points;
498   bGPDspoint pt;
499   int idx = 0;
500
501   /* get origin to reproject point */
502   float origin[3];
503   bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
504   ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
505
506   for (int i = 0; i < totpoints; i++, tpt++) {
507     ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
508     ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
509
510     /* use previous point to determine stroke direction (drawing path) */
511     bGPDspoint pt2;
512     float ref_pt[3];
513
514     if (i == 0) {
515       if (totpoints > 1) {
516         /* extrapolate a point before first point */
517         tGPspoint *tpt2 = &points[1];
518         ED_gpencil_tpoint_to_point(ar, origin, tpt2, &pt2);
519         ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt2);
520
521         interp_v3_v3v3(ref_pt, &pt2.x, &pt.x, 1.5f);
522       }
523       else {
524         copy_v3_v3(ref_pt, &pt.x);
525       }
526     }
527     else {
528       tGPspoint *tpt2 = &points[i - 1];
529       ED_gpencil_tpoint_to_point(ar, origin, tpt2, &pt2);
530       ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt2);
531
532       copy_v3_v3(ref_pt, &pt2.x);
533     }
534
535     /* set point */
536     gpencil_set_buffer_stroke_point(vbo,
537                                     &pt,
538                                     idx,
539                                     pos_id,
540                                     color_id,
541                                     thickness_id,
542                                     uvdata_id,
543                                     prev_pos_id,
544                                     ref_pt,
545                                     thickness,
546                                     gpd->runtime.scolor);
547     idx++;
548   }
549
550   return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
551 }
552
553 /* create batch geometry data for current buffer control point shader */
554 GPUBatch *DRW_gpencil_get_buffer_ctrlpoint_geom(bGPdata *gpd)
555 {
556   bGPDcontrolpoint *cps = gpd->runtime.cp_points;
557   int totpoints = gpd->runtime.tot_cp_points;
558
559   const DRWContextState *draw_ctx = DRW_context_state_get();
560   Scene *scene = draw_ctx->scene;
561   ToolSettings *ts = scene->toolsettings;
562
563   if (ts->gp_sculpt.guide.use_guide) {
564     totpoints++;
565   }
566
567   static GPUVertFormat format = {0};
568   static uint pos_id, color_id, size_id;
569   if (format.attr_len == 0) {
570     pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
571     size_id = GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
572     color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
573   }
574
575   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
576   GPU_vertbuf_data_alloc(vbo, totpoints);
577
578   int idx = 0;
579   for (int i = 0; i < gpd->runtime.tot_cp_points; i++) {
580     bGPDcontrolpoint *cp = &cps[i];
581
582     GPU_vertbuf_attr_set(vbo, color_id, idx, cp->color);
583
584     /* scale size */
585     float size = cp->size * 0.8f;
586     GPU_vertbuf_attr_set(vbo, size_id, idx, &size);
587
588     GPU_vertbuf_attr_set(vbo, pos_id, idx, &cp->x);
589     idx++;
590   }
591
592   if (ts->gp_sculpt.guide.use_guide) {
593     float size = 10 * 0.8f;
594     float color[4];
595     float position[3];
596     if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_CUSTOM) {
597       UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
598       copy_v3_v3(position, ts->gp_sculpt.guide.location);
599     }
600     else if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_OBJECT &&
601              ts->gp_sculpt.guide.reference_object != NULL) {
602       UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
603       copy_v3_v3(position, ts->gp_sculpt.guide.reference_object->loc);
604     }
605     else {
606       UI_GetThemeColor4fv(TH_REDALERT, color);
607       copy_v3_v3(position, scene->cursor.location);
608     }
609     GPU_vertbuf_attr_set(vbo, pos_id, idx, position);
610     GPU_vertbuf_attr_set(vbo, size_id, idx, &size);
611     GPU_vertbuf_attr_set(vbo, color_id, idx, color);
612   }
613
614   return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
615 }
616
617 /* create batch geometry data for current buffer fill shader */
618 GPUBatch *DRW_gpencil_get_buffer_fill_geom(bGPdata *gpd)
619 {
620   if (gpd == NULL) {
621     return NULL;
622   }
623
624   const tGPspoint *points = gpd->runtime.sbuffer;
625   int totpoints = gpd->runtime.sbuffer_size;
626   if (totpoints < 3) {
627     return NULL;
628   }
629
630   const DRWContextState *draw_ctx = DRW_context_state_get();
631   Scene *scene = draw_ctx->scene;
632   ARegion *ar = draw_ctx->ar;
633   ToolSettings *ts = scene->toolsettings;
634   Object *ob = draw_ctx->obact;
635
636   /* get origin to reproject point */
637   float origin[3];
638   bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
639   ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
640
641   int tot_triangles = totpoints - 2;
642   /* allocate memory for temporary areas */
643   uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, __func__);
644   float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, __func__);
645
646   /* Convert points to array and triangulate
647    * Here a cache is not used because while drawing the information changes all the time, so the
648    * cache would be recalculated constantly, so it is better to do direct calculation for each
649    * function call
650    */
651   for (int i = 0; i < totpoints; i++) {
652     const tGPspoint *pt = &points[i];
653     points2d[i][0] = pt->x;
654     points2d[i][1] = pt->y;
655   }
656   BLI_polyfill_calc(points2d, (uint)totpoints, 0, tmp_triangles);
657
658   static GPUVertFormat format = {0};
659   static uint pos_id, color_id;
660   if (format.attr_len == 0) {
661     pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
662     color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
663   }
664
665   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
666
667   /* draw triangulation data */
668   if (tot_triangles > 0) {
669     GPU_vertbuf_data_alloc(vbo, tot_triangles * 3);
670
671     const tGPspoint *tpt;
672     bGPDspoint pt;
673
674     int idx = 0;
675     for (int i = 0; i < tot_triangles; i++) {
676       for (int j = 0; j < 3; j++) {
677         tpt = &points[tmp_triangles[i][j]];
678         ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
679         GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt.x);
680         GPU_vertbuf_attr_set(vbo, color_id, idx, gpd->runtime.sfill);
681         idx++;
682       }
683     }
684   }
685
686   /* clear memory */
687   if (tmp_triangles) {
688     MEM_freeN(tmp_triangles);
689   }
690   if (points2d) {
691     MEM_freeN(points2d);
692   }
693
694   return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
695 }
696
697 /* Draw selected verts for strokes being edited */
698 void DRW_gpencil_get_edit_geom(struct GpencilBatchCacheElem *be,
699                                bGPDstroke *gps,
700                                float alpha,
701                                short dflag)
702 {
703   const DRWContextState *draw_ctx = DRW_context_state_get();
704   Object *ob = draw_ctx->obact;
705   bGPdata *gpd = ob->data;
706   const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
707
708   int vgindex = ob->actdef - 1;
709   if (!BLI_findlink(&ob->defbase, vgindex)) {
710     vgindex = -1;
711   }
712
713   /* Get size of verts:
714    * - The selected state needs to be larger than the unselected state so that
715    *   they stand out more.
716    * - We use the theme setting for size of the unselected verts
717    */
718   float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
719   float vsize;
720   if ((int)bsize > 8) {
721     vsize = 10.0f;
722     bsize = 8.0f;
723   }
724   else {
725     vsize = bsize + 2;
726   }
727
728   /* for now, we assume that the base color of the points is not too close to the real color */
729   float selectColor[4];
730   UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
731   selectColor[3] = alpha;
732
733   float unselectColor[4];
734   UI_GetThemeColor3fv(TH_GP_VERTEX, unselectColor);
735   unselectColor[3] = alpha;
736
737   float linecolor[4];
738   copy_v4_v4(linecolor, gpd->line_color);
739
740   if (be->vbo == NULL) {
741     gpencil_elem_format_ensure(be);
742     be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
743     be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
744     be->thickness_id = GPU_vertformat_attr_add(
745         be->format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
746
747     be->vbo = GPU_vertbuf_create_with_format(be->format);
748     GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
749     be->vbo_len = 0;
750   }
751   gpencil_vbo_ensure_size(be, gps->totpoints);
752
753   /* Draw start and end point differently if enabled stroke direction hint */
754   bool show_direction_hint = (dflag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1);
755
756   /* Draw all the stroke points (selected or not) */
757   bGPDspoint *pt = gps->points;
758   MDeformVert *dvert = gps->dvert;
759
760   float fcolor[4];
761   float fsize = 0;
762   for (int i = 0; i < gps->totpoints; i++, pt++) {
763     /* weight paint */
764     if (is_weight_paint) {
765       float weight = (dvert && dvert->dw && (vgindex > -1)) ? defvert_find_weight(dvert, vgindex) :
766                                                               0.0f;
767       float hue = 2.0f * (1.0f - weight) / 3.0f;
768       hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]);
769       selectColor[3] = 1.0f;
770       copy_v4_v4(fcolor, selectColor);
771       fsize = vsize;
772     }
773     else {
774       if (show_direction_hint && i == 0) {
775         /* start point in green bigger */
776         ARRAY_SET_ITEMS(fcolor, 0.0f, 1.0f, 0.0f, 1.0f);
777         fsize = vsize + 4;
778       }
779       else if (show_direction_hint && (i == gps->totpoints - 1)) {
780         /* end point in red smaller */
781         ARRAY_SET_ITEMS(fcolor, 1.0f, 0.0f, 0.0f, 1.0f);
782         fsize = vsize + 1;
783       }
784       else if (pt->runtime.pt_orig == NULL) {
785         ARRAY_SET_ITEMS(fcolor, linecolor[0], linecolor[1], linecolor[2], selectColor[3]);
786         mul_v4_fl(fcolor, 0.9f);
787         copy_v4_v4(fcolor, fcolor);
788         fsize = vsize * 0.8f;
789       }
790       else if (pt->flag & GP_SPOINT_SELECT) {
791         copy_v4_v4(fcolor, selectColor);
792         fsize = vsize;
793       }
794       else {
795         copy_v4_v4(fcolor, unselectColor);
796         fsize = bsize;
797       }
798     }
799
800     GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
801     GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &fsize);
802     GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
803     be->vbo_len++;
804     if (gps->dvert != NULL) {
805       dvert++;
806     }
807   }
808 }
809
810 /* Draw lines for strokes being edited */
811 void DRW_gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be,
812                                 bGPDstroke *gps,
813                                 float alpha,
814                                 short UNUSED(dflag))
815 {
816   const DRWContextState *draw_ctx = DRW_context_state_get();
817   Object *ob = draw_ctx->obact;
818   bGPdata *gpd = ob->data;
819   const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
820
821   int vgindex = ob->actdef - 1;
822   if (!BLI_findlink(&ob->defbase, vgindex)) {
823     vgindex = -1;
824   }
825
826   float selectColor[4];
827   UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
828   selectColor[3] = alpha;
829   float linecolor[4];
830   copy_v4_v4(linecolor, gpd->line_color);
831
832   if (be->vbo == NULL) {
833     gpencil_elem_format_ensure(be);
834     be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
835     be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
836
837     be->vbo = GPU_vertbuf_create_with_format(be->format);
838     GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
839     be->vbo_len = 0;
840   }
841   gpencil_vbo_ensure_size(be, gps->totpoints);
842
843   /* Draw all the stroke lines (selected or not) */
844   bGPDspoint *pt = gps->points;
845   MDeformVert *dvert = gps->dvert;
846
847   float fcolor[4];
848   for (int i = 0; i < gps->totpoints; i++, pt++) {
849     /* weight paint */
850     if (is_weight_paint) {
851       float weight = (dvert && dvert->dw && (vgindex > -1)) ? defvert_find_weight(dvert, vgindex) :
852                                                               0.0f;
853       float hue = 2.0f * (1.0f - weight) / 3.0f;
854       hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]);
855       selectColor[3] = 1.0f;
856       copy_v4_v4(fcolor, selectColor);
857     }
858     else {
859       if (pt->flag & GP_SPOINT_SELECT) {
860         copy_v4_v4(fcolor, selectColor);
861       }
862       else {
863         copy_v4_v4(fcolor, linecolor);
864       }
865     }
866
867     GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
868     GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
869     be->vbo_len++;
870
871     if (gps->dvert != NULL) {
872       dvert++;
873     }
874   }
875 }
876
877 static void set_grid_point(GPUVertBuf *vbo,
878                            int idx,
879                            float col_grid[4],
880                            uint pos_id,
881                            uint color_id,
882                            float v1,
883                            float v2,
884                            const int axis)
885 {
886   GPU_vertbuf_attr_set(vbo, color_id, idx, col_grid);
887
888   float pos[3];
889   /* Set the grid in the selected axis */
890   switch (axis) {
891     case GP_LOCKAXIS_X: {
892       ARRAY_SET_ITEMS(pos, 0.0f, v1, v2);
893       break;
894     }
895     case GP_LOCKAXIS_Y: {
896       ARRAY_SET_ITEMS(pos, v1, 0.0f, v2);
897       break;
898     }
899     case GP_LOCKAXIS_Z:
900     default: /* view aligned */
901     {
902       ARRAY_SET_ITEMS(pos, v1, v2, 0.0f);
903       break;
904     }
905   }
906
907   GPU_vertbuf_attr_set(vbo, pos_id, idx, pos);
908 }
909
910 /* Draw grid lines */
911 GPUBatch *DRW_gpencil_get_grid(Object *ob)
912 {
913   const DRWContextState *draw_ctx = DRW_context_state_get();
914   Scene *scene = draw_ctx->scene;
915   ToolSettings *ts = scene->toolsettings;
916   View3D *v3d = draw_ctx->v3d;
917   bGPdata *gpd = (bGPdata *)ob->data;
918   const bool do_center = (gpd->grid.lines <= 0) ? false : true;
919
920   float col_grid[4];
921
922   /* verify we have something to draw and valid values */
923   if (gpd->grid.scale[0] == 0.0f) {
924     gpd->grid.scale[0] = 1.0f;
925   }
926   if (gpd->grid.scale[1] == 0.0f) {
927     gpd->grid.scale[1] = 1.0f;
928   }
929
930   if (v3d->overlay.gpencil_grid_opacity < 0.1f) {
931     v3d->overlay.gpencil_grid_opacity = 0.1f;
932   }
933
934   /* set color */
935   copy_v3_v3(col_grid, gpd->grid.color);
936   col_grid[3] = v3d->overlay.gpencil_grid_opacity;
937
938   const int axis = ts->gp_sculpt.lock_axis;
939
940   const char *grid_unit = NULL;
941   const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
942   const float grid_w = gpd->grid.scale[0] * ED_scene_grid_scale(scene, &grid_unit);
943   const float grid_h = gpd->grid.scale[1] * ED_scene_grid_scale(scene, &grid_unit);
944   const float space_w = (grid_w / gridlines);
945   const float space_h = (grid_h / gridlines);
946   const float offset[2] = {gpd->grid.offset[0], gpd->grid.offset[1]};
947
948   const uint vertex_len = 2 * (gridlines * 4 + 2);
949
950   static GPUVertFormat format = {0};
951   static uint pos_id, color_id;
952   if (format.attr_len == 0) {
953     pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
954     color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
955   }
956
957   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
958   GPU_vertbuf_data_alloc(vbo, vertex_len);
959
960   int idx = 0;
961
962   for (int a = 1; a <= gridlines; a++) {
963     const float line_w = a * space_w;
964     const float line_h = a * space_h;
965
966     set_grid_point(
967         vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], -line_h + offset[1], axis);
968     idx++;
969     set_grid_point(
970         vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], -line_h + offset[1], axis);
971     idx++;
972     set_grid_point(
973         vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], +line_h + offset[1], axis);
974     idx++;
975     set_grid_point(
976         vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], +line_h + offset[1], axis);
977     idx++;
978
979     set_grid_point(
980         vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], -grid_h + offset[1], axis);
981     idx++;
982     set_grid_point(
983         vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], +grid_h + offset[1], axis);
984     idx++;
985     set_grid_point(
986         vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], -grid_h + offset[1], axis);
987     idx++;
988     set_grid_point(
989         vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], +grid_h + offset[1], axis);
990     idx++;
991   }
992   /* center lines */
993   if (do_center) {
994     set_grid_point(
995         vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], 0.0f + offset[1], axis);
996     idx++;
997     set_grid_point(
998         vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], 0.0f + offset[1], axis);
999     idx++;
1000
1001     set_grid_point(
1002         vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], -grid_h + offset[1], axis);
1003     idx++;
1004     set_grid_point(
1005         vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], +grid_h + offset[1], axis);
1006     idx++;
1007   }
1008   return GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
1009 }