doxygen: add newline after \file
[blender.git] / source / blender / draw / intern / draw_cache_impl_curve.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2017 by Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup draw
22  *
23  * \brief Curve API for render engines
24  */
25
26 #include "MEM_guardedalloc.h"
27
28 #include "BLI_utildefines.h"
29 #include "BLI_math_vector.h"
30
31 #include "DNA_curve_types.h"
32
33 #include "BKE_curve.h"
34 #include "BKE_displist.h"
35 #include "BKE_font.h"
36
37 #include "GPU_batch.h"
38 #include "GPU_texture.h"
39 #include "GPU_material.h"
40
41 #include "UI_resources.h"
42
43 #include "DRW_render.h"
44
45 #include "draw_cache_impl.h"  /* own include */
46
47 #define SELECT            1
48 #define ACTIVE_NURB       1 << 2
49 #define EVEN_U_BIT        1 << 3 /* Alternate this bit for every U vert. */
50
51 /* Used as values of `color_id` in `edit_curve_overlay_handle_geom.glsl` */
52 enum {
53         COLOR_NURB_ULINE_ID = TH_HANDLE_AUTOCLAMP - TH_HANDLE_FREE + 2,
54
55         TOT_HANDLE_COL,
56 };
57
58 /**
59  * TODO
60  * - Ensure `CurveCache`, `SEQUENCER_DAG_WORKAROUND`.
61  * - Check number of verts/edges to see if cache is valid.
62  * - Check if 'overlay.edges' can use single attribute per edge, not 2 (for selection drawing).
63  */
64
65 static void curve_batch_cache_clear(Curve *cu);
66
67 /* ---------------------------------------------------------------------- */
68 /* Curve Interface, direct access to basic data. */
69
70 static void curve_render_overlay_verts_edges_len_get(
71         ListBase *lb, int *r_vert_len, int *r_edge_len)
72 {
73         BLI_assert(r_vert_len || r_edge_len);
74         int vert_len = 0;
75         int edge_len = 0;
76         for (Nurb *nu = lb->first; nu; nu = nu->next) {
77                 if (nu->bezt) {
78                         vert_len += nu->pntsu * 3;
79                         /* 2x handles per point*/
80                         edge_len += 2 * nu->pntsu;
81                 }
82                 else if (nu->bp) {
83                         vert_len += nu->pntsu * nu->pntsv;
84                         /* segments between points */
85                         edge_len += (nu->pntsu - 1) * nu->pntsv;
86                         edge_len += (nu->pntsv - 1) * nu->pntsu;
87                 }
88         }
89         if (r_vert_len) {
90                 *r_vert_len = vert_len;
91         }
92         if (r_edge_len) {
93                 *r_edge_len = edge_len;
94         }
95 }
96
97 static void curve_render_wire_verts_edges_len_get(
98         const CurveCache *ob_curve_cache,
99         int *r_curve_len, int *r_vert_len, int *r_edge_len)
100 {
101         BLI_assert(r_vert_len || r_edge_len);
102         int vert_len = 0;
103         int edge_len = 0;
104         int curve_len = 0;
105         for (const BevList *bl = ob_curve_cache->bev.first; bl; bl = bl->next) {
106                 if (bl->nr > 0) {
107                         const bool is_cyclic = bl->poly != -1;
108                         edge_len += (is_cyclic) ? bl->nr : bl->nr - 1;
109                         vert_len += bl->nr;
110                         curve_len += 1;
111                 }
112         }
113         for (const DispList *dl = ob_curve_cache->disp.first; dl; dl = dl->next) {
114                 if (ELEM(dl->type, DL_SEGM, DL_POLY)) {
115                         BLI_assert(dl->parts == 1);
116                         const bool is_cyclic = dl->type == DL_POLY;
117                         edge_len += (is_cyclic) ? dl->nr : dl->nr - 1;
118                         vert_len += dl->nr;
119                         curve_len += 1;
120                 }
121         }
122         if (r_vert_len) {
123                 *r_vert_len = vert_len;
124         }
125         if (r_edge_len) {
126                 *r_edge_len = edge_len;
127         }
128         if (r_curve_len) {
129                 *r_curve_len = curve_len;
130         }
131 }
132
133 static int curve_render_normal_len_get(const ListBase *lb, const CurveCache *ob_curve_cache)
134 {
135         int normal_len = 0;
136         const BevList *bl;
137         const Nurb *nu;
138         for (bl = ob_curve_cache->bev.first, nu = lb->first; nu && bl; bl = bl->next, nu = nu->next) {
139                 int nr = bl->nr;
140                 int skip = nu->resolu / 16;
141 #if 0
142                 while (nr-- > 0) { /* accounts for empty bevel lists */
143                         normal_len += 1;
144                         nr -= skip;
145                 }
146 #else
147                 /* Same as loop above */
148                 normal_len += (nr / (skip + 1)) + ((nr % (skip + 1)) != 0);
149 #endif
150         }
151         return normal_len;
152 }
153
154 /* ---------------------------------------------------------------------- */
155 /* Curve Interface, indirect, partially cached access to complex data. */
156
157 typedef struct CurveRenderData {
158         int types;
159
160         struct {
161                 int vert_len;
162                 int edge_len;
163         } overlay;
164
165         struct {
166                 int curve_len;
167                 int vert_len;
168                 int edge_len;
169         } wire;
170
171         /* edit mode normal's */
172         struct {
173                 /* 'edge_len == len * 2'
174                  * 'vert_len == len * 3' */
175                 int len;
176         } normal;
177
178         struct {
179                 EditFont *edit_font;
180         } text;
181
182         /* borrow from 'Object' */
183         CurveCache *ob_curve_cache;
184
185         /* borrow from 'Curve' */
186         ListBase *nurbs;
187
188         /* edit, index in nurb list */
189         int actnu;
190         /* edit, index in active nurb (BPoint or BezTriple) */
191         int actvert;
192 } CurveRenderData;
193
194 enum {
195         /* Wire center-line */
196         CU_DATATYPE_WIRE        = 1 << 0,
197         /* Edit-mode verts and optionally handles */
198         CU_DATATYPE_OVERLAY     = 1 << 1,
199         /* Edit-mode normals */
200         CU_DATATYPE_NORMAL      = 1 << 2,
201         /* Geometry */
202         CU_DATATYPE_SURFACE     = 1 << 3,
203         /* Text */
204         CU_DATATYPE_TEXT_SELECT = 1 << 4,
205 };
206
207 /*
208  * ob_curve_cache can be NULL, only needed for CU_DATATYPE_WIRE
209  */
210 static CurveRenderData *curve_render_data_create(Curve *cu, CurveCache *ob_curve_cache, const int types)
211 {
212         CurveRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__);
213         rdata->types = types;
214         ListBase *nurbs;
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.curve_len, &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,
234                                 &rdata->overlay.vert_len,
235                                 &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_wire_curve_len_get(const CurveRenderData *rdata)
290 {
291         BLI_assert(rdata->types & CU_DATATYPE_WIRE);
292         return rdata->wire.curve_len;
293 }
294
295 static int curve_render_data_normal_len_get(const CurveRenderData *rdata)
296 {
297         BLI_assert(rdata->types & CU_DATATYPE_NORMAL);
298         return rdata->normal.len;
299 }
300
301 static void curve_cd_calc_used_gpu_layers(int *cd_layers, struct GPUMaterial **gpumat_array, int gpumat_array_len)
302 {
303         GPUVertAttrLayers gpu_attrs = {{{0}}};
304         for (int i = 0; i < gpumat_array_len; i++) {
305                 struct GPUMaterial *gpumat = gpumat_array[i];
306                 if (gpumat == NULL) {
307                         continue;
308                 }
309                 GPU_material_vertex_attrs(gpumat, &gpu_attrs);
310                 for (int j = 0; j < gpu_attrs.totlayer; j++) {
311                         const char *name = gpu_attrs.layer[j].name;
312                         int type = gpu_attrs.layer[j].type;
313
314                         /* Curves cannot have named layers.
315                          * Note: We could relax this assumption later. */
316                         if (name[0] != '\0') {
317                                 continue;
318                         }
319
320                         if (type == CD_AUTO_FROM_NAME) {
321                                 type = CD_MTFACE;
322                         }
323
324                         switch (type) {
325                                 case CD_MTFACE:
326                                         *cd_layers |= CD_MLOOPUV;
327                                         break;
328                                 case CD_TANGENT:
329                                         /* Currently unsupported */
330                                         // *cd_layers |= CD_TANGENT;
331                                         break;
332                                 case CD_MCOL:
333                                         /* Curve object don't have Color data. */
334                                         break;
335                                 case CD_ORCO:
336                                         *cd_layers |= CD_ORCO;
337                                         break;
338                         }
339                 }
340         }
341 }
342
343 /* ---------------------------------------------------------------------- */
344 /* Curve GPUBatch Cache */
345
346 typedef struct CurveBatchCache {
347         struct {
348                 GPUVertBuf *pos_nor;
349                 GPUVertBuf *curves_pos;
350         } ordered;
351
352         struct {
353                 GPUVertBuf *pos_nor;
354                 GPUVertBuf *uv;
355
356                 GPUVertBuf *wireframe_data;
357         } tess;
358
359         struct {
360                 /* Curve points. Aligned with ordered.pos_nor */
361                 GPUVertBuf *curves_nor;
362                 GPUVertBuf *curves_weight; /* TODO. */
363                 /* Edit points (beztriples and bpoints) */
364                 GPUVertBuf *pos;
365                 GPUVertBuf *data;
366         } edit;
367
368         struct {
369                 GPUIndexBuf *surfaces_tris;
370                 GPUIndexBuf *curves_lines;
371                 /* Edit mode */
372                 GPUIndexBuf *edit_verts_points; /* Only control points. Not handles. */
373                 GPUIndexBuf *edit_lines;
374         } ibo;
375
376         struct {
377                 GPUBatch *surfaces;
378                 GPUBatch *curves;
379                 /* control handles and vertices */
380                 GPUBatch *edit_edges;
381                 GPUBatch *edit_verts;
382                 GPUBatch *edit_handles_verts;
383                 GPUBatch *edit_normals;
384                 /* Triangles for object mode wireframe. */
385                 GPUBatch *wire_triangles;
386         } batch;
387
388         GPUIndexBuf **surf_per_mat_tris;
389         GPUBatch **surf_per_mat;
390         int mat_len;
391         int cd_used, cd_needed;
392
393         /* settings to determine if cache is invalid */
394         bool is_dirty;
395         bool is_editmode;
396 } CurveBatchCache;
397
398 /* GPUBatch cache management. */
399
400 static bool curve_batch_cache_valid(Curve *cu)
401 {
402         CurveBatchCache *cache = cu->batch_cache;
403
404         if (cache == NULL) {
405                 return false;
406         }
407
408         if (cache->mat_len != max_ii(1, cu->totcol)) {
409                 return false;
410         }
411
412         if (cache->is_dirty) {
413                 return false;
414         }
415
416         if (cache->is_editmode != ((cu->editnurb != NULL) || (cu->editfont != NULL))) {
417                 return false;
418         }
419
420         if (cache->is_editmode) {
421                 if (cu->editfont) {
422                         /* TODO */
423                 }
424         }
425
426         return true;
427 }
428
429 static void curve_batch_cache_init(Curve *cu)
430 {
431         CurveBatchCache *cache = cu->batch_cache;
432
433         if (!cache) {
434                 cache = cu->batch_cache = MEM_callocN(sizeof(*cache), __func__);
435         }
436         else {
437                 memset(cache, 0, sizeof(*cache));
438         }
439
440 #if 0
441         ListBase *nurbs;
442         if (cu->editnurb) {
443                 EditNurb *editnurb = cu->editnurb;
444                 nurbs = &editnurb->nurbs;
445         }
446         else {
447                 nurbs = &cu->nurb;
448         }
449 #endif
450
451         cache->cd_used = 0;
452         cache->mat_len = max_ii(1, cu->totcol);
453         cache->surf_per_mat_tris = MEM_mallocN(sizeof(*cache->surf_per_mat_tris) * cache->mat_len, __func__);
454         cache->surf_per_mat = MEM_mallocN(sizeof(*cache->surf_per_mat) * cache->mat_len, __func__);
455
456         /* TODO Might be wiser to alloc in one chunck. */
457         for (int i = 0; i < cache->mat_len; ++i) {
458                 cache->surf_per_mat_tris[i] = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
459                 cache->surf_per_mat[i] = MEM_callocN(sizeof(GPUBatch), "GPUBatch");
460         }
461
462         cache->is_editmode = (cu->editnurb != NULL) || (cu->editfont != NULL);
463
464         cache->is_dirty = false;
465 }
466
467 static CurveBatchCache *curve_batch_cache_get(Curve *cu)
468 {
469         if (!curve_batch_cache_valid(cu)) {
470                 curve_batch_cache_clear(cu);
471                 curve_batch_cache_init(cu);
472         }
473         return cu->batch_cache;
474 }
475
476 void DRW_curve_batch_cache_dirty_tag(Curve *cu, int mode)
477 {
478         CurveBatchCache *cache = cu->batch_cache;
479         if (cache == NULL) {
480                 return;
481         }
482         switch (mode) {
483                 case BKE_CURVE_BATCH_DIRTY_ALL:
484                         cache->is_dirty = true;
485                         break;
486                 case BKE_CURVE_BATCH_DIRTY_SELECT:
487                         GPU_VERTBUF_DISCARD_SAFE(cache->edit.data);
488
489                         GPU_BATCH_DISCARD_SAFE(cache->batch.edit_edges);
490                         GPU_BATCH_DISCARD_SAFE(cache->batch.edit_verts);
491                         GPU_BATCH_DISCARD_SAFE(cache->batch.edit_handles_verts);
492                         break;
493                 default:
494                         BLI_assert(0);
495         }
496 }
497
498 static void curve_batch_cache_clear(Curve *cu)
499 {
500         CurveBatchCache *cache = cu->batch_cache;
501         if (!cache) {
502                 return;
503         }
504
505         for (int i = 0; i < sizeof(cache->ordered) / sizeof(void *); ++i) {
506                 GPUVertBuf **vbo = (GPUVertBuf **)&cache->ordered;
507                 GPU_VERTBUF_DISCARD_SAFE(vbo[i]);
508         }
509         for (int i = 0; i < sizeof(cache->tess) / sizeof(void *); ++i) {
510                 GPUVertBuf **vbo = (GPUVertBuf **)&cache->tess;
511                 GPU_VERTBUF_DISCARD_SAFE(vbo[i]);
512         }
513         for (int i = 0; i < sizeof(cache->edit) / sizeof(void *); ++i) {
514                 GPUVertBuf **vbo = (GPUVertBuf **)&cache->edit;
515                 GPU_VERTBUF_DISCARD_SAFE(vbo[i]);
516         }
517         for (int i = 0; i < sizeof(cache->ibo) / sizeof(void *); ++i) {
518                 GPUIndexBuf **ibo = (GPUIndexBuf **)&cache->ibo;
519                 GPU_INDEXBUF_DISCARD_SAFE(ibo[i]);
520         }
521         for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
522                 GPUBatch **batch = (GPUBatch **)&cache->batch;
523                 GPU_BATCH_DISCARD_SAFE(batch[i]);
524         }
525
526         for (int i = 0; i < cache->mat_len; ++i) {
527                 GPU_INDEXBUF_DISCARD_SAFE(cache->surf_per_mat_tris[i]);
528                 GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]);
529         }
530         MEM_SAFE_FREE(cache->surf_per_mat_tris);
531         MEM_SAFE_FREE(cache->surf_per_mat);
532         cache->mat_len = 0;
533         cache->cd_used = 0;
534 }
535
536 void DRW_curve_batch_cache_free(Curve *cu)
537 {
538         curve_batch_cache_clear(cu);
539         MEM_SAFE_FREE(cu->batch_cache);
540 }
541
542 /* -------------------------------------------------------------------- */
543 /** \name Private Curve Cache API
544  * \{ */
545
546 /* GPUBatch cache usage. */
547 static void curve_create_curves_pos(CurveRenderData *rdata, GPUVertBuf *vbo_curves_pos)
548 {
549         BLI_assert(rdata->ob_curve_cache != NULL);
550
551         static GPUVertFormat format = { 0 };
552         static struct { uint pos; } attr_id;
553         if (format.attr_len == 0) {
554                 attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
555         }
556
557         const int vert_len = curve_render_data_wire_verts_len_get(rdata);
558         GPU_vertbuf_init_with_format(vbo_curves_pos, &format);
559         GPU_vertbuf_data_alloc(vbo_curves_pos, vert_len);
560
561         int v_idx = 0;
562         for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) {
563                 if (bl->nr <= 0) {
564                         continue;
565                 }
566                 const int i_end = v_idx + bl->nr;
567                 for (const BevPoint *bevp = bl->bevpoints; v_idx < i_end; v_idx++, bevp++) {
568                         GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, bevp->vec);
569                 }
570         }
571         for (const DispList *dl = rdata->ob_curve_cache->disp.first; dl; dl = dl->next) {
572                 if (ELEM(dl->type, DL_SEGM, DL_POLY)) {
573                         for (int i = 0; i < dl->nr; v_idx++, i++) {
574                                 GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, &((float(*)[3])dl->verts)[i]);
575                         }
576                 }
577         }
578         BLI_assert(v_idx == vert_len);
579 }
580
581 static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_curve_lines)
582 {
583         BLI_assert(rdata->ob_curve_cache != NULL);
584
585         const int vert_len = curve_render_data_wire_verts_len_get(rdata);
586         const int edge_len = curve_render_data_wire_edges_len_get(rdata);
587         const int curve_len = curve_render_data_wire_curve_len_get(rdata);
588         /* Count the last vertex or each strip and the primitive restart. */
589         const int index_len = edge_len + curve_len * 2;
590
591         GPUIndexBufBuilder elb;
592         GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, index_len, vert_len, true);
593
594         int v_idx = 0;
595         for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) {
596                 if (bl->nr <= 0) {
597                         continue;
598                 }
599                 const bool is_cyclic = bl->poly != -1;
600                 if (is_cyclic) {
601                         GPU_indexbuf_add_generic_vert(&elb, v_idx + (bl->nr - 1));
602                 }
603                 for (int i = 0; i < bl->nr; i++) {
604                         GPU_indexbuf_add_generic_vert(&elb, v_idx + i);
605                 }
606                 GPU_indexbuf_add_primitive_restart(&elb);
607                 v_idx += bl->nr;
608         }
609         for (const DispList *dl = rdata->ob_curve_cache->disp.first; dl; dl = dl->next) {
610                 if (ELEM(dl->type, DL_SEGM, DL_POLY)) {
611                         const bool is_cyclic = dl->type == DL_POLY;
612                         if (is_cyclic) {
613                                 GPU_indexbuf_add_generic_vert(&elb, v_idx + (dl->nr - 1));
614                         }
615                         for (int i = 0; i < dl->nr; i++) {
616                                 GPU_indexbuf_add_generic_vert(&elb, v_idx + i);
617                         }
618                         GPU_indexbuf_add_primitive_restart(&elb);
619                         v_idx += dl->nr;
620                 }
621         }
622         GPU_indexbuf_build_in_place(&elb, ibo_curve_lines);
623 }
624
625 static void curve_create_edit_curves_nor(CurveRenderData *rdata, GPUVertBuf *vbo_curves_nor)
626 {
627         static GPUVertFormat format = { 0 };
628         static struct { uint pos, nor, tan, rad; } attr_id;
629         if (format.attr_len == 0) {
630                 /* initialize vertex formats */
631                 attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
632                 attr_id.rad = GPU_vertformat_attr_add(&format, "rad", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
633                 attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
634                 attr_id.tan = GPU_vertformat_attr_add(&format, "tan", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
635         }
636
637         int verts_len_capacity = curve_render_data_normal_len_get(rdata) * 2;
638         int vbo_len_used = 0;
639
640         GPU_vertbuf_init_with_format(vbo_curves_nor, &format);
641         GPU_vertbuf_data_alloc(vbo_curves_nor, verts_len_capacity);
642
643         const BevList *bl;
644         const Nurb *nu;
645
646         for (bl = rdata->ob_curve_cache->bev.first, nu = rdata->nurbs->first;
647              nu && bl;
648              bl = bl->next, nu = nu->next)
649         {
650                 const BevPoint *bevp = bl->bevpoints;
651                 int nr = bl->nr;
652                 int skip = nu->resolu / 16;
653
654                 while (nr-- > 0) { /* accounts for empty bevel lists */
655                         float nor[3] = {1.0f, 0.0f, 0.0f};
656                         mul_qt_v3(bevp->quat, nor);
657
658                         GPUPackedNormal pnor = GPU_normal_convert_i10_v3(nor);
659                         GPUPackedNormal ptan = GPU_normal_convert_i10_v3(bevp->dir);
660
661                         /* Only set attributes for one vertex. */
662                         GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.pos, vbo_len_used, bevp->vec);
663                         GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.rad, vbo_len_used, &bevp->radius);
664                         GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.nor, vbo_len_used, &pnor);
665                         GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.tan, vbo_len_used, &ptan);
666                         vbo_len_used++;
667
668                         /* Skip the other vertex (it does not need to be offseted). */
669                         GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.pos, vbo_len_used, bevp->vec);
670                         vbo_len_used++;
671
672                         bevp += skip + 1;
673                         nr -= skip;
674                 }
675         }
676         BLI_assert(vbo_len_used == verts_len_capacity);
677 }
678
679 static char beztriple_vflag_get(CurveRenderData *rdata, char flag, char col_id, int v_idx, int nu_id)
680 {
681         char vflag = 0;
682         SET_FLAG_FROM_TEST(vflag, (flag & SELECT), VFLAG_VERT_SELECTED);
683         SET_FLAG_FROM_TEST(vflag, (v_idx == rdata->actvert), VFLAG_VERT_ACTIVE);
684         SET_FLAG_FROM_TEST(vflag, (nu_id == rdata->actnu), ACTIVE_NURB);
685         /* handle color id */
686         vflag |= col_id << 4; /* << 4 because of EVEN_U_BIT */
687         return vflag;
688 }
689
690 static char bpoint_vflag_get(CurveRenderData *rdata, char flag, int v_idx, int nu_id, int u)
691 {
692         char vflag = 0;
693         SET_FLAG_FROM_TEST(vflag, (flag & SELECT), VFLAG_VERT_SELECTED);
694         SET_FLAG_FROM_TEST(vflag, (v_idx == rdata->actvert), VFLAG_VERT_ACTIVE);
695         SET_FLAG_FROM_TEST(vflag, (nu_id == rdata->actnu), ACTIVE_NURB);
696         SET_FLAG_FROM_TEST(vflag, ((u % 2) == 0), EVEN_U_BIT);
697         vflag |= COLOR_NURB_ULINE_ID << 4; /* << 4 because of EVEN_U_BIT */
698         return vflag;
699 }
700
701 static void curve_create_edit_data_and_handles(
702         CurveRenderData *rdata,
703         GPUVertBuf *vbo_pos, GPUVertBuf *vbo_data, GPUIndexBuf *ibo_edit_verts_points, GPUIndexBuf *ibo_edit_lines)
704 {
705         static GPUVertFormat format_pos = { 0 };
706         static GPUVertFormat format_data = { 0 };
707         static struct { uint pos, data; } attr_id;
708         if (format_pos.attr_len == 0) {
709                 /* initialize vertex formats */
710                 attr_id.pos = GPU_vertformat_attr_add(&format_pos, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
711                 attr_id.data = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
712         }
713
714         int verts_len_capacity = curve_render_data_overlay_verts_len_get(rdata);
715         int edges_len_capacity = curve_render_data_overlay_edges_len_get(rdata) * 2;
716         int vbo_len_used = 0;
717
718         if (DRW_TEST_ASSIGN_VBO(vbo_pos)) {
719                 GPU_vertbuf_init_with_format(vbo_pos, &format_pos);
720                 GPU_vertbuf_data_alloc(vbo_pos, verts_len_capacity);
721         }
722         if (DRW_TEST_ASSIGN_VBO(vbo_data)) {
723                 GPU_vertbuf_init_with_format(vbo_data, &format_data);
724                 GPU_vertbuf_data_alloc(vbo_data, verts_len_capacity);
725         }
726
727         GPUIndexBufBuilder elb_verts, *elbp_verts = NULL;
728         GPUIndexBufBuilder elb_lines, *elbp_lines = NULL;
729         if (DRW_TEST_ASSIGN_IBO(ibo_edit_verts_points)) {
730                 elbp_verts = &elb_verts;
731                 GPU_indexbuf_init(elbp_verts, GPU_PRIM_POINTS, verts_len_capacity, verts_len_capacity);
732         }
733         if (DRW_TEST_ASSIGN_IBO(ibo_edit_lines)) {
734                 elbp_lines = &elb_lines;
735                 GPU_indexbuf_init(elbp_lines, GPU_PRIM_LINES, edges_len_capacity, verts_len_capacity);
736         }
737
738         int v_idx = 0, nu_id = 0;
739         for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, nu_id++) {
740                 const BezTriple *bezt = nu->bezt;
741                 const BPoint *bp = nu->bp;
742                 if (bezt && bezt->hide == false) {
743                         for (int a = 0; a < nu->pntsu; a++, bezt++) {
744                                 if (elbp_verts) {
745                                         GPU_indexbuf_add_point_vert(elbp_verts, vbo_len_used + 1);
746                                 }
747                                 if (elbp_lines) {
748                                         GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 1, vbo_len_used + 0);
749                                         GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 1, vbo_len_used + 2);
750                                 }
751                                 if (vbo_data) {
752                                         char vflag[3] = {
753                                                 beztriple_vflag_get(rdata, bezt->f1, bezt->h1, v_idx, nu_id),
754                                                 beztriple_vflag_get(rdata, bezt->f2, bezt->h1, v_idx, nu_id),
755                                                 beztriple_vflag_get(rdata, bezt->f3, bezt->h2, v_idx, nu_id),
756                                         };
757                                         for (int j = 0; j < 3; j++) {
758                                                 GPU_vertbuf_attr_set(vbo_data, attr_id.data, vbo_len_used + j, &vflag[j]);
759                                         }
760                                 }
761                                 if (vbo_pos) {
762                                         for (int j = 0; j < 3; j++) {
763                                                 GPU_vertbuf_attr_set(vbo_pos, attr_id.pos, vbo_len_used + j, bezt->vec[j]);
764                                         }
765                                 }
766                                 vbo_len_used += 3;
767                                 v_idx += 1;
768                         }
769                 }
770                 else if (bp) {
771                         int pt_len = nu->pntsu * nu->pntsv;
772                         for (int a = 0; a < pt_len; a++, bp++) {
773                                 int u = (a % nu->pntsu);
774                                 int v = (a / nu->pntsu);
775                                 /* Use indexed rendering for bezier.
776                                  * Specify all points and use indices to hide/show. */
777                                 if (elbp_verts && bp->hide == false) {
778                                         GPU_indexbuf_add_point_vert(elbp_verts, vbo_len_used);
779                                 }
780                                 if (elbp_lines && bp->hide == false) {
781                                         const BPoint *bp_next_u = (u < (nu->pntsu - 1)) ? &nu->bp[a + 1] : NULL;
782                                         const BPoint *bp_next_v = (v < (nu->pntsv - 1)) ? &nu->bp[a + nu->pntsu] : NULL;
783                                         if (bp_next_u && (bp_next_u->hide == false)) {
784                                                 GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used, vbo_len_used + 1);
785                                         }
786                                         if (bp_next_v && (bp_next_v->hide == false)) {
787                                                 GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used, vbo_len_used + nu->pntsu);
788                                         }
789                                 }
790                                 if (vbo_data) {
791                                         char vflag = bpoint_vflag_get(rdata, bp->f1, v_idx, nu_id, u);
792                                         GPU_vertbuf_attr_set(vbo_data, attr_id.data, vbo_len_used, &vflag);
793                                 }
794                                 if (vbo_pos) {
795                                         GPU_vertbuf_attr_set(vbo_pos, attr_id.pos, vbo_len_used, bp->vec);
796                                 }
797                                 vbo_len_used += 1;
798                                 v_idx += 1;
799                         }
800                 }
801         }
802
803         /* Resize & Finish */
804         if (elbp_verts != NULL) {
805                 GPU_indexbuf_build_in_place(elbp_verts, ibo_edit_verts_points);
806         }
807         if (elbp_lines != NULL) {
808                 GPU_indexbuf_build_in_place(elbp_lines, ibo_edit_lines);
809         }
810         if (vbo_len_used != verts_len_capacity) {
811                 if (vbo_pos != NULL) {
812                         GPU_vertbuf_data_resize(vbo_pos, vbo_len_used);
813                 }
814                 if (vbo_data != NULL) {
815                         GPU_vertbuf_data_resize(vbo_data, vbo_len_used);
816                 }
817         }
818 }
819
820 /** \} */
821
822 /* -------------------------------------------------------------------- */
823 /** \name Public Object/Curve API
824  * \{ */
825
826 GPUBatch *DRW_curve_batch_cache_get_wire_edge(Curve *cu)
827 {
828         CurveBatchCache *cache = curve_batch_cache_get(cu);
829         return DRW_batch_request(&cache->batch.curves);
830 }
831
832 GPUBatch *DRW_curve_batch_cache_get_normal_edge(Curve *cu)
833 {
834         CurveBatchCache *cache = curve_batch_cache_get(cu);
835         return DRW_batch_request(&cache->batch.edit_normals);
836 }
837
838 GPUBatch *DRW_curve_batch_cache_get_edit_edges(Curve *cu)
839 {
840         CurveBatchCache *cache = curve_batch_cache_get(cu);
841         return DRW_batch_request(&cache->batch.edit_edges);
842 }
843
844 GPUBatch *DRW_curve_batch_cache_get_edit_verts(Curve *cu, bool handles)
845 {
846         CurveBatchCache *cache = curve_batch_cache_get(cu);
847         if (handles) {
848                 return DRW_batch_request(&cache->batch.edit_handles_verts);
849         }
850         else {
851                 return DRW_batch_request(&cache->batch.edit_verts);
852         }
853 }
854
855 GPUBatch *DRW_curve_batch_cache_get_triangles_with_normals(struct Curve *cu)
856 {
857         CurveBatchCache *cache = curve_batch_cache_get(cu);
858         return DRW_batch_request(&cache->batch.surfaces);
859 }
860
861 GPUBatch **DRW_curve_batch_cache_get_surface_shaded(
862         struct Curve *cu,
863         struct GPUMaterial **gpumat_array, uint gpumat_array_len)
864 {
865         CurveBatchCache *cache = curve_batch_cache_get(cu);
866
867         BLI_assert(gpumat_array_len == cache->mat_len);
868
869         curve_cd_calc_used_gpu_layers(&cache->cd_needed, gpumat_array, gpumat_array_len);
870
871         for (int i = 0; i < cache->mat_len; ++i) {
872                 DRW_batch_request(&cache->surf_per_mat[i]);
873         }
874         return cache->surf_per_mat;
875 }
876
877 GPUBatch *DRW_curve_batch_cache_get_wireframes_face(Curve *cu)
878 {
879         CurveBatchCache *cache = curve_batch_cache_get(cu);
880         return DRW_batch_request(&cache->batch.wire_triangles);
881 }
882
883 /** \} */
884
885 /* -------------------------------------------------------------------- */
886 /** \name Grouped batch generation
887  * \{ */
888
889 void DRW_curve_batch_cache_create_requested(Object *ob)
890 {
891         BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT));
892
893         Curve *cu = ob->data;
894         CurveBatchCache *cache = curve_batch_cache_get(cu);
895
896         /* Verify that all surface batches have needed attribute layers. */
897         /* TODO(fclem): We could be a bit smarter here and only do it per material. */
898         for (int i = 0; i < cache->mat_len; ++i) {
899                 if ((cache->cd_used & cache->cd_needed) != cache->cd_needed) {
900                         /* We can't discard batches at this point as they have been
901                          * referenced for drawing. Just clear them in place. */
902                         GPU_batch_clear(cache->surf_per_mat[i]);
903                         memset(cache->surf_per_mat[i], 0, sizeof(*cache->surf_per_mat[i]));
904                 }
905         }
906         if ((cache->cd_used & cache->cd_needed) != cache->cd_needed) {
907                 cache->cd_used |= cache->cd_needed;
908                 cache->cd_needed = 0;
909         }
910
911         /* Init batches and request VBOs & IBOs */
912         if (DRW_batch_requested(cache->batch.surfaces, GPU_PRIM_TRIS)) {
913                 DRW_ibo_request(cache->batch.surfaces, &cache->ibo.surfaces_tris);
914                 DRW_vbo_request(cache->batch.surfaces, &cache->ordered.pos_nor);
915         }
916         if (DRW_batch_requested(cache->batch.curves, GPU_PRIM_LINE_STRIP)) {
917                 DRW_ibo_request(cache->batch.curves, &cache->ibo.curves_lines);
918                 DRW_vbo_request(cache->batch.curves, &cache->ordered.curves_pos);
919         }
920         if (DRW_batch_requested(cache->batch.wire_triangles, GPU_PRIM_TRIS)) {
921                 DRW_vbo_request(cache->batch.wire_triangles, &cache->tess.pos_nor);
922                 DRW_vbo_request(cache->batch.wire_triangles, &cache->tess.wireframe_data);
923         }
924
925         /* Edit mode */
926         if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) {
927                 DRW_ibo_request(cache->batch.edit_edges, &cache->ibo.edit_lines);
928                 DRW_vbo_request(cache->batch.edit_edges, &cache->edit.pos);
929                 DRW_vbo_request(cache->batch.edit_edges, &cache->edit.data);
930         }
931         if (DRW_batch_requested(cache->batch.edit_verts, GPU_PRIM_POINTS)) {
932                 DRW_ibo_request(cache->batch.edit_verts, &cache->ibo.edit_verts_points);
933                 DRW_vbo_request(cache->batch.edit_verts, &cache->edit.pos);
934                 DRW_vbo_request(cache->batch.edit_verts, &cache->edit.data);
935         }
936         if (DRW_batch_requested(cache->batch.edit_handles_verts, GPU_PRIM_POINTS)) {
937                 DRW_vbo_request(cache->batch.edit_handles_verts, &cache->edit.pos);
938                 DRW_vbo_request(cache->batch.edit_handles_verts, &cache->edit.data);
939         }
940         if (DRW_batch_requested(cache->batch.edit_normals, GPU_PRIM_LINES)) {
941                 DRW_vbo_request(cache->batch.edit_normals, &cache->edit.curves_nor);
942         }
943         for (int i = 0; i < cache->mat_len; ++i) {
944                 if (DRW_batch_requested(cache->surf_per_mat[i], GPU_PRIM_TRIS)) {
945                         if (cache->mat_len > 1) {
946                                 DRW_ibo_request(cache->surf_per_mat[i], &cache->surf_per_mat_tris[i]);
947                         }
948                         if (cache->cd_used & CD_MLOOPUV) {
949                                 DRW_vbo_request(cache->surf_per_mat[i], &cache->tess.uv);
950                         }
951                         DRW_vbo_request(cache->surf_per_mat[i], &cache->tess.pos_nor);
952                 }
953         }
954
955         /* Generate MeshRenderData flags */
956         int mr_flag = 0;
957         DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.pos_nor, CU_DATATYPE_SURFACE);
958         DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.curves_pos, CU_DATATYPE_WIRE);
959         DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->tess.pos_nor, CU_DATATYPE_SURFACE);
960         DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->tess.uv, CU_DATATYPE_SURFACE);
961         DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->tess.wireframe_data, CU_DATATYPE_SURFACE);
962         DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.surfaces_tris, CU_DATATYPE_SURFACE);
963         DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.curves_lines, CU_DATATYPE_WIRE);
964
965         DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.pos, CU_DATATYPE_OVERLAY);
966         DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.data, CU_DATATYPE_OVERLAY);
967         DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.curves_nor, CU_DATATYPE_NORMAL);
968         DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.curves_weight, CU_DATATYPE_OVERLAY);
969         DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_verts_points, CU_DATATYPE_OVERLAY);
970         DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_lines, CU_DATATYPE_OVERLAY);
971
972         for (int i = 0; i < cache->mat_len; ++i) {
973                 DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->surf_per_mat_tris[i], CU_DATATYPE_SURFACE);
974         }
975
976         CurveRenderData *rdata = curve_render_data_create(cu, ob->runtime.curve_cache, mr_flag);
977
978         /* DispLists */
979         ListBase *lb = &rdata->ob_curve_cache->disp;
980
981         /* Generate VBOs */
982         if (DRW_vbo_requested(cache->ordered.pos_nor)) {
983                 DRW_displist_vertbuf_create_pos_and_nor(lb, cache->ordered.pos_nor);
984         }
985         if (DRW_vbo_requested(cache->ordered.curves_pos)) {
986                 curve_create_curves_pos(rdata, cache->ordered.curves_pos);
987         }
988
989         if (DRW_vbo_requested(cache->tess.pos_nor) ||
990             DRW_vbo_requested(cache->tess.uv))
991         {
992                 DRW_displist_vertbuf_create_pos_and_nor_and_uv_tess(lb, cache->tess.pos_nor, cache->tess.uv);
993         }
994         if (DRW_vbo_requested(cache->tess.wireframe_data)) {
995                 DRW_displist_vertbuf_create_wireframe_data_tess(lb, cache->tess.wireframe_data);
996         }
997
998         if (DRW_ibo_requested(cache->surf_per_mat_tris[0])) {
999                 DRW_displist_indexbuf_create_triangles_tess_split_by_material(lb, cache->surf_per_mat_tris, cache->mat_len);
1000         }
1001
1002         if (DRW_ibo_requested(cache->ibo.curves_lines)) {
1003                 curve_create_curves_lines(rdata, cache->ibo.curves_lines);
1004         }
1005         if (DRW_ibo_requested(cache->ibo.surfaces_tris)) {
1006                 DRW_displist_indexbuf_create_triangles_in_order(lb, cache->ibo.surfaces_tris);
1007         }
1008
1009         if (DRW_vbo_requested(cache->edit.pos) ||
1010             DRW_vbo_requested(cache->edit.data) ||
1011             DRW_ibo_requested(cache->ibo.edit_verts_points) ||
1012             DRW_ibo_requested(cache->ibo.edit_lines))
1013         {
1014                 curve_create_edit_data_and_handles(rdata, cache->edit.pos, cache->edit.data,
1015                                                           cache->ibo.edit_verts_points, cache->ibo.edit_lines);
1016         }
1017         if (DRW_vbo_requested(cache->edit.curves_nor)) {
1018                 curve_create_edit_curves_nor(rdata, cache->edit.curves_nor);
1019         }
1020
1021         curve_render_data_free(rdata);
1022
1023 #ifdef DEBUG
1024         /* Make sure all requested batches have been setup. */
1025         for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
1026                 BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0));
1027         }
1028 #endif
1029 }
1030
1031 /** \} */