Cleanup: misc spelling fixes
[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_inline.h"
46
47 #include "draw_cache_impl.h" /* own include */
48
49 #define SELECT 1
50 #define ACTIVE_NURB 1 << 2
51 #define EVEN_U_BIT 1 << 3 /* Alternate this bit for every U vert. */
52
53 /* Used as values of `color_id` in `edit_curve_overlay_handle_geom.glsl` */
54 enum {
55   COLOR_NURB_ULINE_ID = TH_HANDLE_AUTOCLAMP - TH_HANDLE_FREE + 2,
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(ListBase *lb,
73                                                      int *r_vert_len,
74                                                      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 += 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 * nu->pntsv;
87       /* segments between points */
88       edge_len += (nu->pntsu - 1) * nu->pntsv;
89       edge_len += (nu->pntsv - 1) * nu->pntsu;
90     }
91   }
92   if (r_vert_len) {
93     *r_vert_len = vert_len;
94   }
95   if (r_edge_len) {
96     *r_edge_len = edge_len;
97   }
98 }
99
100 static void curve_render_wire_verts_edges_len_get(const CurveCache *ob_curve_cache,
101                                                   int *r_curve_len,
102                                                   int *r_vert_len,
103                                                   int *r_edge_len)
104 {
105   BLI_assert(r_vert_len || r_edge_len);
106   int vert_len = 0;
107   int edge_len = 0;
108   int curve_len = 0;
109   for (const BevList *bl = ob_curve_cache->bev.first; bl; bl = bl->next) {
110     if (bl->nr > 0) {
111       const bool is_cyclic = bl->poly != -1;
112       edge_len += (is_cyclic) ? bl->nr : bl->nr - 1;
113       vert_len += bl->nr;
114       curve_len += 1;
115     }
116   }
117   for (const DispList *dl = ob_curve_cache->disp.first; dl; dl = dl->next) {
118     if (ELEM(dl->type, DL_SEGM, DL_POLY)) {
119       BLI_assert(dl->parts == 1);
120       const bool is_cyclic = dl->type == DL_POLY;
121       edge_len += (is_cyclic) ? dl->nr : dl->nr - 1;
122       vert_len += dl->nr;
123       curve_len += 1;
124     }
125   }
126   if (r_vert_len) {
127     *r_vert_len = vert_len;
128   }
129   if (r_edge_len) {
130     *r_edge_len = edge_len;
131   }
132   if (r_curve_len) {
133     *r_curve_len = curve_len;
134   }
135 }
136
137 static int curve_render_normal_len_get(const ListBase *lb, const CurveCache *ob_curve_cache)
138 {
139   int normal_len = 0;
140   const BevList *bl;
141   const Nurb *nu;
142   for (bl = ob_curve_cache->bev.first, nu = lb->first; nu && bl; bl = bl->next, nu = nu->next) {
143     int nr = bl->nr;
144     int skip = nu->resolu / 16;
145 #if 0
146     while (nr-- > 0) { /* accounts for empty bevel lists */
147       normal_len += 1;
148       nr -= skip;
149     }
150 #else
151     /* Same as loop above */
152     normal_len += (nr / (skip + 1)) + ((nr % (skip + 1)) != 0);
153 #endif
154   }
155   return normal_len;
156 }
157
158 /* ---------------------------------------------------------------------- */
159 /* Curve Interface, indirect, partially cached access to complex data. */
160
161 typedef struct CurveRenderData {
162   int types;
163
164   struct {
165     int vert_len;
166     int edge_len;
167   } overlay;
168
169   struct {
170     int curve_len;
171     int vert_len;
172     int edge_len;
173   } wire;
174
175   /* edit mode normal's */
176   struct {
177     /* 'edge_len == len * 2'
178      * 'vert_len == len * 3' */
179     int len;
180   } normal;
181
182   struct {
183     EditFont *edit_font;
184   } text;
185
186   /* borrow from 'Object' */
187   CurveCache *ob_curve_cache;
188
189   /* borrow from 'Curve' */
190   ListBase *nurbs;
191
192   /* edit, index in nurb list */
193   int actnu;
194   /* edit, index in active nurb (BPoint or BezTriple) */
195   int actvert;
196 } CurveRenderData;
197
198 enum {
199   /* Wire center-line */
200   CU_DATATYPE_WIRE = 1 << 0,
201   /* Edit-mode verts and optionally handles */
202   CU_DATATYPE_OVERLAY = 1 << 1,
203   /* Edit-mode normals */
204   CU_DATATYPE_NORMAL = 1 << 2,
205   /* Geometry */
206   CU_DATATYPE_SURFACE = 1 << 3,
207   /* Text */
208   CU_DATATYPE_TEXT_SELECT = 1 << 4,
209 };
210
211 /*
212  * ob_curve_cache can be NULL, only needed for CU_DATATYPE_WIRE
213  */
214 static CurveRenderData *curve_render_data_create(Curve *cu,
215                                                  CurveCache *ob_curve_cache,
216                                                  const int types)
217 {
218   CurveRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__);
219   rdata->types = types;
220   ListBase *nurbs;
221
222   rdata->actnu = cu->actnu;
223   rdata->actvert = cu->actvert;
224
225   rdata->ob_curve_cache = ob_curve_cache;
226
227   if (types & CU_DATATYPE_WIRE) {
228     curve_render_wire_verts_edges_len_get(rdata->ob_curve_cache,
229                                           &rdata->wire.curve_len,
230                                           &rdata->wire.vert_len,
231                                           &rdata->wire.edge_len);
232   }
233
234   if (cu->editnurb) {
235     EditNurb *editnurb = cu->editnurb;
236     nurbs = &editnurb->nurbs;
237
238     if (types & CU_DATATYPE_OVERLAY) {
239       curve_render_overlay_verts_edges_len_get(
240           nurbs, &rdata->overlay.vert_len, &rdata->overlay.edge_len);
241
242       rdata->actnu = cu->actnu;
243       rdata->actvert = cu->actvert;
244     }
245     if (types & CU_DATATYPE_NORMAL) {
246       rdata->normal.len = curve_render_normal_len_get(nurbs, rdata->ob_curve_cache);
247     }
248   }
249   else {
250     nurbs = &cu->nurb;
251   }
252
253   rdata->nurbs = nurbs;
254
255   rdata->text.edit_font = cu->editfont;
256
257   return rdata;
258 }
259
260 static void curve_render_data_free(CurveRenderData *rdata)
261 {
262 #if 0
263   if (rdata->loose_verts) {
264     MEM_freeN(rdata->loose_verts);
265   }
266 #endif
267   MEM_freeN(rdata);
268 }
269
270 static int curve_render_data_overlay_verts_len_get(const CurveRenderData *rdata)
271 {
272   BLI_assert(rdata->types & CU_DATATYPE_OVERLAY);
273   return rdata->overlay.vert_len;
274 }
275
276 static int curve_render_data_overlay_edges_len_get(const CurveRenderData *rdata)
277 {
278   BLI_assert(rdata->types & CU_DATATYPE_OVERLAY);
279   return rdata->overlay.edge_len;
280 }
281
282 static int curve_render_data_wire_verts_len_get(const CurveRenderData *rdata)
283 {
284   BLI_assert(rdata->types & CU_DATATYPE_WIRE);
285   return rdata->wire.vert_len;
286 }
287
288 static int curve_render_data_wire_edges_len_get(const CurveRenderData *rdata)
289 {
290   BLI_assert(rdata->types & CU_DATATYPE_WIRE);
291   return rdata->wire.edge_len;
292 }
293
294 static int curve_render_data_wire_curve_len_get(const CurveRenderData *rdata)
295 {
296   BLI_assert(rdata->types & CU_DATATYPE_WIRE);
297   return rdata->wire.curve_len;
298 }
299
300 static int curve_render_data_normal_len_get(const CurveRenderData *rdata)
301 {
302   BLI_assert(rdata->types & CU_DATATYPE_NORMAL);
303   return rdata->normal.len;
304 }
305
306 static void curve_cd_calc_used_gpu_layers(int *cd_layers,
307                                           struct GPUMaterial **gpumat_array,
308                                           int gpumat_array_len)
309 {
310   GPUVertAttrLayers gpu_attrs = {{{0}}};
311   for (int i = 0; i < gpumat_array_len; i++) {
312     struct GPUMaterial *gpumat = gpumat_array[i];
313     if (gpumat == NULL) {
314       continue;
315     }
316     GPU_material_vertex_attrs(gpumat, &gpu_attrs);
317     for (int j = 0; j < gpu_attrs.totlayer; j++) {
318       const char *name = gpu_attrs.layer[j].name;
319       int type = gpu_attrs.layer[j].type;
320
321       /* Curves cannot have named layers.
322        * Note: We could relax this assumption later. */
323       if (name[0] != '\0') {
324         continue;
325       }
326
327       if (type == CD_AUTO_FROM_NAME) {
328         type = CD_MTFACE;
329       }
330
331       switch (type) {
332         case CD_MTFACE:
333           *cd_layers |= CD_MLOOPUV;
334           break;
335         case CD_TANGENT:
336           /* Currently unsupported */
337           // *cd_layers |= CD_TANGENT;
338           break;
339         case CD_MCOL:
340           /* Curve object don't have Color data. */
341           break;
342         case CD_ORCO:
343           *cd_layers |= CD_ORCO;
344           break;
345       }
346     }
347   }
348 }
349
350 /* ---------------------------------------------------------------------- */
351 /* Curve GPUBatch Cache */
352
353 typedef struct CurveBatchCache {
354   struct {
355     GPUVertBuf *pos_nor;
356     GPUVertBuf *edge_fac;
357     GPUVertBuf *curves_pos;
358
359     GPUVertBuf *loop_pos_nor;
360     GPUVertBuf *loop_uv;
361   } ordered;
362
363   struct {
364     /* Curve points. Aligned with ordered.pos_nor */
365     GPUVertBuf *curves_nor;
366     GPUVertBuf *curves_weight; /* TODO. */
367     /* Edit points (beztriples and bpoints) */
368     GPUVertBuf *pos;
369     GPUVertBuf *data;
370   } edit;
371
372   struct {
373     GPUIndexBuf *surfaces_tris;
374     GPUIndexBuf *surfaces_lines;
375     GPUIndexBuf *curves_lines;
376     GPUIndexBuf *edges_adj_lines;
377     /* Edit mode */
378     GPUIndexBuf *edit_verts_points; /* Only control points. Not handles. */
379     GPUIndexBuf *edit_lines;
380   } ibo;
381
382   struct {
383     GPUBatch *surfaces;
384     GPUBatch *surfaces_edges;
385     GPUBatch *curves;
386     /* control handles and vertices */
387     GPUBatch *edit_edges;
388     GPUBatch *edit_verts;
389     GPUBatch *edit_handles_verts;
390     GPUBatch *edit_normals;
391     GPUBatch *edge_detection;
392   } batch;
393
394   GPUIndexBuf **surf_per_mat_tris;
395   GPUBatch **surf_per_mat;
396   int mat_len;
397   int cd_used, cd_needed;
398
399   /* settings to determine if cache is invalid */
400   bool is_dirty;
401   bool is_editmode;
402
403   /* Valid only if edge_detection is up to date. */
404   bool is_manifold;
405 } CurveBatchCache;
406
407 /* GPUBatch cache management. */
408
409 static bool curve_batch_cache_valid(Curve *cu)
410 {
411   CurveBatchCache *cache = cu->batch_cache;
412
413   if (cache == NULL) {
414     return false;
415   }
416
417   if (cache->mat_len != max_ii(1, cu->totcol)) {
418     return false;
419   }
420
421   if (cache->is_dirty) {
422     return false;
423   }
424
425   if (cache->is_editmode != ((cu->editnurb != NULL) || (cu->editfont != NULL))) {
426     return false;
427   }
428
429   if (cache->is_editmode) {
430     if (cu->editfont) {
431       /* TODO */
432     }
433   }
434
435   return true;
436 }
437
438 static void curve_batch_cache_init(Curve *cu)
439 {
440   CurveBatchCache *cache = cu->batch_cache;
441
442   if (!cache) {
443     cache = cu->batch_cache = MEM_callocN(sizeof(*cache), __func__);
444   }
445   else {
446     memset(cache, 0, sizeof(*cache));
447   }
448
449 #if 0
450   ListBase *nurbs;
451   if (cu->editnurb) {
452     EditNurb *editnurb = cu->editnurb;
453     nurbs = &editnurb->nurbs;
454   }
455   else {
456     nurbs = &cu->nurb;
457   }
458 #endif
459
460   cache->cd_used = 0;
461   cache->mat_len = max_ii(1, cu->totcol);
462   cache->surf_per_mat_tris = MEM_mallocN(sizeof(*cache->surf_per_mat_tris) * cache->mat_len,
463                                          __func__);
464   cache->surf_per_mat = MEM_mallocN(sizeof(*cache->surf_per_mat) * cache->mat_len, __func__);
465
466   /* TODO Might be wiser to alloc in one chunk. */
467   for (int i = 0; i < cache->mat_len; ++i) {
468     cache->surf_per_mat_tris[i] = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf");
469     cache->surf_per_mat[i] = MEM_callocN(sizeof(GPUBatch), "GPUBatch");
470   }
471
472   cache->is_editmode = (cu->editnurb != NULL) || (cu->editfont != NULL);
473
474   cache->is_dirty = false;
475 }
476
477 void DRW_curve_batch_cache_validate(Curve *cu)
478 {
479   if (!curve_batch_cache_valid(cu)) {
480     curve_batch_cache_clear(cu);
481     curve_batch_cache_init(cu);
482   }
483 }
484
485 static CurveBatchCache *curve_batch_cache_get(Curve *cu)
486 {
487   return cu->batch_cache;
488 }
489
490 void DRW_curve_batch_cache_dirty_tag(Curve *cu, int mode)
491 {
492   CurveBatchCache *cache = cu->batch_cache;
493   if (cache == NULL) {
494     return;
495   }
496   switch (mode) {
497     case BKE_CURVE_BATCH_DIRTY_ALL:
498       cache->is_dirty = true;
499       break;
500     case BKE_CURVE_BATCH_DIRTY_SELECT:
501       GPU_VERTBUF_DISCARD_SAFE(cache->edit.data);
502
503       GPU_BATCH_DISCARD_SAFE(cache->batch.edit_edges);
504       GPU_BATCH_DISCARD_SAFE(cache->batch.edit_verts);
505       GPU_BATCH_DISCARD_SAFE(cache->batch.edit_handles_verts);
506       break;
507     default:
508       BLI_assert(0);
509   }
510 }
511
512 static void curve_batch_cache_clear(Curve *cu)
513 {
514   CurveBatchCache *cache = cu->batch_cache;
515   if (!cache) {
516     return;
517   }
518
519   for (int i = 0; i < sizeof(cache->ordered) / sizeof(void *); ++i) {
520     GPUVertBuf **vbo = (GPUVertBuf **)&cache->ordered;
521     GPU_VERTBUF_DISCARD_SAFE(vbo[i]);
522   }
523   for (int i = 0; i < sizeof(cache->edit) / sizeof(void *); ++i) {
524     GPUVertBuf **vbo = (GPUVertBuf **)&cache->edit;
525     GPU_VERTBUF_DISCARD_SAFE(vbo[i]);
526   }
527   for (int i = 0; i < sizeof(cache->ibo) / sizeof(void *); ++i) {
528     GPUIndexBuf **ibo = (GPUIndexBuf **)&cache->ibo;
529     GPU_INDEXBUF_DISCARD_SAFE(ibo[i]);
530   }
531   for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
532     GPUBatch **batch = (GPUBatch **)&cache->batch;
533     GPU_BATCH_DISCARD_SAFE(batch[i]);
534   }
535
536   for (int i = 0; i < cache->mat_len; ++i) {
537     GPU_INDEXBUF_DISCARD_SAFE(cache->surf_per_mat_tris[i]);
538     GPU_BATCH_DISCARD_SAFE(cache->surf_per_mat[i]);
539   }
540   MEM_SAFE_FREE(cache->surf_per_mat_tris);
541   MEM_SAFE_FREE(cache->surf_per_mat);
542   cache->mat_len = 0;
543   cache->cd_used = 0;
544 }
545
546 void DRW_curve_batch_cache_free(Curve *cu)
547 {
548   curve_batch_cache_clear(cu);
549   MEM_SAFE_FREE(cu->batch_cache);
550 }
551
552 /* -------------------------------------------------------------------- */
553 /** \name Private Curve Cache API
554  * \{ */
555
556 /* GPUBatch cache usage. */
557 static void curve_create_curves_pos(CurveRenderData *rdata, GPUVertBuf *vbo_curves_pos)
558 {
559   BLI_assert(rdata->ob_curve_cache != NULL);
560
561   static GPUVertFormat format = {0};
562   static struct {
563     uint pos;
564   } attr_id;
565   if (format.attr_len == 0) {
566     attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
567   }
568
569   const int vert_len = curve_render_data_wire_verts_len_get(rdata);
570   GPU_vertbuf_init_with_format(vbo_curves_pos, &format);
571   GPU_vertbuf_data_alloc(vbo_curves_pos, vert_len);
572
573   int v_idx = 0;
574   for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) {
575     if (bl->nr <= 0) {
576       continue;
577     }
578     const int i_end = v_idx + bl->nr;
579     for (const BevPoint *bevp = bl->bevpoints; v_idx < i_end; v_idx++, bevp++) {
580       GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, bevp->vec);
581     }
582   }
583   for (const DispList *dl = rdata->ob_curve_cache->disp.first; dl; dl = dl->next) {
584     if (ELEM(dl->type, DL_SEGM, DL_POLY)) {
585       for (int i = 0; i < dl->nr; v_idx++, i++) {
586         GPU_vertbuf_attr_set(vbo_curves_pos, attr_id.pos, v_idx, &((float(*)[3])dl->verts)[i]);
587       }
588     }
589   }
590   BLI_assert(v_idx == vert_len);
591 }
592
593 static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_curve_lines)
594 {
595   BLI_assert(rdata->ob_curve_cache != NULL);
596
597   const int vert_len = curve_render_data_wire_verts_len_get(rdata);
598   const int edge_len = curve_render_data_wire_edges_len_get(rdata);
599   const int curve_len = curve_render_data_wire_curve_len_get(rdata);
600   /* Count the last vertex or each strip and the primitive restart. */
601   const int index_len = edge_len + curve_len * 2;
602
603   GPUIndexBufBuilder elb;
604   GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, index_len, vert_len);
605
606   int v_idx = 0;
607   for (const BevList *bl = rdata->ob_curve_cache->bev.first; bl; bl = bl->next) {
608     if (bl->nr <= 0) {
609       continue;
610     }
611     const bool is_cyclic = bl->poly != -1;
612     if (is_cyclic) {
613       GPU_indexbuf_add_generic_vert(&elb, v_idx + (bl->nr - 1));
614     }
615     for (int i = 0; i < bl->nr; i++) {
616       GPU_indexbuf_add_generic_vert(&elb, v_idx + i);
617     }
618     GPU_indexbuf_add_primitive_restart(&elb);
619     v_idx += bl->nr;
620   }
621   for (const DispList *dl = rdata->ob_curve_cache->disp.first; dl; dl = dl->next) {
622     if (ELEM(dl->type, DL_SEGM, DL_POLY)) {
623       const bool is_cyclic = dl->type == DL_POLY;
624       if (is_cyclic) {
625         GPU_indexbuf_add_generic_vert(&elb, v_idx + (dl->nr - 1));
626       }
627       for (int i = 0; i < dl->nr; i++) {
628         GPU_indexbuf_add_generic_vert(&elb, v_idx + i);
629       }
630       GPU_indexbuf_add_primitive_restart(&elb);
631       v_idx += dl->nr;
632     }
633   }
634   GPU_indexbuf_build_in_place(&elb, ibo_curve_lines);
635 }
636
637 static void curve_create_edit_curves_nor(CurveRenderData *rdata, GPUVertBuf *vbo_curves_nor)
638 {
639   static GPUVertFormat format = {0};
640   static struct {
641     uint pos, nor, tan, rad;
642   } attr_id;
643   if (format.attr_len == 0) {
644     /* initialize vertex formats */
645     attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
646     attr_id.rad = GPU_vertformat_attr_add(&format, "rad", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
647     attr_id.nor = GPU_vertformat_attr_add(
648         &format, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
649     attr_id.tan = GPU_vertformat_attr_add(
650         &format, "tan", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
651   }
652
653   int verts_len_capacity = curve_render_data_normal_len_get(rdata) * 2;
654   int vbo_len_used = 0;
655
656   GPU_vertbuf_init_with_format(vbo_curves_nor, &format);
657   GPU_vertbuf_data_alloc(vbo_curves_nor, verts_len_capacity);
658
659   const BevList *bl;
660   const Nurb *nu;
661
662   for (bl = rdata->ob_curve_cache->bev.first, nu = rdata->nurbs->first; nu && bl;
663        bl = bl->next, nu = nu->next) {
664     const BevPoint *bevp = bl->bevpoints;
665     int nr = bl->nr;
666     int skip = nu->resolu / 16;
667
668     while (nr-- > 0) { /* accounts for empty bevel lists */
669       float nor[3] = {1.0f, 0.0f, 0.0f};
670       mul_qt_v3(bevp->quat, nor);
671
672       GPUPackedNormal pnor = GPU_normal_convert_i10_v3(nor);
673       GPUPackedNormal ptan = GPU_normal_convert_i10_v3(bevp->dir);
674
675       /* Only set attributes for one vertex. */
676       GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.pos, vbo_len_used, bevp->vec);
677       GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.rad, vbo_len_used, &bevp->radius);
678       GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.nor, vbo_len_used, &pnor);
679       GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.tan, vbo_len_used, &ptan);
680       vbo_len_used++;
681
682       /* Skip the other vertex (it does not need to be offsetted). */
683       GPU_vertbuf_attr_set(vbo_curves_nor, attr_id.pos, vbo_len_used, bevp->vec);
684       vbo_len_used++;
685
686       bevp += skip + 1;
687       nr -= skip;
688     }
689   }
690   BLI_assert(vbo_len_used == verts_len_capacity);
691 }
692
693 static char beztriple_vflag_get(
694     CurveRenderData *rdata, char flag, char col_id, int v_idx, int nu_id)
695 {
696   char vflag = 0;
697   SET_FLAG_FROM_TEST(vflag, (flag & SELECT), VFLAG_VERT_SELECTED);
698   SET_FLAG_FROM_TEST(vflag, (v_idx == rdata->actvert && nu_id == rdata->actnu), VFLAG_VERT_ACTIVE);
699   SET_FLAG_FROM_TEST(vflag, (nu_id == rdata->actnu), ACTIVE_NURB);
700   /* handle color id */
701   vflag |= col_id << 4; /* << 4 because of EVEN_U_BIT */
702   return vflag;
703 }
704
705 static char bpoint_vflag_get(CurveRenderData *rdata, char flag, int v_idx, int nu_id, int u)
706 {
707   char vflag = 0;
708   SET_FLAG_FROM_TEST(vflag, (flag & SELECT), VFLAG_VERT_SELECTED);
709   SET_FLAG_FROM_TEST(vflag, (v_idx == rdata->actvert && nu_id == rdata->actnu), VFLAG_VERT_ACTIVE);
710   SET_FLAG_FROM_TEST(vflag, (nu_id == rdata->actnu), ACTIVE_NURB);
711   SET_FLAG_FROM_TEST(vflag, ((u % 2) == 0), EVEN_U_BIT);
712   vflag |= COLOR_NURB_ULINE_ID << 4; /* << 4 because of EVEN_U_BIT */
713   return vflag;
714 }
715
716 static void curve_create_edit_data_and_handles(CurveRenderData *rdata,
717                                                GPUVertBuf *vbo_pos,
718                                                GPUVertBuf *vbo_data,
719                                                GPUIndexBuf *ibo_edit_verts_points,
720                                                GPUIndexBuf *ibo_edit_lines)
721 {
722   static GPUVertFormat format_pos = {0};
723   static GPUVertFormat format_data = {0};
724   static struct {
725     uint pos, data;
726   } attr_id;
727   if (format_pos.attr_len == 0) {
728     /* initialize vertex formats */
729     attr_id.pos = GPU_vertformat_attr_add(&format_pos, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
730     attr_id.data = GPU_vertformat_attr_add(&format_data, "data", GPU_COMP_U8, 1, GPU_FETCH_INT);
731   }
732
733   int verts_len_capacity = curve_render_data_overlay_verts_len_get(rdata);
734   int edges_len_capacity = curve_render_data_overlay_edges_len_get(rdata) * 2;
735   int vbo_len_used = 0;
736
737   if (DRW_TEST_ASSIGN_VBO(vbo_pos)) {
738     GPU_vertbuf_init_with_format(vbo_pos, &format_pos);
739     GPU_vertbuf_data_alloc(vbo_pos, verts_len_capacity);
740   }
741   if (DRW_TEST_ASSIGN_VBO(vbo_data)) {
742     GPU_vertbuf_init_with_format(vbo_data, &format_data);
743     GPU_vertbuf_data_alloc(vbo_data, verts_len_capacity);
744   }
745
746   GPUIndexBufBuilder elb_verts, *elbp_verts = NULL;
747   GPUIndexBufBuilder elb_lines, *elbp_lines = NULL;
748   if (DRW_TEST_ASSIGN_IBO(ibo_edit_verts_points)) {
749     elbp_verts = &elb_verts;
750     GPU_indexbuf_init(elbp_verts, GPU_PRIM_POINTS, verts_len_capacity, verts_len_capacity);
751   }
752   if (DRW_TEST_ASSIGN_IBO(ibo_edit_lines)) {
753     elbp_lines = &elb_lines;
754     GPU_indexbuf_init(elbp_lines, GPU_PRIM_LINES, edges_len_capacity, verts_len_capacity);
755   }
756
757   int nu_id = 0;
758   for (Nurb *nu = rdata->nurbs->first; nu; nu = nu->next, nu_id++) {
759     const BezTriple *bezt = nu->bezt;
760     const BPoint *bp = nu->bp;
761     if (bezt) {
762       for (int a = 0; a < nu->pntsu; a++, bezt++) {
763         if (bezt->hide == true) {
764           continue;
765         }
766
767         if (elbp_verts) {
768           GPU_indexbuf_add_point_vert(elbp_verts, vbo_len_used + 1);
769         }
770         if (elbp_lines) {
771           GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 1, vbo_len_used + 0);
772           GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used + 1, vbo_len_used + 2);
773         }
774         if (vbo_data) {
775           char vflag[3] = {
776               beztriple_vflag_get(rdata, bezt->f1, bezt->h1, a, nu_id),
777               beztriple_vflag_get(rdata, bezt->f2, bezt->h1, a, nu_id),
778               beztriple_vflag_get(rdata, bezt->f3, bezt->h2, a, nu_id),
779           };
780           for (int j = 0; j < 3; j++) {
781             GPU_vertbuf_attr_set(vbo_data, attr_id.data, vbo_len_used + j, &vflag[j]);
782           }
783         }
784         if (vbo_pos) {
785           for (int j = 0; j < 3; j++) {
786             GPU_vertbuf_attr_set(vbo_pos, attr_id.pos, vbo_len_used + j, bezt->vec[j]);
787           }
788         }
789         vbo_len_used += 3;
790       }
791     }
792     else if (bp) {
793       int pt_len = nu->pntsu * nu->pntsv;
794       for (int a = 0; a < pt_len; a++, bp++, vbo_len_used += 1) {
795         if (bp->hide == true) {
796           continue;
797         }
798         int u = (a % nu->pntsu);
799         int v = (a / nu->pntsu);
800         /* Use indexed rendering for bezier.
801          * Specify all points and use indices to hide/show. */
802         if (elbp_verts) {
803           GPU_indexbuf_add_point_vert(elbp_verts, vbo_len_used);
804         }
805         if (elbp_lines) {
806           const BPoint *bp_next_u = (u < (nu->pntsu - 1)) ? &nu->bp[a + 1] : NULL;
807           const BPoint *bp_next_v = (v < (nu->pntsv - 1)) ? &nu->bp[a + nu->pntsu] : NULL;
808           if (bp_next_u && (bp_next_u->hide == false)) {
809             GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used, vbo_len_used + 1);
810           }
811           if (bp_next_v && (bp_next_v->hide == false)) {
812             GPU_indexbuf_add_line_verts(elbp_lines, vbo_len_used, vbo_len_used + nu->pntsu);
813           }
814         }
815         if (vbo_data) {
816           char vflag = bpoint_vflag_get(rdata, bp->f1, a, nu_id, u);
817           GPU_vertbuf_attr_set(vbo_data, attr_id.data, vbo_len_used, &vflag);
818         }
819         if (vbo_pos) {
820           GPU_vertbuf_attr_set(vbo_pos, attr_id.pos, vbo_len_used, bp->vec);
821         }
822       }
823     }
824   }
825
826   /* Resize & Finish */
827   if (elbp_verts != NULL) {
828     GPU_indexbuf_build_in_place(elbp_verts, ibo_edit_verts_points);
829   }
830   if (elbp_lines != NULL) {
831     GPU_indexbuf_build_in_place(elbp_lines, ibo_edit_lines);
832   }
833   if (vbo_len_used != verts_len_capacity) {
834     if (vbo_pos != NULL) {
835       GPU_vertbuf_data_resize(vbo_pos, vbo_len_used);
836     }
837     if (vbo_data != NULL) {
838       GPU_vertbuf_data_resize(vbo_data, vbo_len_used);
839     }
840   }
841 }
842
843 /** \} */
844
845 /* -------------------------------------------------------------------- */
846 /** \name Public Object/Curve API
847  * \{ */
848
849 GPUBatch *DRW_curve_batch_cache_get_wire_edge(Curve *cu)
850 {
851   CurveBatchCache *cache = curve_batch_cache_get(cu);
852   return DRW_batch_request(&cache->batch.curves);
853 }
854
855 GPUBatch *DRW_curve_batch_cache_get_normal_edge(Curve *cu)
856 {
857   CurveBatchCache *cache = curve_batch_cache_get(cu);
858   return DRW_batch_request(&cache->batch.edit_normals);
859 }
860
861 GPUBatch *DRW_curve_batch_cache_get_edit_edges(Curve *cu)
862 {
863   CurveBatchCache *cache = curve_batch_cache_get(cu);
864   return DRW_batch_request(&cache->batch.edit_edges);
865 }
866
867 GPUBatch *DRW_curve_batch_cache_get_edit_verts(Curve *cu, bool handles)
868 {
869   CurveBatchCache *cache = curve_batch_cache_get(cu);
870   if (handles) {
871     return DRW_batch_request(&cache->batch.edit_handles_verts);
872   }
873   else {
874     return DRW_batch_request(&cache->batch.edit_verts);
875   }
876 }
877
878 GPUBatch *DRW_curve_batch_cache_get_triangles_with_normals(struct Curve *cu)
879 {
880   CurveBatchCache *cache = curve_batch_cache_get(cu);
881   return DRW_batch_request(&cache->batch.surfaces);
882 }
883
884 GPUBatch **DRW_curve_batch_cache_get_surface_shaded(struct Curve *cu,
885                                                     struct GPUMaterial **gpumat_array,
886                                                     uint gpumat_array_len)
887 {
888   CurveBatchCache *cache = curve_batch_cache_get(cu);
889
890   BLI_assert(gpumat_array_len == cache->mat_len);
891
892   curve_cd_calc_used_gpu_layers(&cache->cd_needed, gpumat_array, gpumat_array_len);
893
894   for (int i = 0; i < cache->mat_len; ++i) {
895     DRW_batch_request(&cache->surf_per_mat[i]);
896   }
897   return cache->surf_per_mat;
898 }
899
900 GPUBatch *DRW_curve_batch_cache_get_wireframes_face(Curve *cu)
901 {
902   CurveBatchCache *cache = curve_batch_cache_get(cu);
903   return DRW_batch_request(&cache->batch.surfaces_edges);
904 }
905
906 GPUBatch *DRW_curve_batch_cache_get_edge_detection(Curve *cu, bool *r_is_manifold)
907 {
908   CurveBatchCache *cache = curve_batch_cache_get(cu);
909   /* Even if is_manifold is not correct (not updated),
910    * the default (not manifold) is just the worst case. */
911   if (r_is_manifold) {
912     *r_is_manifold = cache->is_manifold;
913   }
914   return DRW_batch_request(&cache->batch.edge_detection);
915 }
916
917 /** \} */
918
919 /* -------------------------------------------------------------------- */
920 /** \name Grouped batch generation
921  * \{ */
922
923 void DRW_curve_batch_cache_create_requested(Object *ob)
924 {
925   BLI_assert(ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT));
926
927   Curve *cu = ob->data;
928   CurveBatchCache *cache = curve_batch_cache_get(cu);
929
930   /* Verify that all surface batches have needed attribute layers. */
931   /* TODO(fclem): We could be a bit smarter here and only do it per material. */
932   for (int i = 0; i < cache->mat_len; ++i) {
933     if ((cache->cd_used & cache->cd_needed) != cache->cd_needed) {
934       /* We can't discard batches at this point as they have been
935        * referenced for drawing. Just clear them in place. */
936       GPU_batch_clear(cache->surf_per_mat[i]);
937       memset(cache->surf_per_mat[i], 0, sizeof(*cache->surf_per_mat[i]));
938     }
939   }
940   if ((cache->cd_used & cache->cd_needed) != cache->cd_needed) {
941     cache->cd_used |= cache->cd_needed;
942     cache->cd_needed = 0;
943   }
944
945   /* Init batches and request VBOs & IBOs */
946   if (DRW_batch_requested(cache->batch.surfaces, GPU_PRIM_TRIS)) {
947     DRW_ibo_request(cache->batch.surfaces, &cache->ibo.surfaces_tris);
948     DRW_vbo_request(cache->batch.surfaces, &cache->ordered.pos_nor);
949   }
950   if (DRW_batch_requested(cache->batch.surfaces_edges, GPU_PRIM_LINES)) {
951     DRW_ibo_request(cache->batch.surfaces_edges, &cache->ibo.surfaces_lines);
952     DRW_vbo_request(cache->batch.surfaces_edges, &cache->ordered.pos_nor);
953     DRW_vbo_request(cache->batch.surfaces_edges, &cache->ordered.edge_fac);
954   }
955   if (DRW_batch_requested(cache->batch.curves, GPU_PRIM_LINE_STRIP)) {
956     DRW_ibo_request(cache->batch.curves, &cache->ibo.curves_lines);
957     DRW_vbo_request(cache->batch.curves, &cache->ordered.curves_pos);
958   }
959   if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) {
960     DRW_ibo_request(cache->batch.edge_detection, &cache->ibo.edges_adj_lines);
961     DRW_vbo_request(cache->batch.edge_detection, &cache->ordered.pos_nor);
962   }
963
964   /* Edit mode */
965   if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) {
966     DRW_ibo_request(cache->batch.edit_edges, &cache->ibo.edit_lines);
967     DRW_vbo_request(cache->batch.edit_edges, &cache->edit.pos);
968     DRW_vbo_request(cache->batch.edit_edges, &cache->edit.data);
969   }
970   if (DRW_batch_requested(cache->batch.edit_verts, GPU_PRIM_POINTS)) {
971     DRW_ibo_request(cache->batch.edit_verts, &cache->ibo.edit_verts_points);
972     DRW_vbo_request(cache->batch.edit_verts, &cache->edit.pos);
973     DRW_vbo_request(cache->batch.edit_verts, &cache->edit.data);
974   }
975   if (DRW_batch_requested(cache->batch.edit_handles_verts, GPU_PRIM_POINTS)) {
976     DRW_vbo_request(cache->batch.edit_handles_verts, &cache->edit.pos);
977     DRW_vbo_request(cache->batch.edit_handles_verts, &cache->edit.data);
978   }
979   if (DRW_batch_requested(cache->batch.edit_normals, GPU_PRIM_LINES)) {
980     DRW_vbo_request(cache->batch.edit_normals, &cache->edit.curves_nor);
981   }
982   for (int i = 0; i < cache->mat_len; ++i) {
983     if (DRW_batch_requested(cache->surf_per_mat[i], GPU_PRIM_TRIS)) {
984       if (cache->mat_len > 1) {
985         DRW_ibo_request(cache->surf_per_mat[i], &cache->surf_per_mat_tris[i]);
986       }
987       if (cache->cd_used & CD_MLOOPUV) {
988         DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_uv);
989       }
990       DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_pos_nor);
991     }
992   }
993
994 #ifdef DRW_DEBUG_MESH_CACHE_REQUEST
995   printf("-- %s %s --\n", __func__, ob->id.name + 2);
996 #endif
997
998   /* Generate MeshRenderData flags */
999   int mr_flag = 0;
1000   DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.pos_nor, CU_DATATYPE_SURFACE);
1001   DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.edge_fac, CU_DATATYPE_SURFACE);
1002   DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.curves_pos, CU_DATATYPE_WIRE);
1003   DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.loop_pos_nor, CU_DATATYPE_SURFACE);
1004   DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.loop_uv, CU_DATATYPE_SURFACE);
1005   DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.surfaces_tris, CU_DATATYPE_SURFACE);
1006   DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.surfaces_lines, CU_DATATYPE_SURFACE);
1007   DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.curves_lines, CU_DATATYPE_WIRE);
1008   DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edges_adj_lines, CU_DATATYPE_SURFACE);
1009
1010   DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.pos, CU_DATATYPE_OVERLAY);
1011   DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.data, CU_DATATYPE_OVERLAY);
1012   DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.curves_nor, CU_DATATYPE_NORMAL);
1013   DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.curves_weight, CU_DATATYPE_OVERLAY);
1014   DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_verts_points, CU_DATATYPE_OVERLAY);
1015   DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.edit_lines, CU_DATATYPE_OVERLAY);
1016
1017   for (int i = 0; i < cache->mat_len; ++i) {
1018     DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->surf_per_mat_tris[i], CU_DATATYPE_SURFACE);
1019   }
1020
1021 #ifdef DRW_DEBUG_MESH_CACHE_REQUEST
1022   printf("  mr_flag %d\n\n", mr_flag);
1023 #endif
1024
1025   CurveRenderData *rdata = curve_render_data_create(cu, ob->runtime.curve_cache, mr_flag);
1026
1027   /* DispLists */
1028   ListBase *lb = &rdata->ob_curve_cache->disp;
1029
1030   /* Generate VBOs */
1031   if (DRW_vbo_requested(cache->ordered.pos_nor)) {
1032     DRW_displist_vertbuf_create_pos_and_nor(lb, cache->ordered.pos_nor);
1033   }
1034   if (DRW_vbo_requested(cache->ordered.edge_fac)) {
1035     DRW_displist_vertbuf_create_wiredata(lb, cache->ordered.edge_fac);
1036   }
1037   if (DRW_vbo_requested(cache->ordered.curves_pos)) {
1038     curve_create_curves_pos(rdata, cache->ordered.curves_pos);
1039   }
1040
1041   if (DRW_vbo_requested(cache->ordered.loop_pos_nor) ||
1042       DRW_vbo_requested(cache->ordered.loop_uv)) {
1043     DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv(
1044         lb, cache->ordered.loop_pos_nor, cache->ordered.loop_uv);
1045   }
1046
1047   if (DRW_ibo_requested(cache->surf_per_mat_tris[0])) {
1048     DRW_displist_indexbuf_create_triangles_loop_split_by_material(
1049         lb, cache->surf_per_mat_tris, cache->mat_len);
1050   }
1051
1052   if (DRW_ibo_requested(cache->ibo.curves_lines)) {
1053     curve_create_curves_lines(rdata, cache->ibo.curves_lines);
1054   }
1055   if (DRW_ibo_requested(cache->ibo.surfaces_tris)) {
1056     DRW_displist_indexbuf_create_triangles_in_order(lb, cache->ibo.surfaces_tris);
1057   }
1058   if (DRW_ibo_requested(cache->ibo.surfaces_lines)) {
1059     DRW_displist_indexbuf_create_lines_in_order(lb, cache->ibo.surfaces_lines);
1060   }
1061   if (DRW_ibo_requested(cache->ibo.edges_adj_lines)) {
1062     DRW_displist_indexbuf_create_edges_adjacency_lines(
1063         lb, cache->ibo.edges_adj_lines, &cache->is_manifold);
1064   }
1065
1066   if (DRW_vbo_requested(cache->edit.pos) || DRW_vbo_requested(cache->edit.data) ||
1067       DRW_ibo_requested(cache->ibo.edit_verts_points) ||
1068       DRW_ibo_requested(cache->ibo.edit_lines)) {
1069     curve_create_edit_data_and_handles(rdata,
1070                                        cache->edit.pos,
1071                                        cache->edit.data,
1072                                        cache->ibo.edit_verts_points,
1073                                        cache->ibo.edit_lines);
1074   }
1075   if (DRW_vbo_requested(cache->edit.curves_nor)) {
1076     curve_create_edit_curves_nor(rdata, cache->edit.curves_nor);
1077   }
1078
1079   curve_render_data_free(rdata);
1080
1081 #ifdef DEBUG
1082   /* Make sure all requested batches have been setup. */
1083   for (int i = 0; i < sizeof(cache->batch) / sizeof(void *); ++i) {
1084     BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0));
1085   }
1086 #endif
1087 }
1088
1089 /** \} */