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