GPencil: Rename property Follow Drawing Path to Alignment
[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 /* create batch geometry data for points stroke shader */
133 void DRW_gpencil_get_point_geom(GpencilBatchCacheElem *be,
134                                 bGPDstroke *gps,
135                                 short thickness,
136                                 const float ink[4],
137                                 const int alignment_mode)
138 {
139   int totvertex = gps->totpoints;
140   if (be->vbo == NULL) {
141     be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
142     be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
143     be->thickness_id = GPU_vertformat_attr_add(
144         &be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
145     be->uvdata_id = GPU_vertformat_attr_add(
146         &be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
147     be->prev_pos_id = GPU_vertformat_attr_add(
148         &be->format, "prev_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
149
150     be->vbo = GPU_vertbuf_create_with_format(&be->format);
151     GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
152     be->vbo_len = 0;
153   }
154   gpencil_vbo_ensure_size(be, totvertex);
155
156   /* draw stroke curve */
157   const bGPDspoint *pt = gps->points;
158   float alpha;
159   float col[4];
160
161   for (int i = 0; i < gps->totpoints; i++, pt++) {
162     /* set point */
163     alpha = ink[3] * pt->strength;
164     CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
165     ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
166
167     float thick = max_ff(pt->pressure * thickness, 1.0f);
168
169     GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, col);
170     GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &thick);
171
172     /* transfer both values using the same shader variable */
173     float uvdata[2] = {pt->uv_fac, pt->uv_rot};
174     GPU_vertbuf_attr_set(be->vbo, be->uvdata_id, be->vbo_len, uvdata);
175
176     GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
177
178     /* use previous point to determine stroke direction */
179     bGPDspoint *pt2 = NULL;
180     float fpt[3];
181     if (alignment_mode != GP_STYLE_FOLLOW_PATH) {
182       /* add small offset to get a vector */
183       copy_v3_v3(fpt, &pt->x);
184       fpt[0] += 0.00001f;
185       fpt[1] += 0.00001f;
186       GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt);
187     }
188     else {
189       if (i == 0) {
190         if (gps->totpoints > 1) {
191           /* extrapolate a point before first point */
192           pt2 = &gps->points[1];
193           interp_v3_v3v3(fpt, &pt2->x, &pt->x, 1.5f);
194           GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt);
195         }
196         else {
197           /* add small offset to get a vector */
198           copy_v3_v3(fpt, &pt->x);
199           fpt[0] += 0.00001f;
200           fpt[1] += 0.00001f;
201           GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt);
202         }
203       }
204       else {
205         pt2 = &gps->points[i - 1];
206         GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, &pt2->x);
207       }
208     }
209     be->vbo_len++;
210   }
211 }
212
213 /* create batch geometry data for stroke shader */
214 void DRW_gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be,
215                                  bGPDstroke *gps,
216                                  short thickness,
217                                  const float ink[4])
218 {
219   bGPDspoint *points = gps->points;
220   int totpoints = gps->totpoints;
221   /* if cyclic needs more vertex */
222   int cyclic_add = (gps->flag & GP_STROKE_CYCLIC) ? 1 : 0;
223   int totvertex = totpoints + cyclic_add + 2;
224
225   if (be->vbo == NULL) {
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     be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
340     be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
341     be->uvdata_id = GPU_vertformat_attr_add(
342         &be->format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
343
344     be->vbo = GPU_vertbuf_create_with_format(&be->format);
345     GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
346     be->vbo_len = 0;
347   }
348   gpencil_vbo_ensure_size(be, totvertex);
349
350   /* Draw all triangles for filling the polygon (cache must be calculated before) */
351   bGPDtriangle *stroke_triangle = gps->triangles;
352   for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
353     for (int j = 0; j < 3; j++) {
354       gpencil_set_fill_point(be->vbo,
355                              be->vbo_len,
356                              &gps->points[stroke_triangle->verts[j]],
357                              color,
358                              stroke_triangle->uv[j],
359                              be->pos_id,
360                              be->color_id,
361                              be->uvdata_id);
362       be->vbo_len++;
363     }
364   }
365 }
366
367 /* create batch geometry data for current buffer stroke shader */
368 GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness)
369 {
370   const DRWContextState *draw_ctx = DRW_context_state_get();
371   Scene *scene = draw_ctx->scene;
372   ARegion *ar = draw_ctx->ar;
373   RegionView3D *rv3d = draw_ctx->rv3d;
374   ToolSettings *ts = scene->toolsettings;
375   Object *ob = draw_ctx->obact;
376
377   tGPspoint *points = gpd->runtime.sbuffer;
378   int totpoints = gpd->runtime.sbuffer_size;
379   /* if cyclic needs more vertex */
380   int cyclic_add = (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC) ? 1 : 0;
381   int totvertex = totpoints + cyclic_add + 2;
382
383   static GPUVertFormat format = {0};
384   static uint pos_id, color_id, thickness_id, uvdata_id;
385   if (format.attr_len == 0) {
386     pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
387     color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
388     thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
389     uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
390   }
391
392   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
393   GPU_vertbuf_data_alloc(vbo, totvertex);
394
395   /* draw stroke curve */
396   const tGPspoint *tpt = points;
397   bGPDspoint pt, pt2, pt3;
398   int idx = 0;
399
400   /* get origin to reproject point */
401   float origin[3];
402   bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
403   ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
404
405   for (int i = 0; i < totpoints; i++, tpt++) {
406     ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
407     ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
408
409     /* first point for adjacency (not drawn) */
410     if (i == 0) {
411       if (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC && totpoints > 2) {
412         ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 1], &pt2);
413         gpencil_set_stroke_point(vbo,
414                                  &pt2,
415                                  idx,
416                                  pos_id,
417                                  color_id,
418                                  thickness_id,
419                                  uvdata_id,
420                                  thickness,
421                                  gpd->runtime.scolor);
422         idx++;
423       }
424       else {
425         ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt2);
426         gpencil_set_stroke_point(vbo,
427                                  &pt2,
428                                  idx,
429                                  pos_id,
430                                  color_id,
431                                  thickness_id,
432                                  uvdata_id,
433                                  thickness,
434                                  gpd->runtime.scolor);
435         idx++;
436       }
437     }
438
439     /* set point */
440     gpencil_set_stroke_point(
441         vbo, &pt, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
442     idx++;
443   }
444
445   /* last adjacency point (not drawn) */
446   if (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC && totpoints > 2) {
447     /* draw line to first point to complete the cycle */
448     ED_gpencil_tpoint_to_point(ar, origin, &points[0], &pt2);
449     gpencil_set_stroke_point(
450         vbo, &pt2, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
451     idx++;
452     /* now add adjacency point (not drawn) */
453     ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt3);
454     gpencil_set_stroke_point(
455         vbo, &pt3, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
456     idx++;
457   }
458   /* last adjacency point (not drawn) */
459   else {
460     ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 2], &pt2);
461     gpencil_set_stroke_point(
462         vbo, &pt2, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
463     idx++;
464   }
465
466   return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO);
467 }
468
469 /* create batch geometry data for current buffer point shader */
470 GPUBatch *DRW_gpencil_get_buffer_point_geom(bGPdata *gpd, short thickness)
471 {
472   const DRWContextState *draw_ctx = DRW_context_state_get();
473   Scene *scene = draw_ctx->scene;
474   ARegion *ar = draw_ctx->ar;
475   RegionView3D *rv3d = draw_ctx->rv3d;
476   ToolSettings *ts = scene->toolsettings;
477   Object *ob = draw_ctx->obact;
478
479   tGPspoint *points = gpd->runtime.sbuffer;
480   int totpoints = gpd->runtime.sbuffer_size;
481
482   static GPUVertFormat format = {0};
483   static uint pos_id, color_id, thickness_id, uvdata_id, prev_pos_id;
484   if (format.attr_len == 0) {
485     pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
486     color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
487     thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
488     uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
489     prev_pos_id = GPU_vertformat_attr_add(&format, "prev_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
490   }
491
492   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
493   GPU_vertbuf_data_alloc(vbo, totpoints);
494
495   /* draw stroke curve */
496   const tGPspoint *tpt = points;
497   bGPDspoint pt;
498   int idx = 0;
499
500   /* get origin to reproject point */
501   float origin[3];
502   bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
503   ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
504
505   for (int i = 0; i < totpoints; i++, tpt++) {
506     ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
507     ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
508
509     /* use previous point to determine stroke direction (drawing path) */
510     bGPDspoint pt2;
511     float ref_pt[3];
512
513     if (i == 0) {
514       if (totpoints > 1) {
515         /* extrapolate a point before first point */
516         tGPspoint *tpt2 = &points[1];
517         ED_gpencil_tpoint_to_point(ar, origin, tpt2, &pt2);
518         ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt2);
519
520         interp_v3_v3v3(ref_pt, &pt2.x, &pt.x, 1.5f);
521       }
522       else {
523         copy_v3_v3(ref_pt, &pt.x);
524       }
525     }
526     else {
527       tGPspoint *tpt2 = &points[i - 1];
528       ED_gpencil_tpoint_to_point(ar, origin, tpt2, &pt2);
529       ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt2);
530
531       copy_v3_v3(ref_pt, &pt2.x);
532     }
533
534     /* set point */
535     gpencil_set_buffer_stroke_point(vbo,
536                                     &pt,
537                                     idx,
538                                     pos_id,
539                                     color_id,
540                                     thickness_id,
541                                     uvdata_id,
542                                     prev_pos_id,
543                                     ref_pt,
544                                     thickness,
545                                     gpd->runtime.scolor);
546     idx++;
547   }
548
549   return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
550 }
551
552 /* create batch geometry data for current buffer control point shader */
553 GPUBatch *DRW_gpencil_get_buffer_ctrlpoint_geom(bGPdata *gpd)
554 {
555   bGPDcontrolpoint *cps = gpd->runtime.cp_points;
556   int totpoints = gpd->runtime.tot_cp_points;
557
558   const DRWContextState *draw_ctx = DRW_context_state_get();
559   Scene *scene = draw_ctx->scene;
560   ToolSettings *ts = scene->toolsettings;
561
562   if (ts->gp_sculpt.guide.use_guide) {
563     totpoints++;
564   }
565
566   static GPUVertFormat format = {0};
567   static uint pos_id, color_id, size_id;
568   if (format.attr_len == 0) {
569     pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
570     size_id = GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
571     color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
572   }
573
574   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
575   GPU_vertbuf_data_alloc(vbo, totpoints);
576
577   int idx = 0;
578   for (int i = 0; i < gpd->runtime.tot_cp_points; i++) {
579     bGPDcontrolpoint *cp = &cps[i];
580
581     GPU_vertbuf_attr_set(vbo, color_id, idx, cp->color);
582
583     /* scale size */
584     float size = cp->size * 0.8f;
585     GPU_vertbuf_attr_set(vbo, size_id, idx, &size);
586
587     GPU_vertbuf_attr_set(vbo, pos_id, idx, &cp->x);
588     idx++;
589   }
590
591   if (ts->gp_sculpt.guide.use_guide) {
592     float size = 10 * 0.8f;
593     float color[4];
594     float position[3];
595     if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_CUSTOM) {
596       UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
597       copy_v3_v3(position, ts->gp_sculpt.guide.location);
598     }
599     else if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_OBJECT &&
600              ts->gp_sculpt.guide.reference_object != NULL) {
601       UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
602       copy_v3_v3(position, ts->gp_sculpt.guide.reference_object->loc);
603     }
604     else {
605       UI_GetThemeColor4fv(TH_REDALERT, color);
606       copy_v3_v3(position, scene->cursor.location);
607     }
608     GPU_vertbuf_attr_set(vbo, pos_id, idx, position);
609     GPU_vertbuf_attr_set(vbo, size_id, idx, &size);
610     GPU_vertbuf_attr_set(vbo, color_id, idx, color);
611   }
612
613   return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
614 }
615
616 /* create batch geometry data for current buffer fill shader */
617 GPUBatch *DRW_gpencil_get_buffer_fill_geom(bGPdata *gpd)
618 {
619   if (gpd == NULL) {
620     return NULL;
621   }
622
623   const tGPspoint *points = gpd->runtime.sbuffer;
624   int totpoints = gpd->runtime.sbuffer_size;
625   if (totpoints < 3) {
626     return NULL;
627   }
628
629   const DRWContextState *draw_ctx = DRW_context_state_get();
630   Scene *scene = draw_ctx->scene;
631   ARegion *ar = draw_ctx->ar;
632   ToolSettings *ts = scene->toolsettings;
633   Object *ob = draw_ctx->obact;
634
635   /* get origin to reproject point */
636   float origin[3];
637   bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
638   ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
639
640   int tot_triangles = totpoints - 2;
641   /* allocate memory for temporary areas */
642   uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, __func__);
643   float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, __func__);
644
645   /* Convert points to array and triangulate
646    * Here a cache is not used because while drawing the information changes all the time, so the
647    * cache would be recalculated constantly, so it is better to do direct calculation for each
648    * function call
649    */
650   for (int i = 0; i < totpoints; i++) {
651     const tGPspoint *pt = &points[i];
652     points2d[i][0] = pt->x;
653     points2d[i][1] = pt->y;
654   }
655   BLI_polyfill_calc(points2d, (uint)totpoints, 0, tmp_triangles);
656
657   static GPUVertFormat format = {0};
658   static uint pos_id, color_id;
659   if (format.attr_len == 0) {
660     pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
661     color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
662   }
663
664   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
665
666   /* draw triangulation data */
667   if (tot_triangles > 0) {
668     GPU_vertbuf_data_alloc(vbo, tot_triangles * 3);
669
670     const tGPspoint *tpt;
671     bGPDspoint pt;
672
673     int idx = 0;
674     for (int i = 0; i < tot_triangles; i++) {
675       for (int j = 0; j < 3; j++) {
676         tpt = &points[tmp_triangles[i][j]];
677         ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
678         GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt.x);
679         GPU_vertbuf_attr_set(vbo, color_id, idx, gpd->runtime.sfill);
680         idx++;
681       }
682     }
683   }
684
685   /* clear memory */
686   if (tmp_triangles) {
687     MEM_freeN(tmp_triangles);
688   }
689   if (points2d) {
690     MEM_freeN(points2d);
691   }
692
693   return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
694 }
695
696 /* Draw selected verts for strokes being edited */
697 void DRW_gpencil_get_edit_geom(struct GpencilBatchCacheElem *be,
698                                bGPDstroke *gps,
699                                float alpha,
700                                short dflag)
701 {
702   const DRWContextState *draw_ctx = DRW_context_state_get();
703   Object *ob = draw_ctx->obact;
704   bGPdata *gpd = ob->data;
705   const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
706
707   int vgindex = ob->actdef - 1;
708   if (!BLI_findlink(&ob->defbase, vgindex)) {
709     vgindex = -1;
710   }
711
712   /* Get size of verts:
713    * - The selected state needs to be larger than the unselected state so that
714    *   they stand out more.
715    * - We use the theme setting for size of the unselected verts
716    */
717   float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
718   float vsize;
719   if ((int)bsize > 8) {
720     vsize = 10.0f;
721     bsize = 8.0f;
722   }
723   else {
724     vsize = bsize + 2;
725   }
726
727   /* for now, we assume that the base color of the points is not too close to the real color */
728   float selectColor[4];
729   UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
730   selectColor[3] = alpha;
731
732   float unselectColor[4];
733   UI_GetThemeColor3fv(TH_GP_VERTEX, unselectColor);
734   unselectColor[3] = alpha;
735
736   if (be->vbo == NULL) {
737     be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
738     be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
739     be->thickness_id = GPU_vertformat_attr_add(
740         &be->format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
741
742     be->vbo = GPU_vertbuf_create_with_format(&be->format);
743     GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
744     be->vbo_len = 0;
745   }
746   gpencil_vbo_ensure_size(be, gps->totpoints);
747
748   /* Draw start and end point differently if enabled stroke direction hint */
749   bool show_direction_hint = (dflag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1);
750
751   /* Draw all the stroke points (selected or not) */
752   bGPDspoint *pt = gps->points;
753   MDeformVert *dvert = gps->dvert;
754
755   float fcolor[4];
756   float fsize = 0;
757   for (int i = 0; i < gps->totpoints; i++, pt++) {
758     /* weight paint */
759     if (is_weight_paint) {
760       float weight = (dvert && dvert->dw && (vgindex > -1)) ? defvert_find_weight(dvert, vgindex) :
761                                                               0.0f;
762       float hue = 2.0f * (1.0f - weight) / 3.0f;
763       hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]);
764       selectColor[3] = 1.0f;
765       copy_v4_v4(fcolor, selectColor);
766       fsize = vsize;
767     }
768     else {
769       if (show_direction_hint && i == 0) {
770         /* start point in green bigger */
771         ARRAY_SET_ITEMS(fcolor, 0.0f, 1.0f, 0.0f, 1.0f);
772         fsize = vsize + 4;
773       }
774       else if (show_direction_hint && (i == gps->totpoints - 1)) {
775         /* end point in red smaller */
776         ARRAY_SET_ITEMS(fcolor, 1.0f, 0.0f, 0.0f, 1.0f);
777         fsize = vsize + 1;
778       }
779       else if (pt->flag & GP_SPOINT_SELECT) {
780         copy_v4_v4(fcolor, selectColor);
781         fsize = vsize;
782       }
783       else {
784         copy_v4_v4(fcolor, unselectColor);
785         fsize = bsize;
786       }
787     }
788
789     GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
790     GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &fsize);
791     GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
792     be->vbo_len++;
793     if (gps->dvert != NULL) {
794       dvert++;
795     }
796   }
797 }
798
799 /* Draw lines for strokes being edited */
800 void DRW_gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be,
801                                 bGPDstroke *gps,
802                                 float alpha,
803                                 short UNUSED(dflag))
804 {
805   const DRWContextState *draw_ctx = DRW_context_state_get();
806   Object *ob = draw_ctx->obact;
807   bGPdata *gpd = ob->data;
808   const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
809
810   int vgindex = ob->actdef - 1;
811   if (!BLI_findlink(&ob->defbase, vgindex)) {
812     vgindex = -1;
813   }
814
815   float selectColor[4];
816   UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
817   selectColor[3] = alpha;
818   float linecolor[4];
819   copy_v4_v4(linecolor, gpd->line_color);
820
821   if (be->vbo == NULL) {
822     be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
823     be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
824
825     be->vbo = GPU_vertbuf_create_with_format(&be->format);
826     GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
827     be->vbo_len = 0;
828   }
829   gpencil_vbo_ensure_size(be, gps->totpoints);
830
831   /* Draw all the stroke lines (selected or not) */
832   bGPDspoint *pt = gps->points;
833   MDeformVert *dvert = gps->dvert;
834
835   float fcolor[4];
836   for (int i = 0; i < gps->totpoints; i++, pt++) {
837     /* weight paint */
838     if (is_weight_paint) {
839       float weight = (dvert && dvert->dw && (vgindex > -1)) ? defvert_find_weight(dvert, vgindex) :
840                                                               0.0f;
841       float hue = 2.0f * (1.0f - weight) / 3.0f;
842       hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]);
843       selectColor[3] = 1.0f;
844       copy_v4_v4(fcolor, selectColor);
845     }
846     else {
847       if (pt->flag & GP_SPOINT_SELECT) {
848         copy_v4_v4(fcolor, selectColor);
849       }
850       else {
851         copy_v4_v4(fcolor, linecolor);
852       }
853     }
854
855     GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
856     GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
857     be->vbo_len++;
858
859     if (gps->dvert != NULL) {
860       dvert++;
861     }
862   }
863 }
864
865 static void set_grid_point(GPUVertBuf *vbo,
866                            int idx,
867                            float col_grid[4],
868                            uint pos_id,
869                            uint color_id,
870                            float v1,
871                            float v2,
872                            const int axis)
873 {
874   GPU_vertbuf_attr_set(vbo, color_id, idx, col_grid);
875
876   float pos[3];
877   /* Set the grid in the selected axis */
878   switch (axis) {
879     case GP_LOCKAXIS_X: {
880       ARRAY_SET_ITEMS(pos, 0.0f, v1, v2);
881       break;
882     }
883     case GP_LOCKAXIS_Y: {
884       ARRAY_SET_ITEMS(pos, v1, 0.0f, v2);
885       break;
886     }
887     case GP_LOCKAXIS_Z:
888     default: /* view aligned */
889     {
890       ARRAY_SET_ITEMS(pos, v1, v2, 0.0f);
891       break;
892     }
893   }
894
895   GPU_vertbuf_attr_set(vbo, pos_id, idx, pos);
896 }
897
898 /* Draw grid lines */
899 GPUBatch *DRW_gpencil_get_grid(Object *ob)
900 {
901   const DRWContextState *draw_ctx = DRW_context_state_get();
902   Scene *scene = draw_ctx->scene;
903   ToolSettings *ts = scene->toolsettings;
904   View3D *v3d = draw_ctx->v3d;
905   bGPdata *gpd = (bGPdata *)ob->data;
906   const bool do_center = (gpd->grid.lines <= 0) ? false : true;
907
908   float col_grid[4];
909
910   /* verify we have something to draw and valid values */
911   if (gpd->grid.scale[0] == 0.0f) {
912     gpd->grid.scale[0] = 1.0f;
913   }
914   if (gpd->grid.scale[1] == 0.0f) {
915     gpd->grid.scale[1] = 1.0f;
916   }
917
918   if (v3d->overlay.gpencil_grid_opacity < 0.1f) {
919     v3d->overlay.gpencil_grid_opacity = 0.1f;
920   }
921
922   /* set color */
923   copy_v3_v3(col_grid, gpd->grid.color);
924   col_grid[3] = v3d->overlay.gpencil_grid_opacity;
925
926   const int axis = ts->gp_sculpt.lock_axis;
927
928   const char *grid_unit = NULL;
929   const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
930   const float grid_w = gpd->grid.scale[0] * ED_scene_grid_scale(scene, &grid_unit);
931   const float grid_h = gpd->grid.scale[1] * ED_scene_grid_scale(scene, &grid_unit);
932   const float space_w = (grid_w / gridlines);
933   const float space_h = (grid_h / gridlines);
934   const float offset[2] = {gpd->grid.offset[0], gpd->grid.offset[1]};
935
936   const uint vertex_len = 2 * (gridlines * 4 + 2);
937
938   static GPUVertFormat format = {0};
939   static uint pos_id, color_id;
940   if (format.attr_len == 0) {
941     pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
942     color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
943   }
944
945   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
946   GPU_vertbuf_data_alloc(vbo, vertex_len);
947
948   int idx = 0;
949
950   for (int a = 1; a <= gridlines; a++) {
951     const float line_w = a * space_w;
952     const float line_h = a * space_h;
953
954     set_grid_point(
955         vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], -line_h + offset[1], axis);
956     idx++;
957     set_grid_point(
958         vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], -line_h + offset[1], axis);
959     idx++;
960     set_grid_point(
961         vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], +line_h + offset[1], axis);
962     idx++;
963     set_grid_point(
964         vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], +line_h + offset[1], axis);
965     idx++;
966
967     set_grid_point(
968         vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], -grid_h + offset[1], axis);
969     idx++;
970     set_grid_point(
971         vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], +grid_h + offset[1], axis);
972     idx++;
973     set_grid_point(
974         vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], -grid_h + offset[1], axis);
975     idx++;
976     set_grid_point(
977         vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], +grid_h + offset[1], axis);
978     idx++;
979   }
980   /* center lines */
981   if (do_center) {
982     set_grid_point(
983         vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], 0.0f + offset[1], axis);
984     idx++;
985     set_grid_point(
986         vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], 0.0f + offset[1], axis);
987     idx++;
988
989     set_grid_point(
990         vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], -grid_h + offset[1], axis);
991     idx++;
992     set_grid_point(
993         vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], +grid_h + offset[1], axis);
994     idx++;
995   }
996   return GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
997 }