3fd8a970db9615875e5bf1b35da4efd08539a91f
[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 enum {
296         VFLAG_VERTEX_SELECTED = 1 << 0,
297         VFLAG_VERTEX_ACTIVE   = 1 << 1,
298 };
299
300 /* ---------------------------------------------------------------------- */
301 /* Curve GPUBatch Cache */
302
303 typedef struct CurveBatchCache {
304         /* center-line */
305         struct {
306                 GPUVertBuf *verts;
307                 GPUVertBuf *edges;
308                 GPUBatch *batch;
309                 GPUIndexBuf *elem;
310         } wire;
311
312         /* normals */
313         struct {
314                 GPUVertBuf *verts;
315                 GPUVertBuf *edges;
316                 GPUBatch *batch;
317                 GPUIndexBuf *elem;
318         } normal;
319
320         /* control handles and vertices */
321         struct {
322                 GPUBatch *edges;
323                 GPUBatch *verts;
324         } overlay;
325
326         struct {
327                 GPUVertBuf *verts;
328                 GPUIndexBuf *triangles_in_order;
329                 GPUBatch **shaded_triangles;
330                 GPUBatch *batch;
331                 int mat_len;
332         } surface;
333
334         /* 3d text */
335         struct {
336                 GPUBatch *select;
337                 GPUBatch *cursor;
338         } text;
339
340         /* settings to determine if cache is invalid */
341         bool is_dirty;
342
343         bool hide_handles;
344         bool hide_normals;
345
346         float normal_size;
347
348         bool is_editmode;
349 } CurveBatchCache;
350
351 /* GPUBatch cache management. */
352
353 static bool curve_batch_cache_valid(Curve *cu)
354 {
355         CurveBatchCache *cache = cu->batch_cache;
356
357         if (cache == NULL) {
358                 return false;
359         }
360
361         if (cache->is_dirty) {
362                 return false;
363         }
364
365         if (cache->is_editmode != ((cu->editnurb != NULL) || (cu->editfont != NULL))) {
366                 return false;
367         }
368
369         if (cache->is_editmode) {
370                 if (cu->editnurb) {
371                         if ((cache->hide_handles != ((cu->drawflag & CU_HIDE_HANDLES) != 0))) {
372                                 return false;
373                         }
374                         else if ((cache->hide_normals != ((cu->drawflag & CU_HIDE_NORMALS) != 0))) {
375                                 return false;
376                         }
377                 }
378                 else if (cu->editfont) {
379                         /* TODO */
380                 }
381         }
382
383         return true;
384 }
385
386 static void curve_batch_cache_init(Curve *cu)
387 {
388         CurveBatchCache *cache = cu->batch_cache;
389
390         if (!cache) {
391                 cache = cu->batch_cache = MEM_callocN(sizeof(*cache), __func__);
392         }
393         else {
394                 memset(cache, 0, sizeof(*cache));
395         }
396
397         cache->hide_handles = (cu->drawflag & CU_HIDE_HANDLES) != 0;
398         cache->hide_normals = (cu->drawflag & CU_HIDE_NORMALS) != 0;
399
400 #if 0
401         ListBase *nurbs;
402         if (cu->editnurb) {
403                 EditNurb *editnurb = cu->editnurb;
404                 nurbs = &editnurb->nurbs;
405         }
406         else {
407                 nurbs = &cu->nurb;
408         }
409 #endif
410
411         cache->is_editmode = (cu->editnurb != NULL) || (cu->editfont != NULL);
412
413         cache->is_dirty = false;
414 }
415
416 static CurveBatchCache *curve_batch_cache_get(Curve *cu)
417 {
418         if (!curve_batch_cache_valid(cu)) {
419                 curve_batch_cache_clear(cu);
420                 curve_batch_cache_init(cu);
421         }
422         return cu->batch_cache;
423 }
424
425 void DRW_curve_batch_cache_dirty_tag(Curve *cu, int mode)
426 {
427         CurveBatchCache *cache = cu->batch_cache;
428         if (cache == NULL) {
429                 return;
430         }
431         switch (mode) {
432                 case BKE_CURVE_BATCH_DIRTY_ALL:
433                         cache->is_dirty = true;
434                         break;
435                 case BKE_CURVE_BATCH_DIRTY_SELECT:
436                         /* editnurb */
437                         GPU_BATCH_DISCARD_SAFE(cache->overlay.verts);
438                         GPU_BATCH_DISCARD_SAFE(cache->overlay.edges);
439
440                         /* editfont */
441                         GPU_BATCH_DISCARD_SAFE(cache->text.select);
442                         GPU_BATCH_DISCARD_SAFE(cache->text.cursor);
443                         break;
444                 default:
445                         BLI_assert(0);
446         }
447 }
448
449 static void curve_batch_cache_clear(Curve *cu)
450 {
451         CurveBatchCache *cache = cu->batch_cache;
452         if (!cache) {
453                 return;
454         }
455
456         GPU_BATCH_DISCARD_SAFE(cache->overlay.verts);
457         GPU_BATCH_DISCARD_SAFE(cache->overlay.edges);
458
459         GPU_VERTBUF_DISCARD_SAFE(cache->surface.verts);
460         GPU_INDEXBUF_DISCARD_SAFE(cache->surface.triangles_in_order);
461
462         GPU_BATCH_DISCARD_ARRAY_SAFE(cache->surface.shaded_triangles, cache->surface.mat_len);
463         GPU_BATCH_DISCARD_SAFE(cache->surface.batch);
464
465         /* don't own vbo & elems */
466         GPU_BATCH_DISCARD_SAFE(cache->wire.batch);
467         GPU_VERTBUF_DISCARD_SAFE(cache->wire.verts);
468         GPU_VERTBUF_DISCARD_SAFE(cache->wire.edges);
469         GPU_INDEXBUF_DISCARD_SAFE(cache->wire.elem);
470
471         /* don't own vbo & elems */
472         GPU_BATCH_DISCARD_SAFE(cache->normal.batch);
473         GPU_VERTBUF_DISCARD_SAFE(cache->normal.verts);
474         GPU_VERTBUF_DISCARD_SAFE(cache->normal.edges);
475         GPU_INDEXBUF_DISCARD_SAFE(cache->normal.elem);
476
477         /* 3d text */
478         GPU_BATCH_DISCARD_SAFE(cache->text.cursor);
479         GPU_BATCH_DISCARD_SAFE(cache->text.select);
480 }
481
482 void DRW_curve_batch_cache_free(Curve *cu)
483 {
484         curve_batch_cache_clear(cu);
485         MEM_SAFE_FREE(cu->batch_cache);
486 }
487
488 /* -------------------------------------------------------------------- */
489
490 /** \name Private Curve Cache API
491  * \{ */
492
493 /* GPUBatch cache usage. */
494 static GPUVertBuf *curve_batch_cache_get_wire_verts(CurveRenderData *rdata, CurveBatchCache *cache)
495 {
496         BLI_assert(rdata->types & CU_DATATYPE_WIRE);
497         BLI_assert(rdata->ob_curve_cache != NULL);
498
499         if (cache->wire.verts == NULL) {
500                 static GPUVertFormat format = { 0 };
501                 static struct { uint pos; } attr_id;
502                 if (format.attr_len == 0) {
503                         /* initialize vertex format */
504                         attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
505                 }
506
507                 const int vert_len = curve_render_data_wire_verts_len_get(rdata);
508
509                 GPUVertBuf *vbo = cache->wire.verts = GPU_vertbuf_create_with_format(&format);
510                 GPU_vertbuf_data_alloc(vbo, vert_len);
511                 int vbo_len_used = 0;
512                 for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) {
513                         if (bl->nr > 0) {
514                                 const int i_end = vbo_len_used + bl->nr;
515                                 for (const BevPoint *bevp = bl->bevpoints; vbo_len_used < i_end; vbo_len_used++, bevp++) {
516                                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bevp->vec);
517                                 }
518                         }
519                 }
520                 BLI_assert(vbo_len_used == vert_len);
521         }
522
523         return cache->wire.verts;
524 }
525
526 static GPUIndexBuf *curve_batch_cache_get_wire_edges(CurveRenderData *rdata, CurveBatchCache *cache)
527 {
528         BLI_assert(rdata->types & CU_DATATYPE_WIRE);
529         BLI_assert(rdata->ob_curve_cache != NULL);
530
531         if (cache->wire.edges == NULL) {
532                 const int vert_len = curve_render_data_wire_verts_len_get(rdata);
533                 const int edge_len = curve_render_data_wire_edges_len_get(rdata);
534                 int edge_len_used = 0;
535
536                 GPUIndexBufBuilder elb;
537                 GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len);
538
539                 int i = 0;
540                 for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) {
541                         if (bl->nr > 0) {
542                                 const bool is_cyclic = bl->poly != -1;
543                                 const int i_end = i + (bl->nr);
544                                 int i_prev;
545                                 if (is_cyclic) {
546                                         i_prev = i + (bl->nr - 1);
547                                 }
548                                 else {
549                                         i_prev = i;
550                                         i += 1;
551                                 }
552                                 for (; i < i_end; i_prev = i++) {
553                                         GPU_indexbuf_add_line_verts(&elb, i_prev, i);
554                                         edge_len_used += 1;
555                                 }
556                         }
557                 }
558
559                 if (rdata->hide_handles) {
560                         BLI_assert(edge_len_used <= edge_len);
561                 }
562                 else {
563                         BLI_assert(edge_len_used == edge_len);
564                 }
565
566                 cache->wire.elem = GPU_indexbuf_build(&elb);
567         }
568
569         return cache->wire.elem;
570 }
571
572 static GPUVertBuf *curve_batch_cache_get_normal_verts(CurveRenderData *rdata, CurveBatchCache *cache)
573 {
574         BLI_assert(rdata->types & CU_DATATYPE_NORMAL);
575         BLI_assert(rdata->ob_curve_cache != NULL);
576
577         if (cache->normal.verts == NULL) {
578                 static GPUVertFormat format = { 0 };
579                 static struct { uint pos; } attr_id;
580                 if (format.attr_len == 0) {
581                         /* initialize vertex format */
582                         attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
583                 }
584
585                 const int normal_len = curve_render_data_normal_len_get(rdata);
586                 const int vert_len = normal_len * 3;
587
588                 GPUVertBuf *vbo = cache->normal.verts = GPU_vertbuf_create_with_format(&format);
589                 GPU_vertbuf_data_alloc(vbo, vert_len);
590                 int vbo_len_used = 0;
591
592                 const BevList *bl;
593                 const Nurb *nu;
594
595                 for (bl = rdata->ob_curve_cache->bev.first, nu = rdata->nurbs->first;
596                      nu && bl;
597                      bl = bl->next, nu = nu->next)
598                 {
599                         const BevPoint *bevp = bl->bevpoints;
600                         int nr = bl->nr;
601                         int skip = nu->resolu / 16;
602
603                         while (nr-- > 0) { /* accounts for empty bevel lists */
604                                 const float fac = bevp->radius * cache->normal_size;
605                                 float vec_a[3]; /* Offset perpendicular to the curve */
606                                 float vec_b[3]; /* Delta along the curve */
607
608                                 vec_a[0] = fac;
609                                 vec_a[1] = 0.0f;
610                                 vec_a[2] = 0.0f;
611
612                                 mul_qt_v3(bevp->quat, vec_a);
613                                 madd_v3_v3fl(vec_a, bevp->dir, -fac);
614
615                                 reflect_v3_v3v3(vec_b, vec_a, bevp->dir);
616                                 negate_v3(vec_b);
617
618                                 add_v3_v3(vec_a, bevp->vec);
619                                 add_v3_v3(vec_b, bevp->vec);
620
621                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, vec_a);
622                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, bevp->vec);
623                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, vec_b);
624
625                                 bevp += skip + 1;
626                                 nr -= skip;
627                         }
628                 }
629                 BLI_assert(vbo_len_used == vert_len);
630         }
631
632         return cache->normal.verts;
633 }
634
635 static GPUIndexBuf *curve_batch_cache_get_normal_edges(CurveRenderData *rdata, CurveBatchCache *cache)
636 {
637         BLI_assert(rdata->types & CU_DATATYPE_NORMAL);
638         BLI_assert(rdata->ob_curve_cache != NULL);
639
640         if (cache->normal.edges == NULL) {
641                 const int normal_len = curve_render_data_normal_len_get(rdata);
642                 const int vert_len = normal_len * 3;
643                 const int edge_len = normal_len * 2;
644
645                 GPUIndexBufBuilder elb;
646                 GPU_indexbuf_init(&elb, GPU_PRIM_LINES, edge_len, vert_len);
647
648                 int vbo_len_used = 0;
649                 for (int i = 0; i < normal_len; i++) {
650                         GPU_indexbuf_add_line_verts(&elb, vbo_len_used + 0, vbo_len_used + 1);
651                         GPU_indexbuf_add_line_verts(&elb, vbo_len_used + 1, vbo_len_used + 2);
652                         vbo_len_used += 3;
653                 }
654
655                 BLI_assert(vbo_len_used == vert_len);
656
657                 cache->normal.elem = GPU_indexbuf_build(&elb);
658         }
659
660         return cache->normal.elem;
661 }
662
663 static void curve_batch_cache_create_overlay_batches(Curve *cu)
664 {
665         /* Since CU_DATATYPE_OVERLAY is slow to generate, generate them all at once */
666         int options = CU_DATATYPE_OVERLAY;
667
668         CurveBatchCache *cache = curve_batch_cache_get(cu);
669         CurveRenderData *rdata = curve_render_data_create(cu, NULL, options);
670
671         if (cache->overlay.verts == NULL) {
672                 static GPUVertFormat format = { 0 };
673                 static struct { uint pos, data; } attr_id;
674                 if (format.attr_len == 0) {
675                         /* initialize vertex format */
676                         attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
677                         attr_id.data = GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
678                 }
679
680                 GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
681                 const int vbo_len_capacity = curve_render_data_overlay_verts_len_get(rdata);
682                 int vbo_len_used = 0;
683                 GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
684                 int i = 0;
685                 for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next) {
686                         if (nu->bezt) {
687                                 int a = 0;
688                                 for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
689                                         if (bezt->hide == false) {
690                                                 const bool is_active = (i == rdata->actvert);
691                                                 char vflag;
692
693                                                 if (rdata->hide_handles) {
694                                                         vflag = (bezt->f2 & SELECT) ?
695                                                                 (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
696                                                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[1]);
697                                                         GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
698                                                         vbo_len_used += 1;
699                                                 }
700                                                 else {
701                                                         for (int j = 0; j < 3; j++) {
702                                                                 vflag = ((&bezt->f1)[j] & SELECT) ?
703                                                                         (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
704                                                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[j]);
705                                                                 GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
706                                                                 vbo_len_used += 1;
707                                                         }
708                                                 }
709                                         }
710                                         i += 1;
711                                 }
712                         }
713                         else if (nu->bp) {
714                                 int a = 0;
715                                 for (const BPoint *bp = nu->bp; a < nu->pntsu; a++, bp++) {
716                                         if (bp->hide == false) {
717                                                 const bool is_active = (i == rdata->actvert);
718                                                 char vflag;
719                                                 vflag = (bp->f1 & SELECT) ? (is_active ? VFLAG_VERTEX_ACTIVE : VFLAG_VERTEX_SELECTED) : 0;
720                                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp->vec);
721                                                 GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &vflag);
722                                                 vbo_len_used += 1;
723                                         }
724                                         i += 1;
725                                 }
726                         }
727                         i += nu->pntsu;
728                 }
729                 if (vbo_len_capacity != vbo_len_used) {
730                         GPU_vertbuf_data_resize(vbo, vbo_len_used);
731                 }
732
733                 cache->overlay.verts = GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
734         }
735
736
737         if ((cache->overlay.edges == NULL) && (rdata->hide_handles == false)) {
738                 /* Note: we could reference indices to vertices (above) */
739
740                 static GPUVertFormat format = { 0 };
741                 static struct { uint pos, data; } attr_id;
742                 if (format.attr_len == 0) {
743                         /* initialize vertex format */
744                         attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
745                         attr_id.data = GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
746                 }
747
748                 GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
749                 const int edge_len =  curve_render_data_overlay_edges_len_get(rdata);
750                 const int vbo_len_capacity = edge_len * 2;
751                 int vbo_len_used = 0;
752                 GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
753                 int i = 0;
754                 for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, i++) {
755                         const bool is_active_nurb = (i == cu->actnu);
756
757                         if (nu->bezt) {
758                                 int a = 0;
759                                 for (const BezTriple *bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
760                                         if (bezt->hide == false) {
761                                                 char col_id;
762
763                                                 for (int j = 0; j < 2; j += 1) {
764                                                         /* same vertex twice, only check different selection */
765                                                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[1]);
766                                                         vbo_len_used += 1;
767
768                                                         col_id = (&bezt->h1)[j];
769                                                         if ((&bezt->f1)[j * 2] & SELECT) {
770                                                                 col_id += HANDLE_SEL_OFFSET;
771                                                         }
772                                                         if (is_active_nurb) {
773                                                                 col_id |= ACTIVE_NURB;
774                                                         }
775
776                                                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bezt->vec[j * 2]);
777                                                         GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &col_id);
778                                                         vbo_len_used += 1;
779                                                 }
780                                         }
781                                 }
782                         }
783                         else if (nu->bp) {
784                                 int a = 1;
785                                 for (const BPoint *bp_prev = nu->bp, *bp_curr = &nu->bp[1]; a < nu->pntsu; a++, bp_prev = bp_curr++) {
786                                         if ((bp_prev->hide == false) && (bp_curr->hide == false)) {
787                                                 char col_id = ((bp_prev->f1 & SELECT) && (bp_curr->f1 & SELECT)) ? COLOR_NURB_SEL_ULINE_ID : COLOR_NURB_ULINE_ID;
788
789                                                 if (is_active_nurb) {
790                                                         col_id |= ACTIVE_NURB;
791                                                 }
792
793                                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp_prev->vec);
794                                                 vbo_len_used += 1;
795
796                                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, bp_curr->vec);
797                                                 GPU_vertbuf_attr_set(vbo, attr_id.data, vbo_len_used, &col_id);
798                                                 vbo_len_used += 1;
799
800                                         }
801                                 }
802                         }
803                 }
804                 if (vbo_len_capacity != vbo_len_used) {
805                         GPU_vertbuf_data_resize(vbo, vbo_len_used);
806                 }
807
808                 cache->overlay.edges = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
809         }
810
811         curve_render_data_free(rdata);
812 }
813
814 static GPUBatch *curve_batch_cache_get_pos_and_normals(CurveRenderData *rdata, CurveBatchCache *cache)
815 {
816         BLI_assert(rdata->types & CU_DATATYPE_SURFACE);
817         if (cache->surface.batch == NULL) {
818                 ListBase *lb = &rdata->ob_curve_cache->disp;
819
820                 if (cache->surface.verts == NULL) {
821                         cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb);
822                 }
823                 if (cache->surface.triangles_in_order == NULL) {
824                         cache->surface.triangles_in_order = DRW_displist_indexbuf_calc_triangles_in_order(lb);
825                 }
826                 cache->surface.batch = GPU_batch_create(
827                         GPU_PRIM_TRIS, cache->surface.verts, cache->surface.triangles_in_order);
828         }
829
830         return cache->surface.batch;
831 }
832
833 /** \} */
834
835
836 /* -------------------------------------------------------------------- */
837
838 /** \name Private Object/Font Cache API
839  * \{ */
840
841
842 static GPUBatch *curve_batch_cache_get_overlay_select(CurveRenderData *rdata, CurveBatchCache *cache)
843 {
844         BLI_assert(rdata->types & CU_DATATYPE_TEXT_SELECT);
845         if (cache->text.select == NULL) {
846                 EditFont *ef = rdata->text.edit_font;
847                 static GPUVertFormat format = { 0 };
848                 static struct { uint pos; } attr_id;
849                 if (format.attr_len == 0) {
850                         attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
851                 }
852
853                 GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
854                 const int vbo_len_capacity = ef->selboxes_len * 6;
855                 int vbo_len_used = 0;
856                 GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
857
858                 float box[4][3];
859
860                 /* fill in xy below */
861                 box[0][2] = box[1][2] = box[2][2] = box[3][2] = 0.001;
862
863                 for (int i = 0; i < ef->selboxes_len; i++) {
864                         EditFontSelBox *sb = &ef->selboxes[i];
865
866                         float selboxw;
867                         if (i + 1 != ef->selboxes_len) {
868                                 if (ef->selboxes[i + 1].y == sb->y)
869                                         selboxw = ef->selboxes[i + 1].x - sb->x;
870                                 else
871                                         selboxw = sb->w;
872                         }
873                         else {
874                                 selboxw = sb->w;
875                         }
876
877                         if (sb->rot == 0.0f) {
878                                 copy_v2_fl2(box[0], sb->x, sb->y);
879                                 copy_v2_fl2(box[1], sb->x + selboxw, sb->y);
880                                 copy_v2_fl2(box[2], sb->x + selboxw, sb->y + sb->h);
881                                 copy_v2_fl2(box[3], sb->x, sb->y + sb->h);
882                         }
883                         else {
884                                 float mat[2][2];
885
886                                 angle_to_mat2(mat, sb->rot);
887
888                                 copy_v2_fl2(box[0], sb->x, sb->y);
889
890                                 copy_v2_fl2(box[1], selboxw, 0.0f);
891                                 mul_m2v2(mat, box[1]);
892                                 add_v2_v2(box[1], &sb->x);
893
894                                 copy_v2_fl2(box[2], selboxw, sb->h);
895                                 mul_m2v2(mat, box[2]);
896                                 add_v2_v2(box[2], &sb->x);
897
898                                 copy_v2_fl2(box[3], 0.0f, sb->h);
899                                 mul_m2v2(mat, box[3]);
900                                 add_v2_v2(box[3], &sb->x);
901                         }
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[1]);
905                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[2]);
906
907                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[0]);
908                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[2]);
909                         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used++, box[3]);
910                 }
911                 BLI_assert(vbo_len_used == vbo_len_capacity);
912                 cache->text.select = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
913         }
914         return cache->text.select;
915 }
916
917 static GPUBatch *curve_batch_cache_get_overlay_cursor(CurveRenderData *rdata, CurveBatchCache *cache)
918 {
919         BLI_assert(rdata->types & CU_DATATYPE_TEXT_SELECT);
920         if (cache->text.cursor == NULL) {
921                 static GPUVertFormat format = { 0 };
922                 static struct { uint pos; } attr_id;
923                 if (format.attr_len == 0) {
924                         attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
925                 }
926
927                 GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
928                 const int vbo_len_capacity = 4;
929                 GPU_vertbuf_data_alloc(vbo, vbo_len_capacity);
930                 for (int i = 0; i < 4; i++) {
931                         GPU_vertbuf_attr_set(vbo, attr_id.pos, i, rdata->text.edit_font->textcurs[i]);
932                 }
933                 cache->text.cursor = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO);
934         }
935         return cache->text.cursor;
936 }
937
938 /** \} */
939
940 /* -------------------------------------------------------------------- */
941
942 /** \name Public Object/Curve API
943  * \{ */
944
945 GPUBatch *DRW_curve_batch_cache_get_wire_edge(Curve *cu, CurveCache *ob_curve_cache)
946 {
947         CurveBatchCache *cache = curve_batch_cache_get(cu);
948
949         if (cache->wire.batch == NULL) {
950                 /* create batch from Curve */
951                 CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_WIRE);
952
953                 cache->wire.batch = GPU_batch_create(
954                         GPU_PRIM_LINES,
955                         curve_batch_cache_get_wire_verts(rdata, cache),
956                         curve_batch_cache_get_wire_edges(rdata, cache));
957
958                 curve_render_data_free(rdata);
959         }
960         return cache->wire.batch;
961 }
962
963 GPUBatch *DRW_curve_batch_cache_get_normal_edge(Curve *cu, CurveCache *ob_curve_cache, float normal_size)
964 {
965         CurveBatchCache *cache = curve_batch_cache_get(cu);
966
967         if (cache->normal.batch != NULL) {
968                 cache->normal_size = normal_size;
969                 if (cache->normal_size != normal_size) {
970                         GPU_BATCH_DISCARD_SAFE(cache->normal.batch);
971                         GPU_VERTBUF_DISCARD_SAFE(cache->normal.edges);
972                 }
973         }
974         cache->normal_size = normal_size;
975
976         if (cache->normal.batch == NULL) {
977                 /* create batch from Curve */
978                 CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_NORMAL);
979
980                 cache->normal.batch = GPU_batch_create(
981                         GPU_PRIM_LINES,
982                         curve_batch_cache_get_normal_verts(rdata, cache),
983                         curve_batch_cache_get_normal_edges(rdata, cache));
984
985                 curve_render_data_free(rdata);
986                 cache->normal_size = normal_size;
987         }
988         return cache->normal.batch;
989 }
990
991 GPUBatch *DRW_curve_batch_cache_get_overlay_edges(Curve *cu)
992 {
993         CurveBatchCache *cache = curve_batch_cache_get(cu);
994
995         if (cache->overlay.edges == NULL) {
996                 curve_batch_cache_create_overlay_batches(cu);
997         }
998
999         return cache->overlay.edges;
1000 }
1001
1002 GPUBatch *DRW_curve_batch_cache_get_overlay_verts(Curve *cu)
1003 {
1004         CurveBatchCache *cache = curve_batch_cache_get(cu);
1005
1006         if (cache->overlay.verts == NULL) {
1007                 curve_batch_cache_create_overlay_batches(cu);
1008         }
1009
1010         return cache->overlay.verts;
1011 }
1012
1013 GPUBatch *DRW_curve_batch_cache_get_triangles_with_normals(
1014         struct Curve *cu, struct CurveCache *ob_curve_cache)
1015 {
1016         CurveBatchCache *cache = curve_batch_cache_get(cu);
1017
1018         if (cache->surface.batch == NULL) {
1019                 CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE);
1020
1021                 curve_batch_cache_get_pos_and_normals(rdata, cache);
1022
1023                 curve_render_data_free(rdata);
1024         }
1025
1026         return cache->surface.batch;
1027 }
1028
1029 GPUBatch **DRW_curve_batch_cache_get_surface_shaded(
1030         struct Curve *cu, struct CurveCache *ob_curve_cache,
1031         struct GPUMaterial **UNUSED(gpumat_array), uint gpumat_array_len)
1032 {
1033         CurveBatchCache *cache = curve_batch_cache_get(cu);
1034
1035         if (cache->surface.mat_len != gpumat_array_len) {
1036                 GPU_BATCH_DISCARD_ARRAY_SAFE(cache->surface.shaded_triangles, cache->surface.mat_len);
1037         }
1038
1039         if (cache->surface.shaded_triangles == NULL) {
1040                 CurveRenderData *rdata = curve_render_data_create(cu, ob_curve_cache, CU_DATATYPE_SURFACE);
1041                 ListBase *lb = &rdata->ob_curve_cache->disp;
1042
1043                 cache->surface.mat_len = gpumat_array_len;
1044                 if (cu->flag & CU_UV_ORCO) {
1045                         cache->surface.shaded_triangles = DRW_displist_batch_calc_tri_pos_normals_and_uv_split_by_material(
1046                                 lb, gpumat_array_len);
1047                 }
1048                 else {
1049                         cache->surface.shaded_triangles = MEM_mallocN(
1050                                 sizeof(*cache->surface.shaded_triangles) * gpumat_array_len, __func__);
1051                         GPUIndexBuf **el = DRW_displist_indexbuf_calc_triangles_in_order_split_by_material(
1052                                 lb, gpumat_array_len);
1053
1054                         if (cache->surface.verts == NULL) {
1055                                 cache->surface.verts = DRW_displist_vertbuf_calc_pos_with_normals(lb);
1056                         }
1057
1058                         for (int i = 0; i < gpumat_array_len; ++i) {
1059                                 cache->surface.shaded_triangles[i] = GPU_batch_create_ex(
1060                                         GPU_PRIM_TRIS, cache->surface.verts, el[i], GPU_BATCH_OWNS_INDEX);
1061                         }
1062
1063                         MEM_freeN(el); /* Save `el` in cache? */
1064                 }
1065
1066                 curve_render_data_free(rdata);
1067         }
1068
1069         return cache->surface.shaded_triangles;
1070 }
1071
1072
1073 /* -------------------------------------------------------------------- */
1074
1075 /** \name Public Object/Font API
1076  * \{ */
1077
1078 GPUBatch *DRW_curve_batch_cache_get_overlay_select(Curve *cu)
1079 {
1080         CurveBatchCache *cache = curve_batch_cache_get(cu);
1081
1082         if (cache->text.select == NULL) {
1083                 CurveRenderData *rdata = curve_render_data_create(cu, NULL, CU_DATATYPE_TEXT_SELECT);
1084
1085                 curve_batch_cache_get_overlay_select(rdata, cache);
1086
1087                 curve_render_data_free(rdata);
1088         }
1089
1090         return cache->text.select;
1091 }
1092
1093 GPUBatch *DRW_curve_batch_cache_get_overlay_cursor(Curve *cu)
1094 {
1095         CurveBatchCache *cache = curve_batch_cache_get(cu);
1096
1097         if (cache->text.cursor == NULL) {
1098                 CurveRenderData *rdata = curve_render_data_create(cu, NULL, CU_DATATYPE_TEXT_SELECT);
1099
1100                 curve_batch_cache_get_overlay_cursor(rdata, cache);
1101
1102                 curve_render_data_free(rdata);
1103         }
1104
1105         return cache->text.cursor;
1106 }
1107
1108 /** \} */