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