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