GP: Cleanup const variables
[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 static void gpencil_vbo_ensure_size(GpencilBatchCacheElem *be, int totvertex)
91 {
92         if (be->vbo->vertex_alloc <= be->vbo_len + totvertex) {
93                 uint newsize = be->vbo->vertex_alloc + (((totvertex / GPENCIL_VBO_BLOCK_SIZE) + 1) * GPENCIL_VBO_BLOCK_SIZE);
94                 GPU_vertbuf_data_resize(be->vbo, newsize);
95         }
96 }
97
98 /* create batch geometry data for points stroke shader */
99 void DRW_gpencil_get_point_geom(GpencilBatchCacheElem *be, bGPDstroke *gps, short thickness, const float ink[4])
100 {
101         int totvertex = gps->totpoints;
102         if (be->vbo == NULL) {
103                 be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
104                 be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
105                 be->thickness_id = GPU_vertformat_attr_add(&be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
106                 be->uvdata_id = GPU_vertformat_attr_add(&be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
107
108                 be->vbo = GPU_vertbuf_create_with_format(&be->format);
109                 GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
110                 be->vbo_len = 0;
111         }
112         gpencil_vbo_ensure_size(be, totvertex);
113
114         /* draw stroke curve */
115         const bGPDspoint *pt = gps->points;
116         float alpha;
117         float col[4];
118
119         for (int i = 0; i < gps->totpoints; i++, pt++) {
120                 /* set point */
121                 alpha = ink[3] * pt->strength;
122                 CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
123                 ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
124
125                 float thick = max_ff(pt->pressure * thickness, 1.0f);
126
127                 GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, col);
128                 GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &thick);
129
130                 /* transfer both values using the same shader variable */
131                 float uvdata[2] = { pt->uv_fac, pt->uv_rot };
132                 GPU_vertbuf_attr_set(be->vbo, be->uvdata_id, be->vbo_len, uvdata);
133
134                 GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
135                 be->vbo_len++;
136         }
137 }
138
139 /* create batch geometry data for stroke shader */
140 void DRW_gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be, bGPDstroke *gps, short thickness, const float ink[4])
141 {
142         bGPDspoint *points = gps->points;
143         int totpoints = gps->totpoints;
144         /* if cyclic needs more vertex */
145         int cyclic_add = (gps->flag & GP_STROKE_CYCLIC) ? 1 : 0;
146         int totvertex = totpoints + cyclic_add + 2;
147
148         if (be->vbo == NULL) {
149                 be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
150                 be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
151                 be->thickness_id = GPU_vertformat_attr_add(&be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
152                 be->uvdata_id = GPU_vertformat_attr_add(&be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
153
154                 be->vbo = GPU_vertbuf_create_with_format(&be->format);
155                 GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
156                 be->vbo_len = 0;
157         }
158         gpencil_vbo_ensure_size(be, totvertex);
159
160         /* draw stroke curve */
161         const bGPDspoint *pt = points;
162         for (int i = 0; i < totpoints; i++, pt++) {
163                 /* first point for adjacency (not drawn) */
164                 if (i == 0) {
165                         if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
166                                 gpencil_set_stroke_point(
167                                         be->vbo, &points[totpoints - 1], be->vbo_len,
168                                         be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
169                                 be->vbo_len++;
170                         }
171                         else {
172                                 gpencil_set_stroke_point(
173                                         be->vbo, &points[1], be->vbo_len,
174                                         be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
175                                 be->vbo_len++;
176                         }
177                 }
178                 /* set point */
179                 gpencil_set_stroke_point(
180                         be->vbo, pt, be->vbo_len,
181                         be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
182                 be->vbo_len++;
183         }
184
185         if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
186                 /* draw line to first point to complete the cycle */
187                 gpencil_set_stroke_point(
188                         be->vbo, &points[0], be->vbo_len,
189                         be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
190                 be->vbo_len++;
191                 /* now add adjacency point (not drawn) */
192                 gpencil_set_stroke_point(
193                         be->vbo, &points[1], be->vbo_len,
194                         be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
195                 be->vbo_len++;
196         }
197         /* last adjacency point (not drawn) */
198         else {
199                 gpencil_set_stroke_point(
200                         be->vbo, &points[totpoints - 2], be->vbo_len,
201                         be->pos_id, be->color_id, be->thickness_id, be->uvdata_id, thickness, ink);
202                 be->vbo_len++;
203         }
204 }
205
206 /* create batch geometry data for stroke shader */
207 void DRW_gpencil_get_fill_geom(struct GpencilBatchCacheElem *be, Object *ob, bGPDstroke *gps, const float color[4])
208 {
209         BLI_assert(gps->totpoints >= 3);
210
211         /* Calculate triangles cache for filling area (must be done only after changes) */
212         if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) {
213                 DRW_gpencil_triangulate_stroke_fill(ob, gps);
214                 ED_gpencil_calc_stroke_uv(ob, gps);
215         }
216
217         BLI_assert(gps->tot_triangles >= 1);
218         int totvertex = gps->tot_triangles * 3;
219
220         if (be->vbo == NULL) {
221                 be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
222                 be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
223                 be->uvdata_id = GPU_vertformat_attr_add(&be->format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
224
225                 be->vbo = GPU_vertbuf_create_with_format(&be->format);
226                 GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
227                 be->vbo_len = 0;
228         }
229         gpencil_vbo_ensure_size(be, totvertex);
230
231         /* Draw all triangles for filling the polygon (cache must be calculated before) */
232         bGPDtriangle *stroke_triangle = gps->triangles;
233         for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
234                 for (int j = 0; j < 3; j++) {
235                         gpencil_set_fill_point(
236                                 be->vbo, be->vbo_len, &gps->points[stroke_triangle->verts[j]], color, stroke_triangle->uv[j],
237                                 be->pos_id, be->color_id, be->uvdata_id);
238                         be->vbo_len++;
239                 }
240         }
241 }
242
243 /* create batch geometry data for current buffer stroke shader */
244 GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness)
245 {
246         const DRWContextState *draw_ctx = DRW_context_state_get();
247         Scene *scene = draw_ctx->scene;
248         ARegion *ar = draw_ctx->ar;
249         RegionView3D *rv3d = draw_ctx->rv3d;
250         ToolSettings *ts = scene->toolsettings;
251         Object *ob = draw_ctx->obact;
252
253         tGPspoint *points = gpd->runtime.sbuffer;
254         int totpoints = gpd->runtime.sbuffer_size;
255
256         static GPUVertFormat format = { 0 };
257         static uint pos_id, color_id, thickness_id, uvdata_id;
258         if (format.attr_len == 0) {
259                 pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
260                 color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
261                 thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
262                 uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
263         }
264
265         GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
266         GPU_vertbuf_data_alloc(vbo, totpoints + 2);
267
268         /* draw stroke curve */
269         const tGPspoint *tpt = points;
270         bGPDspoint pt, pt2;
271         int idx = 0;
272
273         /* get origin to reproject point */
274         float origin[3];
275         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
276         ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
277
278         for (int i = 0; i < totpoints; i++, tpt++) {
279                 ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
280                 ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
281
282                 /* first point for adjacency (not drawn) */
283                 if (i == 0) {
284                         if (totpoints > 1) {
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                         }
290                         else {
291                                 gpencil_set_stroke_point(
292                                         vbo, &pt, idx,
293                                         pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
294                         }
295                         idx++;
296                 }
297                 /* set point */
298                 gpencil_set_stroke_point(
299                         vbo, &pt, idx,
300                         pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
301                 idx++;
302         }
303
304         /* last adjacency point (not drawn) */
305         if (totpoints > 2) {
306                 ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 2], &pt2);
307                 gpencil_set_stroke_point(
308                         vbo, &pt2, idx,
309                         pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
310         }
311         else {
312                 gpencil_set_stroke_point(
313                         vbo, &pt, idx,
314                         pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
315         }
316
317         return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO);
318 }
319
320 /* create batch geometry data for current buffer point shader */
321 GPUBatch *DRW_gpencil_get_buffer_point_geom(bGPdata *gpd, short thickness)
322 {
323         const DRWContextState *draw_ctx = DRW_context_state_get();
324         Scene *scene = draw_ctx->scene;
325         ARegion *ar = draw_ctx->ar;
326         RegionView3D *rv3d = draw_ctx->rv3d;
327         ToolSettings *ts = scene->toolsettings;
328         Object *ob = draw_ctx->obact;
329
330         tGPspoint *points = gpd->runtime.sbuffer;
331         int totpoints = gpd->runtime.sbuffer_size;
332
333         static GPUVertFormat format = { 0 };
334         static uint pos_id, color_id, thickness_id, uvdata_id;
335         if (format.attr_len == 0) {
336                 pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
337                 color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
338                 thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
339                 uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
340         }
341
342         GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
343         GPU_vertbuf_data_alloc(vbo, totpoints);
344
345         /* draw stroke curve */
346         const tGPspoint *tpt = points;
347         bGPDspoint pt;
348         int idx = 0;
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(scene, ob, gpl, ts->gpencil_v3d_align, origin);
354
355         for (int i = 0; i < totpoints; i++, tpt++) {
356                 ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
357                 ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
358
359                 /* set point */
360                 gpencil_set_stroke_point(
361                         vbo, &pt, idx,
362                         pos_id, color_id, thickness_id, uvdata_id,
363                         thickness, gpd->runtime.scolor);
364                 idx++;
365         }
366
367         return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
368 }
369
370 /* create batch geometry data for current buffer fill shader */
371 GPUBatch *DRW_gpencil_get_buffer_fill_geom(bGPdata *gpd)
372 {
373         if (gpd == NULL) {
374                 return NULL;
375         }
376
377         const tGPspoint *points = gpd->runtime.sbuffer;
378         int totpoints = gpd->runtime.sbuffer_size;
379         if (totpoints < 3) {
380                 return NULL;
381         }
382
383         const DRWContextState *draw_ctx = DRW_context_state_get();
384         Scene *scene = draw_ctx->scene;
385         ARegion *ar = draw_ctx->ar;
386         ToolSettings *ts = scene->toolsettings;
387         Object *ob = draw_ctx->obact;
388
389         /* get origin to reproject point */
390         float origin[3];
391         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
392         ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
393
394         int tot_triangles = totpoints - 2;
395         /* allocate memory for temporary areas */
396         uint (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, __func__);
397         float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, __func__);
398
399         /* Convert points to array and triangulate
400          * Here a cache is not used because while drawing the information changes all the time, so the cache
401          * would be recalculated constantly, so it is better to do direct calculation for each function call
402          */
403         for (int i = 0; i < totpoints; i++) {
404                 const tGPspoint *pt = &points[i];
405                 points2d[i][0] = pt->x;
406                 points2d[i][1] = pt->y;
407         }
408         BLI_polyfill_calc(points2d, (uint)totpoints, 0, tmp_triangles);
409
410         static GPUVertFormat format = { 0 };
411         static uint pos_id, color_id;
412         if (format.attr_len == 0) {
413                 pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
414                 color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
415         }
416
417         GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
418
419         /* draw triangulation data */
420         if (tot_triangles > 0) {
421                 GPU_vertbuf_data_alloc(vbo, tot_triangles * 3);
422
423                 const tGPspoint *tpt;
424                 bGPDspoint pt;
425
426                 int idx = 0;
427                 for (int i = 0; i < tot_triangles; i++) {
428                         for (int j = 0; j < 3; j++) {
429                                 tpt = &points[tmp_triangles[i][j]];
430                                 ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt);
431                                 GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt.x);
432                                 GPU_vertbuf_attr_set(vbo, color_id, idx, gpd->runtime.sfill);
433                                 idx++;
434                         }
435                 }
436         }
437
438         /* clear memory */
439         if (tmp_triangles) {
440                 MEM_freeN(tmp_triangles);
441         }
442         if (points2d) {
443                 MEM_freeN(points2d);
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 void DRW_gpencil_get_edit_geom(struct GpencilBatchCacheElem *be, 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         const 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         if (be->vbo == NULL) {
487                 be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
488                 be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
489                 be->thickness_id = GPU_vertformat_attr_add(&be->format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
490
491                 be->vbo = GPU_vertbuf_create_with_format(&be->format);
492                 GPU_vertbuf_data_alloc(be->vbo, gps->totpoints);
493                 be->vbo_len = 0;
494         }
495         gpencil_vbo_ensure_size(be, 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         float fcolor[4];
505         float fsize = 0;
506         for (int i = 0; i < gps->totpoints; i++, pt++) {
507                 /* weight paint */
508                 if (is_weight_paint) {
509                         float weight = (dvert && dvert->dw) ? defvert_find_weight(dvert, vgindex) : 0.0f;
510                         float hue = 2.0f * (1.0f - weight) / 3.0f;
511                         hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]);
512                         selectColor[3] = 1.0f;
513                         copy_v4_v4(fcolor, selectColor);
514                         fsize = vsize;
515                 }
516                 else {
517                         if (show_direction_hint && i == 0) {
518                                 /* start point in green bigger */
519                                 ARRAY_SET_ITEMS(fcolor, 0.0f, 1.0f, 0.0f, 1.0f);
520                                 fsize = vsize + 4;
521                         }
522                         else if (show_direction_hint && (i == gps->totpoints - 1)) {
523                                 /* end point in red smaller */
524                                 ARRAY_SET_ITEMS(fcolor, 1.0f, 0.0f, 0.0f, 1.0f);
525                                 fsize = vsize + 1;
526                         }
527                         else if (pt->flag & GP_SPOINT_SELECT) {
528                                 copy_v4_v4(fcolor, selectColor);
529                                 fsize = vsize;
530                         }
531                         else {
532                                 copy_v4_v4(fcolor, unselectColor);
533                                 fsize = bsize;
534                         }
535                 }
536
537                 GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
538                 GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &fsize);
539                 GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
540                 be->vbo_len++;
541                 if (gps->dvert != NULL) {
542                         dvert++;
543                 }
544         }
545 }
546
547 /* Draw lines for strokes being edited */
548 void DRW_gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be, bGPDstroke *gps, float alpha, short UNUSED(dflag))
549 {
550         const DRWContextState *draw_ctx = DRW_context_state_get();
551         Object *ob = draw_ctx->obact;
552         bGPdata *gpd = ob->data;
553         const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
554
555         int vgindex = ob->actdef - 1;
556         if (!BLI_findlink(&ob->defbase, vgindex)) {
557                 vgindex = -1;
558         }
559
560         float selectColor[4];
561         UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
562         selectColor[3] = alpha;
563         float linecolor[4];
564         copy_v4_v4(linecolor, gpd->line_color);
565
566         if (be->vbo == NULL) {
567                 be->pos_id = GPU_vertformat_attr_add(&be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
568                 be->color_id = GPU_vertformat_attr_add(&be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
569
570                 be->vbo = GPU_vertbuf_create_with_format(&be->format);
571                 GPU_vertbuf_data_alloc(be->vbo, gps->totpoints);
572                 be->vbo_len = 0;
573         }
574         gpencil_vbo_ensure_size(be, gps->totpoints);
575
576         /* Draw all the stroke lines (selected or not) */
577         bGPDspoint *pt = gps->points;
578         MDeformVert *dvert = gps->dvert;
579
580         float fcolor[4];
581         for (int i = 0; i < gps->totpoints; i++, pt++) {
582                 /* weight paint */
583                 if (is_weight_paint) {
584                         float weight = (dvert && dvert->dw) ? defvert_find_weight(dvert, vgindex) : 0.0f;
585                         float hue = 2.0f * (1.0f - weight) / 3.0f;
586                         hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]);
587                         selectColor[3] = 1.0f;
588                         copy_v4_v4(fcolor, selectColor);
589                 }
590                 else {
591                         if (pt->flag & GP_SPOINT_SELECT) {
592                                 copy_v4_v4(fcolor, selectColor);
593                         }
594                         else {
595                                 copy_v4_v4(fcolor, linecolor);
596                         }
597                 }
598
599                 GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
600                 GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
601                 be->vbo_len++;
602
603                 if (gps->dvert != NULL) {
604                         dvert++;
605                 }
606         }
607 }
608
609 static void set_grid_point(
610         GPUVertBuf *vbo, int idx, float col_grid[4],
611         uint pos_id, uint color_id,
612         float v1, float v2, const int axis)
613 {
614         GPU_vertbuf_attr_set(vbo, color_id, idx, col_grid);
615
616         float pos[3];
617         /* Set the grid in the selected axis */
618         switch (axis) {
619                 case GP_LOCKAXIS_X:
620                 {
621                         ARRAY_SET_ITEMS(pos, 0.0f, v1, v2);
622                         break;
623                 }
624                 case GP_LOCKAXIS_Y:
625                 {
626                         ARRAY_SET_ITEMS(pos, v1, 0.0f, v2);
627                         break;
628                 }
629                 case GP_LOCKAXIS_Z:
630                 default:  /* view aligned */
631                 {
632                         ARRAY_SET_ITEMS(pos, v1, v2, 0.0f);
633                         break;
634                 }
635         }
636
637         GPU_vertbuf_attr_set(vbo, pos_id, idx, pos);
638 }
639
640 /* Draw grid lines */
641 GPUBatch *DRW_gpencil_get_grid(Object *ob)
642 {
643         const DRWContextState *draw_ctx = DRW_context_state_get();
644         Scene *scene = draw_ctx->scene;
645         ToolSettings *ts = scene->toolsettings;
646         View3D *v3d = draw_ctx->v3d;
647         bGPdata *gpd = (bGPdata *)ob->data;
648         const bool do_center = (gpd->grid.lines <= 0) ? false : true;
649
650         float col_grid[4];
651
652         /* verify we have something to draw and valid values */
653         if (gpd->grid.scale[0] == 0.0f) {
654                 gpd->grid.scale[0] = 1.0f;
655         }
656         if (gpd->grid.scale[1] == 0.0f) {
657                 gpd->grid.scale[1] = 1.0f;
658         }
659
660         if (v3d->overlay.gpencil_grid_opacity < 0.1f) {
661                 v3d->overlay.gpencil_grid_opacity = 0.1f;
662         }
663
664         /* set color */
665         copy_v3_v3(col_grid, gpd->grid.color);
666         col_grid[3] = v3d->overlay.gpencil_grid_opacity;
667
668         const int axis = ts->gp_sculpt.lock_axis;
669
670         const char *grid_unit = NULL;
671         const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
672         const float grid_w = gpd->grid.scale[0] * ED_scene_grid_scale(scene, &grid_unit);
673         const float grid_h = gpd->grid.scale[1] * ED_scene_grid_scale(scene, &grid_unit);
674         const float space_w = (grid_w / gridlines);
675         const float space_h = (grid_h / gridlines);
676         const float offset[2] = { gpd->grid.offset[0], gpd->grid.offset[1] };
677
678         const uint vertex_len = 2 * (gridlines * 4 + 2);
679
680         static GPUVertFormat format = { 0 };
681         static uint pos_id, color_id;
682         if (format.attr_len == 0) {
683                 pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
684                 color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
685         }
686
687         GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
688         GPU_vertbuf_data_alloc(vbo, vertex_len);
689
690         int idx = 0;
691
692         for (int a = 1; a <= gridlines; a++) {
693                 const float line_w = a * space_w;
694                 const float line_h = a * space_h;
695
696                 set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], -line_h + offset[1], axis);
697                 idx++;
698                 set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], -line_h + offset[1], axis);
699                 idx++;
700                 set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], +line_h + offset[1], axis);
701                 idx++;
702                 set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], +line_h + offset[1], axis);
703                 idx++;
704
705                 set_grid_point(vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], -grid_h + offset[1], axis);
706                 idx++;
707                 set_grid_point(vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], +grid_h + offset[1], axis);
708                 idx++;
709                 set_grid_point(vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], -grid_h + offset[1], axis);
710                 idx++;
711                 set_grid_point(vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], +grid_h + offset[1], axis);
712                 idx++;
713         }
714         /* center lines */
715         if (do_center) {
716                 set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], 0.0f + offset[1], axis);
717                 idx++;
718                 set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], 0.0f + offset[1], axis);
719                 idx++;
720
721                 set_grid_point(vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], -grid_h + offset[1], axis);
722                 idx++;
723                 set_grid_point(vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], +grid_h + offset[1], axis);
724                 idx++;
725         }
726         return GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
727 }