d1c214c2aa6c2b4e679fd30c9289e9eab69232e7
[blender.git] / source / blender / draw / intern / draw_cache_impl_displist.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 DispList API for render engines
24  *
25  * \note DispList may be removed soon! This is a utility for object types that use render.
26  */
27
28 #include "BLI_alloca.h"
29 #include "BLI_utildefines.h"
30 #include "BLI_edgehash.h"
31 #include "BLI_math_vector.h"
32
33 #include "DNA_curve_types.h"
34
35 #include "BKE_displist.h"
36
37 #include "GPU_batch.h"
38 #include "GPU_extensions.h"
39
40 #include "draw_cache_inline.h"
41
42 #include "draw_cache_impl.h" /* own include */
43
44 static int dl_vert_len(const DispList *dl)
45 {
46   switch (dl->type) {
47     case DL_INDEX3:
48     case DL_INDEX4:
49       return dl->nr;
50     case DL_SURF:
51       return dl->parts * dl->nr;
52   }
53   return 0;
54 }
55
56 static int dl_tri_len(const DispList *dl)
57 {
58   switch (dl->type) {
59     case DL_INDEX3:
60       return dl->parts;
61     case DL_INDEX4:
62       return dl->parts * 2;
63     case DL_SURF:
64       return dl->totindex * 2;
65   }
66   return 0;
67 }
68
69 /* see: displist_get_allverts */
70 static int curve_render_surface_vert_len_get(const ListBase *lb)
71 {
72   int vert_len = 0;
73   for (const DispList *dl = lb->first; dl; dl = dl->next) {
74     vert_len += dl_vert_len(dl);
75   }
76   return vert_len;
77 }
78
79 static int curve_render_surface_tri_len_get(const ListBase *lb)
80 {
81   int tri_len = 0;
82   for (const DispList *dl = lb->first; dl; dl = dl->next) {
83     tri_len += dl_tri_len(dl);
84   }
85   return tri_len;
86 }
87
88 typedef void(SetTriIndicesFn)(void *thunk, uint v1, uint v2, uint v3);
89
90 static void displist_indexbufbuilder_set(
91     SetTriIndicesFn *set_tri_indices,
92     SetTriIndicesFn *set_quad_tri_indices, /* meh, find a better solution. */
93     void *thunk,
94     const DispList *dl,
95     const int ofs)
96 {
97   if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
98     const int *idx = dl->index;
99     if (dl->type == DL_INDEX3) {
100       const int i_end = dl->parts;
101       for (int i = 0; i < i_end; i++, idx += 3) {
102         set_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs);
103       }
104     }
105     else if (dl->type == DL_SURF) {
106       const int i_end = dl->totindex;
107       for (int i = 0; i < i_end; i++, idx += 4) {
108         set_quad_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs);
109         set_quad_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[3] + ofs);
110       }
111     }
112     else {
113       BLI_assert(dl->type == DL_INDEX4);
114       const int i_end = dl->parts;
115       for (int i = 0; i < i_end; i++, idx += 4) {
116         if (idx[2] != idx[3]) {
117           set_quad_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[1] + ofs);
118           set_quad_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs);
119         }
120         else {
121           set_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[1] + ofs);
122         }
123       }
124     }
125   }
126 }
127
128 static int displist_indexbufbuilder_tess_set(
129     SetTriIndicesFn *set_tri_indices,
130     SetTriIndicesFn *set_quad_tri_indices, /* meh, find a better solution. */
131     void *thunk,
132     const DispList *dl,
133     const int ofs)
134 {
135   int v_idx = ofs;
136   if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
137     if (dl->type == DL_INDEX3) {
138       for (int i = 0; i < dl->parts; i++) {
139         set_tri_indices(thunk, v_idx + 0, v_idx + 1, v_idx + 2);
140         v_idx += 3;
141       }
142     }
143     else if (dl->type == DL_SURF) {
144       for (int a = 0; a < dl->parts; a++) {
145         if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) {
146           break;
147         }
148         int b = (dl->flag & DL_CYCL_U) ? 0 : 1;
149         for (; b < dl->nr; b++) {
150           set_quad_tri_indices(thunk, v_idx + 0, v_idx + 1, v_idx + 2);
151           set_quad_tri_indices(thunk, v_idx + 3, v_idx + 4, v_idx + 5);
152           v_idx += 6;
153         }
154       }
155     }
156     else {
157       BLI_assert(dl->type == DL_INDEX4);
158       const int *idx = dl->index;
159       for (int i = 0; i < dl->parts; i++, idx += 4) {
160         if (idx[2] != idx[3]) {
161           set_quad_tri_indices(thunk, v_idx + 0, v_idx + 1, v_idx + 2);
162           set_quad_tri_indices(thunk, v_idx + 3, v_idx + 4, v_idx + 5);
163           v_idx += 6;
164         }
165         else {
166           set_tri_indices(thunk, v_idx + 0, v_idx + 1, v_idx + 2);
167           v_idx += 3;
168         }
169       }
170     }
171   }
172   return v_idx;
173 }
174
175 void DRW_displist_vertbuf_create_pos_and_nor(ListBase *lb, GPUVertBuf *vbo)
176 {
177   static GPUVertFormat format = {0};
178   static struct {
179     uint pos, nor;
180   } attr_id;
181   if (format.attr_len == 0) {
182     /* initialize vertex format */
183     attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
184     attr_id.nor = GPU_vertformat_attr_add(
185         &format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
186   }
187
188   GPU_vertbuf_init_with_format(vbo, &format);
189   GPU_vertbuf_data_alloc(vbo, curve_render_surface_vert_len_get(lb));
190
191   BKE_displist_normals_add(lb);
192
193   int vbo_len_used = 0;
194   for (const DispList *dl = lb->first; dl; dl = dl->next) {
195     const bool ndata_is_single = dl->type == DL_INDEX3;
196     if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
197       const float *fp_co = dl->verts;
198       const float *fp_no = dl->nors;
199       const int vbo_end = vbo_len_used + dl_vert_len(dl);
200       while (vbo_len_used < vbo_end) {
201         GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, fp_co);
202         if (fp_no) {
203           GPUPackedNormal vnor_pack = GPU_normal_convert_i10_v3(fp_no);
204           GPU_vertbuf_attr_set(vbo, attr_id.nor, vbo_len_used, &vnor_pack);
205           if (ndata_is_single == false) {
206             fp_no += 3;
207           }
208         }
209         fp_co += 3;
210         vbo_len_used += 1;
211       }
212     }
213   }
214 }
215
216 void DRW_displist_vertbuf_create_wiredata(ListBase *lb, GPUVertBuf *vbo)
217 {
218   static GPUVertFormat format = {0};
219   static struct {
220     uint wd;
221   } attr_id;
222   if (format.attr_len == 0) {
223     /* initialize vertex format */
224     if (!GPU_crappy_amd_driver()) {
225       /* Some AMD drivers strangely crash with a vbo with this format. */
226       attr_id.wd = GPU_vertformat_attr_add(
227           &format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
228     }
229     else {
230       attr_id.wd = GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
231     }
232   }
233
234   int vbo_len_used = curve_render_surface_vert_len_get(lb);
235
236   GPU_vertbuf_init_with_format(vbo, &format);
237   GPU_vertbuf_data_alloc(vbo, vbo_len_used);
238
239   if (vbo->format.stride == 1) {
240     memset(vbo->data, 0xFF, (size_t)vbo_len_used);
241   }
242   else {
243     GPUVertBufRaw wd_step;
244     GPU_vertbuf_attr_get_raw_data(vbo, attr_id.wd, &wd_step);
245     for (int i = 0; i < vbo_len_used; i++) {
246       *((float *)GPU_vertbuf_raw_step(&wd_step)) = 1.0f;
247     }
248   }
249 }
250
251 void DRW_displist_indexbuf_create_triangles_in_order(ListBase *lb, GPUIndexBuf *ibo)
252 {
253   const int tri_len = curve_render_surface_tri_len_get(lb);
254   const int vert_len = curve_render_surface_vert_len_get(lb);
255
256   GPUIndexBufBuilder elb;
257   GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len);
258
259   int ofs = 0;
260   for (const DispList *dl = lb->first; dl; dl = dl->next) {
261     displist_indexbufbuilder_set((SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
262                                  (SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
263                                  &elb,
264                                  dl,
265                                  ofs);
266     ofs += dl_vert_len(dl);
267   }
268
269   GPU_indexbuf_build_in_place(&elb, ibo);
270 }
271
272 void DRW_displist_indexbuf_create_triangles_loop_split_by_material(ListBase *lb,
273                                                                    GPUIndexBuf **ibo_mats,
274                                                                    uint mat_len)
275 {
276   GPUIndexBufBuilder *elb = BLI_array_alloca(elb, mat_len);
277
278   const int tri_len = curve_render_surface_tri_len_get(lb);
279
280   /* Init each index buffer builder */
281   for (int i = 0; i < mat_len; i++) {
282     GPU_indexbuf_init(&elb[i], GPU_PRIM_TRIS, tri_len * 3, tri_len * 3);
283   }
284
285   /* calc each index buffer builder */
286   uint v_idx = 0;
287   for (const DispList *dl = lb->first; dl; dl = dl->next) {
288     v_idx = displist_indexbufbuilder_tess_set((SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
289                                               (SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
290                                               &elb[dl->col],
291                                               dl,
292                                               v_idx);
293   }
294
295   /* build each indexbuf */
296   for (int i = 0; i < mat_len; i++) {
297     GPU_indexbuf_build_in_place(&elb[i], ibo_mats[i]);
298   }
299 }
300
301 static void set_overlay_wires_tri_indices(void *thunk, uint v1, uint v2, uint v3)
302 {
303   GPUIndexBufBuilder *eld = (GPUIndexBufBuilder *)thunk;
304   GPU_indexbuf_add_line_verts(eld, v1, v2);
305   GPU_indexbuf_add_line_verts(eld, v2, v3);
306   GPU_indexbuf_add_line_verts(eld, v3, v1);
307 }
308
309 static void set_overlay_wires_quad_tri_indices(void *thunk, uint v1, uint v2, uint v3)
310 {
311   GPUIndexBufBuilder *eld = (GPUIndexBufBuilder *)thunk;
312   GPU_indexbuf_add_line_verts(eld, v1, v3);
313   GPU_indexbuf_add_line_verts(eld, v3, v2);
314 }
315
316 void DRW_displist_indexbuf_create_lines_in_order(ListBase *lb, GPUIndexBuf *ibo)
317 {
318   const int tri_len = curve_render_surface_tri_len_get(lb);
319   const int vert_len = curve_render_surface_vert_len_get(lb);
320
321   GPUIndexBufBuilder elb;
322   GPU_indexbuf_init(&elb, GPU_PRIM_LINES, tri_len * 3, vert_len);
323
324   int ofs = 0;
325   for (const DispList *dl = lb->first; dl; dl = dl->next) {
326     displist_indexbufbuilder_set(
327         set_overlay_wires_tri_indices, set_overlay_wires_quad_tri_indices, &elb, dl, ofs);
328     ofs += dl_vert_len(dl);
329   }
330
331   GPU_indexbuf_build_in_place(&elb, ibo);
332 }
333
334 static void surf_uv_quad(const DispList *dl, const uint quad[4], float r_uv[4][2])
335 {
336   int orco_sizeu = dl->nr - 1;
337   int orco_sizev = dl->parts - 1;
338
339   /* exception as handled in convertblender.c too */
340   if (dl->flag & DL_CYCL_U) {
341     orco_sizeu++;
342   }
343   if (dl->flag & DL_CYCL_V) {
344     orco_sizev++;
345   }
346
347   for (int i = 0; i < 4; i++) {
348     /* find uv based on vertex index into grid array */
349     r_uv[i][0] = (quad[i] / dl->nr) / (float)orco_sizev;
350     r_uv[i][1] = (quad[i] % dl->nr) / (float)orco_sizeu;
351
352     /* cyclic correction */
353     if ((i == 1 || i == 2) && r_uv[i][0] == 0.0f) {
354       r_uv[i][0] = 1.0f;
355     }
356     if ((i == 0 || i == 1) && r_uv[i][1] == 0.0f) {
357       r_uv[i][1] = 1.0f;
358     }
359   }
360 }
361
362 static void displist_vertbuf_attr_set_tri_pos_nor_uv(GPUVertBufRaw *pos_step,
363                                                      GPUVertBufRaw *nor_step,
364                                                      GPUVertBufRaw *uv_step,
365                                                      const float v1[3],
366                                                      const float v2[3],
367                                                      const float v3[3],
368                                                      const GPUPackedNormal *n1,
369                                                      const GPUPackedNormal *n2,
370                                                      const GPUPackedNormal *n3,
371                                                      const float uv1[2],
372                                                      const float uv2[2],
373                                                      const float uv3[2])
374 {
375   if (pos_step->size != 0) {
376     copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v1);
377     copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v2);
378     copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v3);
379
380     *(GPUPackedNormal *)GPU_vertbuf_raw_step(nor_step) = *n1;
381     *(GPUPackedNormal *)GPU_vertbuf_raw_step(nor_step) = *n2;
382     *(GPUPackedNormal *)GPU_vertbuf_raw_step(nor_step) = *n3;
383   }
384
385   if (uv_step->size != 0) {
386     normal_float_to_short_v2(GPU_vertbuf_raw_step(uv_step), uv1);
387     normal_float_to_short_v2(GPU_vertbuf_raw_step(uv_step), uv2);
388     normal_float_to_short_v2(GPU_vertbuf_raw_step(uv_step), uv3);
389   }
390 }
391
392 void DRW_displist_vertbuf_create_loop_pos_and_nor_and_uv(ListBase *lb,
393                                                          GPUVertBuf *vbo_pos_nor,
394                                                          GPUVertBuf *vbo_uv)
395 {
396   static GPUVertFormat format_pos_nor = {0};
397   static GPUVertFormat format_uv = {0};
398   static struct {
399     uint pos, nor, uv;
400   } attr_id;
401   if (format_pos_nor.attr_len == 0) {
402     /* initialize vertex format */
403     attr_id.pos = GPU_vertformat_attr_add(
404         &format_pos_nor, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
405     attr_id.nor = GPU_vertformat_attr_add(
406         &format_pos_nor, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
407     /* UVs are in [0..1] range. We can compress them. */
408     attr_id.uv = GPU_vertformat_attr_add(
409         &format_uv, "u", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT);
410   }
411
412   int vbo_len_capacity = curve_render_surface_tri_len_get(lb) * 3;
413
414   GPUVertBufRaw pos_step = {0};
415   GPUVertBufRaw nor_step = {0};
416   GPUVertBufRaw uv_step = {0};
417
418   if (DRW_TEST_ASSIGN_VBO(vbo_pos_nor)) {
419     GPU_vertbuf_init_with_format(vbo_pos_nor, &format_pos_nor);
420     GPU_vertbuf_data_alloc(vbo_pos_nor, vbo_len_capacity);
421     GPU_vertbuf_attr_get_raw_data(vbo_pos_nor, attr_id.pos, &pos_step);
422     GPU_vertbuf_attr_get_raw_data(vbo_pos_nor, attr_id.nor, &nor_step);
423   }
424   if (DRW_TEST_ASSIGN_VBO(vbo_uv)) {
425     GPU_vertbuf_init_with_format(vbo_uv, &format_uv);
426     GPU_vertbuf_data_alloc(vbo_uv, vbo_len_capacity);
427     GPU_vertbuf_attr_get_raw_data(vbo_uv, attr_id.uv, &uv_step);
428   }
429
430   BKE_displist_normals_add(lb);
431
432   for (const DispList *dl = lb->first; dl; dl = dl->next) {
433     const bool is_smooth = (dl->rt & CU_SMOOTH) != 0;
434     if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
435       const float(*verts)[3] = (float(*)[3])dl->verts;
436       const float(*nors)[3] = (float(*)[3])dl->nors;
437       const int *idx = dl->index;
438       float uv[4][2];
439
440       if (dl->type == DL_INDEX3) {
441         /* Currently 'DL_INDEX3' is always a flat surface with a single normal. */
442         const GPUPackedNormal pnor = GPU_normal_convert_i10_v3(dl->nors);
443         const float x_max = (float)(dl->nr - 1);
444         uv[0][1] = uv[1][1] = uv[2][1] = 0.0f;
445         const int i_end = dl->parts;
446         for (int i = 0; i < i_end; i++, idx += 3) {
447           if (vbo_uv) {
448             uv[0][0] = idx[0] / x_max;
449             uv[1][0] = idx[1] / x_max;
450             uv[2][0] = idx[2] / x_max;
451           }
452
453           displist_vertbuf_attr_set_tri_pos_nor_uv(&pos_step,
454                                                    &nor_step,
455                                                    &uv_step,
456                                                    verts[idx[0]],
457                                                    verts[idx[2]],
458                                                    verts[idx[1]],
459                                                    &pnor,
460                                                    &pnor,
461                                                    &pnor,
462                                                    uv[0],
463                                                    uv[2],
464                                                    uv[1]);
465         }
466       }
467       else if (dl->type == DL_SURF) {
468         uint quad[4];
469         for (int a = 0; a < dl->parts; a++) {
470           if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) {
471             break;
472           }
473
474           int b;
475           if (dl->flag & DL_CYCL_U) {
476             quad[0] = dl->nr * a;
477             quad[3] = quad[0] + dl->nr - 1;
478             quad[1] = quad[0] + dl->nr;
479             quad[2] = quad[3] + dl->nr;
480             b = 0;
481           }
482           else {
483             quad[3] = dl->nr * a;
484             quad[0] = quad[3] + 1;
485             quad[2] = quad[3] + dl->nr;
486             quad[1] = quad[0] + dl->nr;
487             b = 1;
488           }
489           if ((dl->flag & DL_CYCL_V) && a == dl->parts - 1) {
490             quad[1] -= dl->parts * dl->nr;
491             quad[2] -= dl->parts * dl->nr;
492           }
493
494           for (; b < dl->nr; b++) {
495             if (vbo_uv) {
496               surf_uv_quad(dl, quad, uv);
497             }
498
499             GPUPackedNormal pnors_quad[4];
500             if (is_smooth) {
501               for (int j = 0; j < 4; j++) {
502                 pnors_quad[j] = GPU_normal_convert_i10_v3(nors[quad[j]]);
503               }
504             }
505             else {
506               float nor_flat[3];
507               normal_quad_v3(
508                   nor_flat, verts[quad[0]], verts[quad[1]], verts[quad[2]], verts[quad[3]]);
509               pnors_quad[0] = GPU_normal_convert_i10_v3(nor_flat);
510               pnors_quad[1] = pnors_quad[0];
511               pnors_quad[2] = pnors_quad[0];
512               pnors_quad[3] = pnors_quad[0];
513             }
514
515             displist_vertbuf_attr_set_tri_pos_nor_uv(&pos_step,
516                                                      &nor_step,
517                                                      &uv_step,
518                                                      verts[quad[2]],
519                                                      verts[quad[0]],
520                                                      verts[quad[1]],
521                                                      &pnors_quad[2],
522                                                      &pnors_quad[0],
523                                                      &pnors_quad[1],
524                                                      uv[2],
525                                                      uv[0],
526                                                      uv[1]);
527
528             displist_vertbuf_attr_set_tri_pos_nor_uv(&pos_step,
529                                                      &nor_step,
530                                                      &uv_step,
531                                                      verts[quad[0]],
532                                                      verts[quad[2]],
533                                                      verts[quad[3]],
534                                                      &pnors_quad[0],
535                                                      &pnors_quad[2],
536                                                      &pnors_quad[3],
537                                                      uv[0],
538                                                      uv[2],
539                                                      uv[3]);
540
541             quad[2] = quad[1];
542             quad[1]++;
543             quad[3] = quad[0];
544             quad[0]++;
545           }
546         }
547       }
548       else {
549         BLI_assert(dl->type == DL_INDEX4);
550         uv[0][0] = uv[0][1] = uv[1][0] = uv[3][1] = 0.0f;
551         uv[1][1] = uv[2][0] = uv[2][1] = uv[3][0] = 1.0f;
552
553         const int i_end = dl->parts;
554         for (int i = 0; i < i_end; i++, idx += 4) {
555           const bool is_tri = idx[2] != idx[3];
556
557           GPUPackedNormal pnors_idx[4];
558           if (is_smooth) {
559             int idx_len = is_tri ? 3 : 4;
560             for (int j = 0; j < idx_len; j++) {
561               pnors_idx[j] = GPU_normal_convert_i10_v3(nors[idx[j]]);
562             }
563           }
564           else {
565             float nor_flat[3];
566             if (is_tri) {
567               normal_tri_v3(nor_flat, verts[idx[0]], verts[idx[1]], verts[idx[2]]);
568             }
569             else {
570               normal_quad_v3(nor_flat, verts[idx[0]], verts[idx[1]], verts[idx[2]], verts[idx[3]]);
571             }
572             pnors_idx[0] = GPU_normal_convert_i10_v3(nor_flat);
573             pnors_idx[1] = pnors_idx[0];
574             pnors_idx[2] = pnors_idx[0];
575             pnors_idx[3] = pnors_idx[0];
576           }
577
578           displist_vertbuf_attr_set_tri_pos_nor_uv(&pos_step,
579                                                    &nor_step,
580                                                    &uv_step,
581                                                    verts[idx[0]],
582                                                    verts[idx[2]],
583                                                    verts[idx[1]],
584                                                    &pnors_idx[0],
585                                                    &pnors_idx[2],
586                                                    &pnors_idx[1],
587                                                    uv[0],
588                                                    uv[2],
589                                                    uv[1]);
590
591           if (idx[2] != idx[3]) {
592             displist_vertbuf_attr_set_tri_pos_nor_uv(&pos_step,
593                                                      &nor_step,
594                                                      &uv_step,
595                                                      verts[idx[2]],
596                                                      verts[idx[0]],
597                                                      verts[idx[3]],
598                                                      &pnors_idx[2],
599                                                      &pnors_idx[0],
600                                                      &pnors_idx[3],
601                                                      uv[2],
602                                                      uv[0],
603                                                      uv[3]);
604           }
605         }
606       }
607     }
608   }
609   /* Resize and finish. */
610   if (pos_step.size != 0) {
611     int vbo_len_used = GPU_vertbuf_raw_used(&pos_step);
612     if (vbo_len_used < vbo_len_capacity) {
613       GPU_vertbuf_data_resize(vbo_pos_nor, vbo_len_used);
614     }
615   }
616   if (uv_step.size != 0) {
617     int vbo_len_used = GPU_vertbuf_raw_used(&uv_step);
618     if (vbo_len_used < vbo_len_capacity) {
619       GPU_vertbuf_data_resize(vbo_uv, vbo_len_used);
620     }
621   }
622 }
623
624 /* Edge detection/adjecency */
625 #define NO_EDGE INT_MAX
626 static void set_edge_adjacency_lines_indices(
627     EdgeHash *eh, GPUIndexBufBuilder *elb, bool *r_is_manifold, uint v1, uint v2, uint v3)
628 {
629   bool inv_indices = (v2 > v3);
630   void **pval;
631   bool value_is_init = BLI_edgehash_ensure_p(eh, v2, v3, &pval);
632   int v_data = POINTER_AS_INT(*pval);
633   if (!value_is_init || v_data == NO_EDGE) {
634     /* Save the winding order inside the sign bit. Because the
635      * edgehash sort the keys and we need to compare winding later. */
636     int value = (int)v1 + 1; /* Int 0 bm_looptricannot be signed */
637     *pval = POINTER_FROM_INT((inv_indices) ? -value : value);
638   }
639   else {
640     /* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
641     *pval = POINTER_FROM_INT(NO_EDGE);
642     bool inv_opposite = (v_data < 0);
643     uint v_opposite = (uint)abs(v_data) - 1;
644
645     if (inv_opposite == inv_indices) {
646       /* Don't share edge if triangles have non matching winding. */
647       GPU_indexbuf_add_line_adj_verts(elb, v1, v2, v3, v1);
648       GPU_indexbuf_add_line_adj_verts(elb, v_opposite, v2, v3, v_opposite);
649       *r_is_manifold = false;
650     }
651     else {
652       GPU_indexbuf_add_line_adj_verts(elb, v1, v2, v3, v_opposite);
653     }
654   }
655 }
656
657 static void set_edges_adjacency_lines_indices(void *thunk, uint v1, uint v2, uint v3)
658 {
659   void **packed = (void **)thunk;
660   GPUIndexBufBuilder *elb = (GPUIndexBufBuilder *)packed[0];
661   EdgeHash *eh = (EdgeHash *)packed[1];
662   bool *r_is_manifold = (bool *)packed[2];
663
664   set_edge_adjacency_lines_indices(eh, elb, r_is_manifold, v1, v2, v3);
665   set_edge_adjacency_lines_indices(eh, elb, r_is_manifold, v2, v3, v1);
666   set_edge_adjacency_lines_indices(eh, elb, r_is_manifold, v3, v1, v2);
667 }
668
669 void DRW_displist_indexbuf_create_edges_adjacency_lines(struct ListBase *lb,
670                                                         struct GPUIndexBuf *ibo,
671                                                         bool *r_is_manifold)
672 {
673   const int tri_len = curve_render_surface_tri_len_get(lb);
674   const int vert_len = curve_render_surface_vert_len_get(lb);
675
676   *r_is_manifold = true;
677
678   /* Allocate max but only used indices are sent to GPU. */
679   GPUIndexBufBuilder elb;
680   GPU_indexbuf_init(&elb, GPU_PRIM_LINES_ADJ, tri_len * 3, vert_len);
681
682   EdgeHash *eh = BLI_edgehash_new_ex(__func__, tri_len * 3);
683
684   /* pack values to pass to `set_edges_adjacency_lines_indices` function. */
685   void *thunk[3] = {&elb, eh, r_is_manifold};
686   int v_idx = 0;
687   for (const DispList *dl = lb->first; dl; dl = dl->next) {
688     displist_indexbufbuilder_set((SetTriIndicesFn *)set_edges_adjacency_lines_indices,
689                                  (SetTriIndicesFn *)set_edges_adjacency_lines_indices,
690                                  thunk,
691                                  dl,
692                                  v_idx);
693     v_idx += dl_vert_len(dl);
694   }
695
696   /* Create edges for remaning non manifold edges. */
697   EdgeHashIterator *ehi;
698   for (ehi = BLI_edgehashIterator_new(eh); BLI_edgehashIterator_isDone(ehi) == false;
699        BLI_edgehashIterator_step(ehi)) {
700     uint v1, v2;
701     int v_data = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
702     if (v_data == NO_EDGE) {
703       continue;
704     }
705     BLI_edgehashIterator_getKey(ehi, &v1, &v2);
706     uint v0 = (uint)abs(v_data) - 1;
707     if (v_data < 0) { /* inv_opposite  */
708       SWAP(uint, v1, v2);
709     }
710     GPU_indexbuf_add_line_adj_verts(&elb, v0, v1, v2, v0);
711     *r_is_manifold = false;
712   }
713   BLI_edgehashIterator_free(ehi);
714   BLI_edgehash_free(eh, NULL);
715
716   GPU_indexbuf_build_in_place(&elb, ibo);
717 }
718 #undef NO_EDGE