Edit Mesh: Add support for draw option parameters
[blender.git] / source / blender / draw / intern / draw_cache_impl_curve.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) 2017 by Blender Foundation.
19  * All rights reserved.
20  *
21  * ***** END GPL LICENSE BLOCK *****
22  */
23
24 /** \file draw_cache_impl_curve.c
25  *  \ingroup draw
26  *
27  * \brief Curve API for render engines
28  */
29
30 #include "MEM_guardedalloc.h"
31
32 #include "BLI_utildefines.h"
33 #include "BLI_math_vector.h"
34
35 #include "DNA_curve_types.h"
36
37 #include "BKE_curve.h"
38
39 #include "BKE_font.h"
40
41 #include "GPU_batch.h"
42
43 #include "UI_resources.h"
44
45 #include "draw_cache_impl.h"  /* own include */
46
47 #define SELECT            1
48 #define ACTIVE_NURB       1 << 7 /* last char bite */
49 #define HANDLE_SEL_OFFSET (TH_HANDLE_SEL_FREE - TH_HANDLE_FREE)
50
51 /* Used as values of `color_id` in `edit_curve_overlay_handle_geom.glsl` */
52 enum {
53         COLOR_NURB_ULINE_ID = TH_HANDLE_SEL_AUTOCLAMP - TH_HANDLE_FREE + 1,
54         COLOR_NURB_SEL_ULINE_ID,
55         COLOR_ACTIVE_SPLINE,
56
57         TOT_HANDLE_COL,
58 };
59
60 /**
61  * TODO
62  * - Ensure `CurveCache`, `SEQUENCER_DAG_WORKAROUND`.
63  * - Check number of verts/edges to see if cache is valid.
64  * - Check if 'overlay.edges' can use single attribute per edge, not 2 (for selection drawing).
65  */
66
67 static void curve_batch_cache_clear(Curve *cu);
68
69 /* ---------------------------------------------------------------------- */
70 /* Curve Interface, direct access to basic data. */
71
72 static void curve_render_overlay_verts_edges_len_get(
73         ListBase *lb, bool hide_handles,
74         int *r_vert_len, int *r_edge_len)
75 {
76         BLI_assert(r_vert_len || r_edge_len);
77         int vert_len = 0;
78         int edge_len = 0;
79         for (Nurb *nu = lb->first; nu; nu = nu->next) {
80                 if (nu->bezt) {
81                         vert_len += hide_handles ? nu->pntsu : (nu->pntsu * 3);
82                         /* 2x handles per point*/
83                         edge_len += 2 * nu->pntsu;
84                 }
85                 else if (nu->bp) {
86                         vert_len += nu->pntsu;
87                         /* segments between points */
88                         edge_len += nu->pntsu - 1;
89                 }
90         }
91         if (r_vert_len) {
92                 *r_vert_len = vert_len;
93         }
94         if (r_edge_len) {
95                 *r_edge_len = edge_len;
96         }
97 }
98
99 static void curve_render_wire_verts_edges_len_get(
100         const CurveCache *ob_curve_cache,
101         int *r_vert_len, int *r_edge_len)
102 {
103         BLI_assert(r_vert_len || r_edge_len);
104         int vert_len = 0;
105         int edge_len = 0;
106         for (const BevList *bl = ob_curve_cache->bev.first; bl; bl = bl->next) {
107                 if (bl->nr > 0) {
108                         const bool is_cyclic = bl->poly != -1;
109
110                         /* verts */
111                         vert_len += bl->nr;
112
113                         /* edges */
114                         edge_len += bl->nr;
115                         if (!is_cyclic) {
116                                 edge_len -= 1;
117                         }
118                 }
119         }
120         if (r_vert_len) {
121                 *r_vert_len = vert_len;
122         }
123         if (r_edge_len) {
124                 *r_edge_len = edge_len;
125         }
126 }
127
128 static int curve_render_normal_len_get(const ListBase *lb, const CurveCache *ob_curve_cache)
129 {
130         int normal_len = 0;
131         const BevList *bl;
132         const Nurb *nu;
133         for (bl = ob_curve_cache->bev.first, nu = lb->first; nu && bl; bl = bl->next, nu = nu->next) {
134                 int nr = bl->nr;
135                 int skip = nu->resolu / 16;
136 #if 0
137                 while (nr-- > 0) { /* accounts for empty bevel lists */
138                         normal_len += 1;
139                         nr -= skip;
140                 }
141 #else
142                 /* Same as loop above */
143                 normal_len += (nr / (skip + 1)) + ((nr % (skip + 1)) != 0);
144 #endif
145         }
146         return normal_len;
147 }
148
149 /* ---------------------------------------------------------------------- */
150 /* Curve Interface, indirect, partially cached access to complex data. */
151
152 typedef struct CurveRenderData {
153         int types;
154
155         struct {
156                 int vert_len;
157                 int edge_len;
158         } overlay;
159
160         struct {
161                 int vert_len;
162                 int edge_len;
163         } wire;
164
165         /* edit mode normal's */
166         struct {
167                 /* 'edge_len == len * 2'
168                  * 'vert_len == len * 3' */
169                 int len;
170         } normal;
171
172         struct {
173                 EditFont *edit_font;
174         } text;
175
176         bool hide_handles;
177         bool hide_normals;
178
179         /* borrow from 'Object' */
180         CurveCache *ob_curve_cache;
181
182         /* borrow from 'Curve' */
183         ListBase *nurbs;
184
185         /* edit, index in nurb list */
186         int actnu;
187         /* edit, index in active nurb (BPoint or BezTriple) */
188         int actvert;
189 } CurveRenderData;
190
191 enum {
192         /* Wire center-line */
193         CU_DATATYPE_WIRE        = 1 << 0,
194         /* Edit-mode verts and optionally handles */
195         CU_DATATYPE_OVERLAY     = 1 << 1,
196         /* Edit-mode normals */
197         CU_DATATYPE_NORMAL      = 1 << 2,
198         /* Geometry */
199         CU_DATATYPE_SURFACE     = 1 << 3,
200         /* Text */
201         CU_DATATYPE_TEXT_SELECT = 1 << 4,
202 };
203
204 /*
205  * ob_curve_cache can be NULL, only needed for CU_DATATYPE_WIRE
206  */
207 static CurveRenderData *curve_render_data_create(Curve *cu, CurveCache *ob_curve_cache, const int types)
208 {
209         CurveRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__);
210         rdata->types = types;
211         ListBase *nurbs;
212
213         rdata->hide_handles = (cu->drawflag & CU_HIDE_HANDLES) != 0;
214         rdata->hide_normals = (cu->drawflag & CU_HIDE_NORMALS) != 0;
215
216         rdata->actnu = cu->actnu;
217         rdata->actvert = cu->actvert;
218
219         rdata->ob_curve_cache = ob_curve_cache;
220
221         if (types & CU_DATATYPE_WIRE) {
222                 curve_render_wire_verts_edges_len_get(
223                         rdata->ob_curve_cache,
224                         &rdata->wire.vert_len, &rdata->wire.edge_len);
225         }
226
227         if (cu->editnurb) {
228                 EditNurb *editnurb = cu->editnurb;
229                 nurbs = &editnurb->nurbs;
230
231                 if (types & CU_DATATYPE_OVERLAY) {
232                         curve_render_overlay_verts_edges_len_get(
233                                 nurbs, rdata->hide_handles,
234                                 &rdata->overlay.vert_len,
235                                 rdata->hide_handles ? NULL : &rdata->overlay.edge_len);
236
237                         rdata->actnu = cu->actnu;
238                         rdata->actvert = cu->actvert;
239                 }
240                 if (types & CU_DATATYPE_NORMAL) {
241                         rdata->normal.len = curve_render_normal_len_get(nurbs, rdata->ob_curve_cache);
242                 }
243         }
244         else {
245                 nurbs = &cu->nurb;
246         }
247
248         rdata->nurbs = nurbs;
249
250         rdata->text.edit_font = cu->editfont;
251
252         return rdata;
253 }
254
255 static void curve_render_data_free(CurveRenderData *rdata)
256 {
257 #if 0
258         if (rdata->loose_verts) {
259                 MEM_freeN(rdata->loose_verts);
260         }
261 #endif
262         MEM_freeN(rdata);
263 }
264
265 static int curve_render_data_overlay_verts_len_get(const CurveRenderData *rdata)
266 {
267         BLI_assert(rdata->types & CU_DATATYPE_OVERLAY);
268         return rdata->overlay.vert_len;
269 }
270
271 static int curve_render_data_overlay_edges_len_get(const CurveRenderData *rdata)
272 {
273         BLI_assert(rdata->types & CU_DATATYPE_OVERLAY);
274         return rdata->overlay.edge_len;
275 }
276
277 static int curve_render_data_wire_verts_len_get(const CurveRenderData *rdata)
278 {
279         BLI_assert(rdata->types & CU_DATATYPE_WIRE);
280         return rdata->wire.vert_len;
281 }
282
283 static int curve_render_data_wire_edges_len_get(const CurveRenderData *rdata)
284 {
285         BLI_assert(rdata->types & CU_DATATYPE_WIRE);
286         return rdata->wire.edge_len;
287 }
288
289 static int curve_render_data_normal_len_get(const CurveRenderData *rdata)
290 {
291         BLI_assert(rdata->types & CU_DATATYPE_NORMAL);
292         return rdata->normal.len;
293 }
294
295
296 /* ---------------------------------------------------------------------- */
297 /* Curve GPUBatch Cache */
298
299 typedef struct CurveBatchCache {
300         /* center-line */
301         struct {
302                 GPUVertBuf *verts;
303                 GPUVertBuf *edges;
304                 GPUBatch *batch;
305                 GPUIndexBuf *elem;
306         } wire;
307
308         /* normals */
309         struct {
310                 GPUVertBuf *verts;
311                 GPUVertBuf *edges;
312                 GPUBatch *batch;
313                 GPUIndexBuf *elem;
314         } normal;
315
316         /* control handles and vertices */
317         struct {
318                 GPUBatch *edges;
319                 GPUBatch *verts;
320         } overlay;
321
322         struct {
323                 GPUVertBuf *verts;
324                 GPUIndexBuf *triangles_in_order;
325                 GPUBatch **shaded_triangles;
326                 GPUBatch *batch;
327                 int mat_len;
328         } surface;
329
330         /* 3d text */
331         struct {
332                 GPUBatch *select;
333                 GPUBatch *cursor;
334         } text;
335
336         /* settings to determine if cache is invalid */
337         bool is_dirty;
338
339         bool hide_handles;
340         bool hide_normals;
341
342         float normal_size;
343
344         bool is_editmode;
345 } CurveBatchCache;
346
347 /* GPUBatch cache management. */
348
349 static bool curve_batch_cache_valid(Curve *cu)
350 {
351         CurveBatchCache *cache = cu->batch_cache;
352
353         if (cache == NULL) {
354                 return false;
355         }
356
357         if (cache->is_dirty) {
358                 return false;
359         }
360
361         if (cache->is_editmode != ((cu->editnurb != NULL) || (cu->editfont != NULL))) {
362                 return false;
363         }
364
365         if (cache->is_editmode) {
366                 if (cu->editnurb) {
367                         if ((cache->hide_handles != ((cu->drawflag & CU_HIDE_HANDLES) != 0))) {
368                                 return false;
369                         }
370                         else if ((cache->hide_normals != ((cu->drawflag & CU_HIDE_NORMALS) != 0))) {
371                                 return false;
372                         }
373                 }
374                 else if (cu->editfont) {
375                         /* TODO */
376                 }
377         }
378
379         return true;
380 }
381
382 static void curve_batch_cache_init(Curve *cu)
383 {
384         CurveBatchCache *cache = cu->batch_cache;
385
386         if (!cache) {
387                 cache = cu->batch_cache = MEM_callocN(sizeof(*cache), __func__);
388         }
389         else {
390                 memset(cache, 0, sizeof(*cache));
391         }
392
393         cache->hide_handles = (cu->drawflag & CU_HIDE_HANDLES) != 0;
394         cache->hide_normals = (cu->drawflag & CU_HIDE_NORMALS) != 0;
395
396 #if 0
397         ListBase *nurbs;
398         if (cu->editnurb) {
399                 EditNurb *editnurb = cu->editnurb;
400                 nurbs = &editnurb->nurbs;
401         }
402         else {
403                 nurbs = &cu->nurb;
404         }
405 #endif
406
407         cache->is_editmode = (cu->editnurb != NULL) || (cu->editfont != NULL);
408
409         cache->is_dirty = false;
410 }
411
412 static CurveBatchCache *curve_batch_cache_get(Curve *cu)
413 {
414         if (!curve_batch_cache_valid(cu)) {
415                 curve_batch_cache_clear(cu);
416                 curve_batch_cache_init(cu);
417         }
418         return cu->batch_cache;
419 }
420
421 void DRW_curve_batch_cache_dirty_tag(Curve *cu, int mode)
422 {
423         CurveBatchCache *cache = cu->batch_cache;
424         if (cache == NULL) {
425                 return;
426         }
427         switch (mode) {
428                 case BKE_CURVE_BATCH_DIRTY_ALL:
429                         cache->is_dirty = true;
430                         break;
431                 case BKE_CURVE_BATCH_DIRTY_SELECT:
432                         /* editnurb */
433                         GPU_BATCH_DISCARD_SAFE(cache->overlay.verts);
434                         GPU_BATCH_DISCARD_SAFE(cache->overlay.edges);
435
436                         /* editfont */
437                         GPU_BATCH_DISCARD_SAFE(cache->text.select);
438                         GPU_BATCH_DISCARD_SAFE(cache->text.cursor);
439                         break;
440                 default:
441                         BLI_assert(0);
442         }
443 }
444
445 static void curve_batch_cache_clear(Curve *cu)
446 {
447         CurveBatchCache *cache = cu->batch_cache;
448         if (!cache) {
449                 return;
450         }
451
452         GPU_BATCH_DISCARD_SAFE(cache->overlay.verts);
453         GPU_BATCH_DISCARD_SAFE(cache->overlay.edges);
454
455         GPU_VERTBUF_DISCARD_SAFE(cache->surface.verts);
456         GPU_INDEXBUF_DISCARD_SAFE(cache->surface.triangles_in_order);
457
458         GPU_BATCH_DISCARD_ARRAY_SAFE(cache->surface.shaded_triangles, cache->surface.mat_len);
459         GPU_BATCH_DISCARD_SAFE(cache->surface.batch);
460
461         /* don't own vbo & elems */
462         GPU_BATCH_DISCARD_SAFE(cache->wire.batch);
463         GPU_VERTBUF_DISCARD_SAFE(cache->wire.verts);
464         GPU_VERTBUF_DISCARD_SAFE(cache->wire.edges);
465         GPU_INDEXBUF_DISCARD_SAFE(cache->wire.elem);
466
467         /* don't own vbo & elems */
468         GPU_BATCH_DISCARD_SAFE(cache->normal.batch);
469         GPU_VERTBUF_DISCARD_SAFE(cache->normal.verts);
470         GPU_VERTBUF_DISCARD_SAFE(cache->normal.edges);
471         GPU_INDEXBUF_DISCARD_SAFE(cache->normal.elem);
472
473         /* 3d text */
474         GPU_BATCH_DISCARD_SAFE(cache->text.cursor);
475         GPU_BATCH_DISCARD_SAFE(cache->text.select);
476 }
477
478 void DRW_curve_batch_cache_free(Curve *cu)
479 {
480         curve_batch_cache_clear(cu);
481         MEM_SAFE_FREE(cu->batch_cache);
482 }
483
484 /* -------------------------------------------------------------------- */
485
486 /** \name Private Curve Cache API
487  * \{ */
488
489 /* GPUBatch cache usage. */
490 static GPUVertBuf *curve_batch_cache_get_wire_verts(CurveRenderData *rdata, CurveBatchCache *cache)
491 {
492         BLI_assert(rdata->types & CU_DATATYPE_WIRE);
493         BLI_assert(rdata->ob_curve_cache != NULL);
494
495         if (cache->wire.verts == NULL) {
496                 static GPUVertFormat format = { 0 };
497                 static struct { uint pos; } attr_id;
498                 if (format.attr_len == 0) {
499                         /* initialize vertex format */
500                         attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
501                 }
502
503                 const int vert_len = curve_render_data_wire_verts_len_get(rdata);
504
505                 GPUVertBuf *vbo = cache->wire.verts = GPU_vertbuf_create_with_format(&format);
506                 GPU_vertbuf_data_alloc(vbo, vert_len);
507                 int vbo_len_used = 0;
508                 for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) {
509                         if (bl->nr > 0) {
510                                 const int i_end = vbo_len_used + bl->nr;
511                                 for (const BevPoint *bevp = bl->bevpoints; vbo_len_used < i_end; vbo_len_used++, bevp++) {
512                                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bevp->vec);
513                                 }
514                         }
515                 }
516                 BLI_assert(vbo_len_used == vert_len);
517         }
518
519         return cache->wire.verts;
520 }
521
522 static GPUIndexBuf *curve_batch_cache_get_wire_edges(CurveRenderData *rdata, CurveBatchCache *cache)
523 {
524         BLI_assert(rdata->types & CU_DATATYPE_WIRE);
525         BLI_assert(rdata->ob_curve_cache != NULL);
526
527         if (cache->wire.edges == NULL) {
528                 const int vert_len = curve_render_data_wire_verts_len_get(rdata);
529                 const int edge_len = curve_render_data_wire_edges_len_get(rdata);
530                 int edge_len_used = 0;
531
532                 GPUIndexBufBuilder elb;
533                 GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len);
534
535                 int i = 0;
536                 for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) {
537                         if (bl->nr > 0) {
538                                 const bool is_cyclic = bl->poly != -1;
539                                 const int i_end = i + (bl->nr);
540                                 int i_prev;
541                                 if (is_cyclic) {
542                                         i_prev = i + (bl->nr - 1);
543                                 }
544                                 else {
545                                         i_prev = i;
546                                         i += 1;
547                                 }
548                                 for (; i < i_end; i_prev = i++) {
549                                         GPU_indexbuf_add_line_verts(&elb, i_prev, i);
550                                         edge_len_used += 1;
551                                 }
552                         }
553                 }
554
555                 if (rdata->hide_handles) {
556                         BLI_assert(edge_len_used <= edge_len);
557                 }
558                 else {
559                         BLI_assert(edge_len_used == edge_len);
560                 }
561
562                 cache->wire.elem = GPU_indexbuf_build(&elb);
563         }
564
565         return cache->wire.elem;
566 }
567
568 static GPUVertBuf *curve_batch_cache_get_normal_verts(CurveRenderData *rdata, CurveBatchCache *cache)
569 {
570         BLI_assert(rdata->types & CU_DATATYPE_NORMAL);
571         BLI_assert(rdata->ob_curve_cache != NULL);
572
573         if (cache->normal.verts == NULL) {
574                 static GPUVertFormat format = { 0 };
575                 static struct { uint pos; } attr_id;
576                 if (format.attr_len == 0) {
577                         /* initialize vertex format */
578                         attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
579                 }
580
581                 const int normal_len = curve_render_data_normal_len_get(rdata);
582                 const int vert_len = normal_len * 3;
583
584                 GPUVertBuf *vbo = cache->normal.verts = GPU_vertbuf_create_with_format(&format);
585                 GPU_vertbuf_data_alloc(vbo, vert_len);
586                 int vbo_len_used = 0;
587
588                 const BevList *bl;
589                 const Nurb *nu;
590
591                 for (bl = rdata->ob_curve_cache->bev.first, nu = rdata->nurbs->first;
592                      nu && bl;
593                      bl = bl->next, nu = nu->next)
594                 {
595                         const BevPoint *bevp = bl->bevpoints;
596                         int nr = bl->nr;
597                         int skip = nu->resolu / 16;
598
599                         while (nr-- > 0) { /* accounts for empty bevel lists */
600                                 const float fac = bevp->radius * cache->normal_size;
601                                 float vec_a[3]; /* Offset perpendicular to the curve */
602                                 float vec_b[3]; /* Delta along the curve */
603
604                                 vec_a[0] = fac;
605                                 vec_a[1] = 0.0f;
606                                 vec_a[2] = 0.0f;
607
608                                 mul_qt_v3(bevp->quat, vec_a);
609                                 madd_v3_v3fl(vec_a, bevp->dir, -fac);
610
611                                 reflect_v3_v3v3(vec_b, vec_a, bevp->dir);
612                                 negate_v3(vec_b);
613
614                                 add_v3_v3(vec_a, bevp->vec);
615                                 add_v3_v3(vec_b, bevp->vec);
616
617                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, vec_a);
618                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, bevp->vec);
619                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, vec_b);
620
621                                 bevp += skip + 1;
622                                 nr -= skip;
623                         }
624                 }
625                 BLI_assert(vbo_len_used == vert_len);
626         }
627
628         return cache->normal.verts;
629 }
630
631 static GPUIndexBuf *curve_batch_cache_get_normal_edges(CurveRenderData *rdata, CurveBatchCache *cache)
632 {
633         BLI_assert(rdata->types & CU_DATATYPE_NORMAL);
634         BLI_assert(rdata->ob_curve_cache != NULL);
635
636         if (cache->normal.edges == NULL) {
637                 const int normal_len = curve_render_data_normal_len_get(rdata);
638                 const int vert_len = normal_len * 3;
639                 const int edge_len = normal_len * 2;
640
641                 GPUIndexBufBuilder elb;
642                 GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len);
643
644                 int vbo_len_used = 0;
645                 for (int i = 0; i < normal_len; i++) {
646                         GPU_indexbuf_add_line_verts(&elb, vbo_len_used + 0, vbo_len_used + 1);
647                         GPU_indexbuf_add_line_verts(&elb, vbo_len_used + 1, vbo_len_used + 2);
648                         vbo_len_used += 3;
649                 }
650
651                 BLI_assert(vbo_len_used == vert_len);
652
653                 cache->normal.elem = GPU_indexbuf_build(&elb);
654         }
655
656         return cache->normal.elem;
657 }
658
659 static void curve_batch_cache_create_overlay_batches(Curve *cu)
660 {
661         /* Since CU_DATATYPE_OVERLAY is slow to generate, generate them all at once */
662         int options = CU_DATATYPE_OVERLAY;
663
664         CurveBatchCache *cache = curve_batch_cache_get(cu);
665         CurveRenderData *rdata = curve_render_data_create(cu, NULL, options);
666
667         if (cache->overlay.verts == NULL) {
668                 static GPUVertFormat format = { 0 };
669                 static struct { uint pos, data; } attr_id;
670                 if (format.attr_len == 0) {
671                         /* initialize vertex format */
672                         attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
673                         attr_id.data = GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
674                 }
675
676                 GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
677                 const int vbo_len_capacity = curve_render_data_overlay_verts_len_get(rdata);
678                 int vbo_len_used = 0;
679                 GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
680                 int i = 0;
681                 for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next) {
682                         if (nu->bezt) {
683                                 int a = 0;
684                                 for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
685                                         if (bezt->hide == false) {
686                                                 const bool is_active = (i == rdata->actvert);
687                                                 char vflag;
688
689                                                 if (rdata->hide_handles) {
690                                                         vflag = (bezt->f2 & SELECT) ?
691                                                                 (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
692                                                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[1]);
693                                                         GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
694                                                         vbo_len_used += 1;
695                                                 }
696                                                 else {
697                                                         for (int j = 0; j < 3; j++) {
698                                                                 vflag = ((&bezt->f1)[j] & SELECT) ?
699                                                                         (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
700                                                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[j]);
701                                                                 GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
702                                                                 vbo_len_used += 1;
703                                                         }
704                                                 }
705                                         }
706                                         i += 1;
707                                 }
708                         }
709                         else if (nu->bp) {
710                                 int a = 0;
711                                 for (const BPoint *bp = nu->bp; a < nu->pntsu; a++, bp++) {
712                                         if (bp->hide == false) {
713                                                 const bool is_active = (i == rdata->actvert);
714                                                 char vflag;
715                                                 vflag = (bp->f1 & SELECT) ? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
716                                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp->vec);
717                                                 GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
718                                                 vbo_len_used += 1;
719                                         }
720                                         i += 1;
721                                 }
722                         }
723                         i += nu->pntsu;
724                 }
725                 if (vbo_len_capacity != vbo_len_used) {
726                         GPU_vertbuf_data_resize(vbo, vbo_len_used);
727                 }
728
729                 cache->overlay.verts = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
730         }
731
732
733         if ((cache->overlay.edges == NULL) && (rdata->hide_handles == false)) {
734                 /* Note: we could reference indices to vertices (above) */
735
736                 static GPUVertFormat format = { 0 };
737                 static struct { uint pos, data; } attr_id;
738                 if (format.attr_len == 0) {
739                         /* initialize vertex format */
740                         attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
741                         attr_id.data = GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
742                 }
743
744                 GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
745                 const int edge_len =  curve_render_data_overlay_edges_len_get(rdata);
746                 const int vbo_len_capacity = edge_len * 2;
747                 int vbo_len_used = 0;
748                 GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
749                 int i = 0;
750                 for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, i++) {
751                         const bool is_active_nurb = (i == cu->actnu);
752
753                         if (nu->bezt) {
754                                 int a = 0;
755                                 for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
756                                         if (bezt->hide == false) {
757                                                 char col_id;
758
759                                                 for (int j = 0; j < 2; j += 1) {
760                                                         /* same vertex twice, only check different selection */
761                                                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[1]);
762                                                         vbo_len_used += 1;
763
764                                                         col_id = (&bezt->h1)[j];
765                                                         if ((&bezt->f1)[j * 2] & SELECT) {
766                                                                 col_id += HANDLE_SEL_OFFSET;
767                                                         }
768                                                         if (is_active_nurb) {
769                                                                 col_id |= ACTIVE_NURB;
770                                                         }
771
772                                                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[j * 2]);
773                                                         GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &col_id);
774                                                         vbo_len_used += 1;
775                                                 }
776                                         }
777                                 }
778                         }
779                         else if (nu->bp) {
780                                 int a = 1;
781                                 for (const BPoint *bp_prev = nu->bp, *bp_curr = &nu->bp[1]; a < nu->pntsu; a++, bp_prev = bp_curr++) {
782                                         if ((bp_prev->hide == false) && (bp_curr->hide == false)) {
783                                                 char col_id = ((bp_prev->f1 & SELECT) && (bp_curr->f1 & SELECT)) ? COLOR_NURB_SEL_ULINE_ID : COLOR_NURB_ULINE_ID;
784
785                                                 if (is_active_nurb) {
786                                                         col_id |= ACTIVE_NURB;
787                                                 }
788
789                                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp_prev->vec);
790                                                 vbo_len_used += 1;
791
792                                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp_curr->vec);
793                                                 GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &col_id);
794                                                 vbo_len_used += 1;
795
796                                         }
797                                 }
798                         }
799                 }
800                 if (vbo_len_capacity != vbo_len_used) {
801                         GPU_vertbuf_data_resize(vbo, vbo_len_used);
802                 }
803
804                 cache->overlay.edges = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
805         }
806
807         curve_render_data_free(rdata);
808 }
809
810 static GPUBatch *curve_batch_cache_get_pos_and_normals(CurveRenderData *rdata, CurveBatchCache *cache)
811 {
812         BLI_assert(rdata->types & CU_DATATYPE_SURFACE);
813         if (cache->surface.batch == NULL) {
814                 ListBase *lb = &rdata->ob_curve_cache->disp;
815
816                 if (cache->surface.verts == NULL) {
817                         cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb);
818                 }
819                 if (cache->surface.triangles_in_order == NULL) {
820                         cache->surface.triangles_in_order = DRW_displist_indexbuf_calc_triangles_in_order(lb);
821                 }
822                 cache->surface.batch = GPU_batch_create(
823                         GPU_PRIM_TRIS, cache->surface.verts, cache->surface.triangles_in_order);
824         }
825
826         return cache->surface.batch;
827 }
828
829 /** \} */
830
831
832 /* -------------------------------------------------------------------- */
833
834 /** \name Private Object/Font Cache API
835  * \{ */
836
837
838 static GPUBatch *curve_batch_cache_get_overlay_select(CurveRenderData *rdata, CurveBatchCache *cache)
839 {
840         BLI_assert(rdata->types & CU_DATATYPE_TEXT_SELECT);
841         if (cache->text.select == NULL) {
842                 EditFont *ef = rdata->text.edit_font;
843                 static GPUVertFormat format = { 0 };
844                 static struct { uint pos; } attr_id;
845                 if (format.attr_len == 0) {
846                         attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
847                 }
848
849                 GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
850                 const int vbo_len_capacity = ef->selboxes_len * 6;
851                 int vbo_len_used = 0;
852                 GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
853
854                 float box[4][3];
855
856                 /* fill in xy below */
857                 box[0][2] = box[1][2] = box[2][2] = box[3][2] = 0.001;
858
859                 for (int i = 0; i < ef->selboxes_len; i++) {
860                         EditFontSelBox *sb = &ef->selboxes[i];
861
862                         float selboxw;
863                         if (i + 1 != ef->selboxes_len) {
864                                 if (ef->selboxes[i + 1].y == sb->y)
865                                         selboxw = ef->selboxes[i + 1].x - sb->x;
866                                 else
867                                         selboxw = sb->w;
868                         }
869                         else {
870                                 selboxw = sb->w;
871                         }
872
873                         if (sb->rot == 0.0f) {
874                                 copy_v2_fl2(box[0], sb->x, sb->y);
875                                 copy_v2_fl2(box[1], sb->x + selboxw, sb->y);
876                                 copy_v2_fl2(box[2], sb->x + selboxw, sb->y + sb->h);
877                                 copy_v2_fl2(box[3], sb->x, sb->y + sb->h);
878                         }
879                         else {
880                                 float mat[2][2];
881
882                                 angle_to_mat2(mat, sb->rot);
883
884                                 copy_v2_fl2(box[0], sb->x, sb->y);
885
886                                 copy_v2_fl2(box[1], selboxw, 0.0f);
887                                 mul_m2v2(mat, box[1]);
888                                 add_v2_v2(box[1], &sb->x);
889
890                                 copy_v2_fl2(box[2], selboxw, sb->h);
891                                 mul_m2v2(mat, box[2]);
892                                 add_v2_v2(box[2], &sb->x);
893
894                                 copy_v2_fl2(box[3], 0.0f, sb->h);
895                                 mul_m2v2(mat, box[3]);
896                                 add_v2_v2(box[3], &sb->x);
897                         }
898
899                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[0]);
900                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[1]);
901                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[2]);
902
903                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[0]);
904                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[2]);
905                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[3]);
906                 }
907                 BLI_assert(vbo_len_used == vbo_len_capacity);
908                 cache->text.select = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
909         }
910         return cache->text.select;
911 }
912
913 static GPUBatch *curve_batch_cache_get_overlay_cursor(CurveRenderData *rdata, CurveBatchCache *cache)
914 {
915         BLI_assert(rdata->types & CU_DATATYPE_TEXT_SELECT);
916         if (cache->text.cursor == NULL) {
917                 static GPUVertFormat format = { 0 };
918                 static struct { uint pos; } attr_id;
919                 if (format.attr_len == 0) {
920                         attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
921                 }
922
923                 GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
924                 const int vbo_len_capacity = 4;
925                 GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
926                 for (int i = 0; i < 4; i++) {
927                         GPU_vertbuf_attr_set(vbo, attr_id.pos, i, rdata->text.edit_font->textcurs[i]);
928                 }
929                 cache->text.cursor = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
930         }
931         return cache->text.cursor;
932 }
933
934 /** \} */
935
936 /* -------------------------------------------------------------------- */
937
938 /** \name Public Object/Curve API
939  * \{ */
940
941 GPUBatch *DRW_curve_batch_cache_get_wire_edge(Curve *cu, CurveCache *ob_curve_cache)
942 {
943         CurveBatchCache *cache = curve_batch_cache_get(cu);
944
945         if (cache->wire.batch == NULL) {
946                 /* create batch from Curve */
947                 CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_WIRE);
948
949                 cache->wire.batch = GPU_batch_create(
950                         GPU_PRIM_LINES,
951                         curve_batch_cache_get_wire_verts(rdata, cache),
952                         curve_batch_cache_get_wire_edges(rdata, cache));
953
954                 curve_render_data_free(rdata);
955         }
956         return cache->wire.batch;
957 }
958
959 GPUBatch *DRW_curve_batch_cache_get_normal_edge(Curve *cu, CurveCache *ob_curve_cache, float normal_size)
960 {
961         CurveBatchCache *cache = curve_batch_cache_get(cu);
962
963         if (cache->normal.batch != NULL) {
964                 cache->normal_size = normal_size;
965                 if (cache->normal_size != normal_size) {
966                         GPU_BATCH_DISCARD_SAFE(cache->normal.batch);
967                         GPU_VERTBUF_DISCARD_SAFE(cache->normal.edges);
968                 }
969         }
970         cache->normal_size = normal_size;
971
972         if (cache->normal.batch == NULL) {
973                 /* create batch from Curve */
974                 CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_NORMAL);
975
976                 cache->normal.batch = GPU_batch_create(
977                         GPU_PRIM_LINES,
978                         curve_batch_cache_get_normal_verts(rdata, cache),
979                         curve_batch_cache_get_normal_edges(rdata, cache));
980
981                 curve_render_data_free(rdata);
982                 cache->normal_size = normal_size;
983         }
984         return cache->normal.batch;
985 }
986
987 GPUBatch *DRW_curve_batch_cache_get_overlay_edges(Curve *cu)
988 {
989         CurveBatchCache *cache = curve_batch_cache_get(cu);
990
991         if (cache->overlay.edges == NULL) {
992                 curve_batch_cache_create_overlay_batches(cu);
993         }
994
995         return cache->overlay.edges;
996 }
997
998 GPUBatch *DRW_curve_batch_cache_get_overlay_verts(Curve *cu)
999 {
1000         CurveBatchCache *cache = curve_batch_cache_get(cu);
1001
1002         if (cache->overlay.verts == NULL) {
1003                 curve_batch_cache_create_overlay_batches(cu);
1004         }
1005
1006         return cache->overlay.verts;
1007 }
1008
1009 GPUBatch *DRW_curve_batch_cache_get_triangles_with_normals(
1010         struct Curve *cu, struct CurveCache *ob_curve_cache)
1011 {
1012         CurveBatchCache *cache = curve_batch_cache_get(cu);
1013
1014         if (cache->surface.batch == NULL) {
1015                 CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE);
1016
1017                 curve_batch_cache_get_pos_and_normals(rdata, cache);
1018
1019                 curve_render_data_free(rdata);
1020         }
1021
1022         return cache->surface.batch;
1023 }
1024
1025 GPUBatch **DRW_curve_batch_cache_get_surface_shaded(
1026         struct Curve *cu, struct CurveCache *ob_curve_cache,
1027         struct GPUMaterial **UNUSED(gpumat_array), uint gpumat_array_len)
1028 {
1029         CurveBatchCache *cache = curve_batch_cache_get(cu);
1030
1031         if (cache->surface.mat_len != gpumat_array_len) {
1032                 GPU_BATCH_DISCARD_ARRAY_SAFE(cache->surface.shaded_triangles, cache->surface.mat_len);
1033         }
1034
1035         if (cache->surface.shaded_triangles == NULL) {
1036                 CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE);
1037                 ListBase *lb = &rdata->ob_curve_cache->disp;
1038
1039                 cache->surface.mat_len = gpumat_array_len;
1040                 if (cu->flag & CU_UV_ORCO) {
1041                         cache->surface.shaded_triangles = DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(
1042                                 lb, gpumat_array_len);
1043                 }
1044                 else {
1045                         cache->surface.shaded_triangles = MEM_mallocN(
1046                                 sizeof(*cache->surface.shaded_triangles) * gpumat_array_len, __func__);
1047                         GPUIndexBuf **el = DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(
1048                                 lb, gpumat_array_len);
1049
1050                         if (cache->surface.verts == NULL) {
1051                                 cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb);
1052                         }
1053
1054                         for (int i = 0; i < gpumat_array_len; ++i) {
1055                                 cache->surface.shaded_triangles[i] = GPU_batch_create_ex(
1056                                         GPU_PRIM_TRIS, cache->surface.verts, el[i], GPU_BATCH_OWNS_INDEX);
1057                         }
1058
1059                         MEM_freeN(el); /* Save `el` in cache? */
1060                 }
1061
1062                 curve_render_data_free(rdata);
1063         }
1064
1065         return cache->surface.shaded_triangles;
1066 }
1067
1068
1069 /* -------------------------------------------------------------------- */
1070
1071 /** \name Public Object/Font API
1072  * \{ */
1073
1074 GPUBatch *DRW_curve_batch_cache_get_overlay_select(Curve *cu)
1075 {
1076         CurveBatchCache *cache = curve_batch_cache_get(cu);
1077
1078         if (cache->text.select == NULL) {
1079                 CurveRenderData *rdata = curve_render_data_create(cu, NULL, CU_DATATYPE_TEXT_SELECT);
1080
1081                 curve_batch_cache_get_overlay_select(rdata, cache);
1082
1083                 curve_render_data_free(rdata);
1084         }
1085
1086         return cache->text.select;
1087 }
1088
1089 GPUBatch *DRW_curve_batch_cache_get_overlay_cursor(Curve *cu)
1090 {
1091         CurveBatchCache *cache = curve_batch_cache_get(cu);
1092
1093         if (cache->text.cursor == NULL) {
1094                 CurveRenderData *rdata = curve_render_data_create(cu, NULL, CU_DATATYPE_TEXT_SELECT);
1095
1096                 curve_batch_cache_get_overlay_cursor(rdata, cache);
1097
1098                 curve_render_data_free(rdata);
1099         }
1100
1101         return cache->text.cursor;
1102 }
1103
1104 /** \} */