doxygen: add newline after \file
[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
29 #include "BLI_alloca.h"
30 #include "BLI_utildefines.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
39 #include "draw_cache_impl.h"  /* own include */
40
41 static int dl_vert_len(const DispList *dl)
42 {
43         switch (dl->type) {
44                 case DL_INDEX3:
45                 case DL_INDEX4:
46                         return dl->nr;
47                 case DL_SURF:
48                         return dl->parts * dl->nr;
49         }
50         return 0;
51 }
52
53 static int dl_tri_len(const DispList *dl)
54 {
55         switch (dl->type) {
56                 case DL_INDEX3:
57                         return dl->parts;
58                 case DL_INDEX4:
59                         return dl->parts * 2;
60                 case DL_SURF:
61                         return dl->totindex * 2;
62         }
63         return 0;
64 }
65
66 /* see: displist_get_allverts */
67 static int curve_render_surface_vert_len_get(const ListBase *lb)
68 {
69         int vert_len = 0;
70         for (const DispList *dl = lb->first; dl; dl = dl->next) {
71                 vert_len += dl_vert_len(dl);
72         }
73         return vert_len;
74 }
75
76 static int curve_render_surface_tri_len_get(const ListBase *lb)
77 {
78         int tri_len = 0;
79         for (const DispList *dl = lb->first; dl; dl = dl->next) {
80                 tri_len += dl_tri_len(dl);
81         }
82         return tri_len;
83 }
84
85 typedef void (SetTriIndicesFn)(void *thunk, uint v1, uint v2, uint v3);
86
87 static void displist_indexbufbuilder_set(
88         SetTriIndicesFn *set_tri_indices,
89         SetTriIndicesFn *set_quad_tri_indices, /* meh, find a better solution. */
90         void *thunk, const DispList *dl, const int ofs)
91 {
92         if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
93                 const int *idx = dl->index;
94                 if (dl->type == DL_INDEX3) {
95                         const int i_end = dl->parts;
96                         for (int i = 0; i < i_end; i++, idx += 3) {
97                                 set_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs);
98                         }
99                 }
100                 else if (dl->type == DL_SURF) {
101                         const int i_end = dl->totindex;
102                         for (int i = 0; i < i_end; i++, idx += 4) {
103                                 set_quad_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[1] + ofs);
104                                 set_quad_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[3] + ofs);
105                         }
106                 }
107                 else {
108                         BLI_assert(dl->type == DL_INDEX4);
109                         const int i_end = dl->parts;
110                         for (int i = 0; i < i_end; i++, idx += 4) {
111                                 if (idx[2] != idx[3]) {
112                                         set_quad_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[1] + ofs);
113                                         set_quad_tri_indices(thunk, idx[0] + ofs, idx[2] + ofs, idx[3] + ofs);
114                                 }
115                                 else {
116                                         set_tri_indices(thunk, idx[2] + ofs, idx[0] + ofs, idx[1] + ofs);
117                                 }
118                         }
119                 }
120         }
121 }
122
123 static int displist_indexbufbuilder_tess_set(
124         SetTriIndicesFn *set_tri_indices,
125         SetTriIndicesFn *set_quad_tri_indices, /* meh, find a better solution. */
126         void *thunk, const DispList *dl, const int ofs)
127 {
128         int v_idx = ofs;
129         if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
130                 if (dl->type == DL_INDEX3) {
131                         for (int i = 0; i < dl->parts; i++) {
132                                 set_tri_indices(thunk, v_idx + 0, v_idx + 1, v_idx + 2);
133                                 v_idx += 3;
134                         }
135                 }
136                 else if (dl->type == DL_SURF) {
137                         for (int a = 0; a < dl->parts; a++) {
138                                 if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) {
139                                         break;
140                                 }
141                                 int b = (dl->flag & DL_CYCL_U) ? 0 : 1;
142                                 for (; b < dl->nr; b++) {
143                                         set_quad_tri_indices(thunk, v_idx + 0, v_idx + 1, v_idx + 2);
144                                         set_quad_tri_indices(thunk, v_idx + 3, v_idx + 4, v_idx + 5);
145                                         v_idx += 6;
146                                 }
147                         }
148                 }
149                 else {
150                         BLI_assert(dl->type == DL_INDEX4);
151                         const int *idx = dl->index;
152                         for (int i = 0; i < dl->parts; i++, idx += 4) {
153                                 if (idx[2] != idx[3]) {
154                                         set_quad_tri_indices(thunk, v_idx + 0, v_idx + 1, v_idx + 2);
155                                         set_quad_tri_indices(thunk, v_idx + 3, v_idx + 4, v_idx + 5);
156                                         v_idx += 6;
157                                 }
158                                 else {
159                                         set_tri_indices(thunk, v_idx + 0, v_idx + 1, v_idx + 2);
160                                         v_idx += 3;
161                                 }
162                         }
163                 }
164         }
165         return v_idx;
166 }
167
168 void DRW_displist_vertbuf_create_pos_and_nor(ListBase *lb, GPUVertBuf *vbo)
169 {
170         static GPUVertFormat format = { 0 };
171         static struct { uint pos, nor; } attr_id;
172         if (format.attr_len == 0) {
173                 /* initialize vertex format */
174                 attr_id.pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
175                 attr_id.nor = GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
176         }
177
178         GPU_vertbuf_init_with_format(vbo, &format);
179         GPU_vertbuf_data_alloc(vbo, curve_render_surface_vert_len_get(lb));
180
181         BKE_displist_normals_add(lb);
182
183         int vbo_len_used = 0;
184         for (const DispList *dl = lb->first; dl; dl = dl->next) {
185                 const bool ndata_is_single = dl->type == DL_INDEX3;
186                 if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
187                         const float *fp_co = dl->verts;
188                         const float *fp_no = dl->nors;
189                         const int vbo_end = vbo_len_used + dl_vert_len(dl);
190                         while (vbo_len_used < vbo_end) {
191                                 GPU_vertbuf_attr_set(vbo, attr_id.pos, vbo_len_used, fp_co);
192                                 if (fp_no) {
193                                         static short short_no[4];
194                                         normal_float_to_short_v3(short_no, fp_no);
195                                         GPU_vertbuf_attr_set(vbo, attr_id.nor, vbo_len_used, short_no);
196                                         if (ndata_is_single == false) {
197                                                 fp_no += 3;
198                                         }
199                                 }
200                                 fp_co += 3;
201                                 vbo_len_used += 1;
202                         }
203                 }
204         }
205 }
206
207 void DRW_displist_indexbuf_create_triangles_in_order(ListBase *lb, GPUIndexBuf *ibo)
208 {
209         const int tri_len = curve_render_surface_tri_len_get(lb);
210         const int vert_len = curve_render_surface_vert_len_get(lb);
211
212         GPUIndexBufBuilder elb;
213         GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tri_len, vert_len);
214
215         int ofs = 0;
216         for (const DispList *dl = lb->first; dl; dl = dl->next) {
217                 displist_indexbufbuilder_set(
218                         (SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
219                         (SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
220                         &elb, dl, ofs);
221                 ofs += dl_vert_len(dl);
222         }
223
224         GPU_indexbuf_build_in_place(&elb, ibo);
225 }
226
227 void DRW_displist_indexbuf_create_triangles_tess_split_by_material(
228         ListBase *lb,
229         GPUIndexBuf **ibo_mats, uint mat_len)
230 {
231         GPUIndexBufBuilder *elb = BLI_array_alloca(elb, mat_len);
232
233         const int tri_len = curve_render_surface_tri_len_get(lb);
234
235         /* Init each index buffer builder */
236         for (int i = 0; i < mat_len; i++) {
237                 GPU_indexbuf_init(&elb[i], GPU_PRIM_TRIS, tri_len * 3, tri_len * 3);
238         }
239
240         /* calc each index buffer builder */
241         uint v_idx = 0;
242         for (const DispList *dl = lb->first; dl; dl = dl->next) {
243                 v_idx = displist_indexbufbuilder_tess_set(
244                         (SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
245                         (SetTriIndicesFn *)GPU_indexbuf_add_tri_verts,
246                         &elb[dl->col], dl, v_idx);
247         }
248
249         /* build each indexbuf */
250         for (int i = 0; i < mat_len; i++) {
251                 GPU_indexbuf_build_in_place(&elb[i], ibo_mats[i]);
252         }
253 }
254
255 typedef struct DRWDisplistWireThunk {
256         uint wd_id, ofs;
257         const DispList *dl;
258         GPUVertBuf *vbo;
259 } DRWDisplistWireThunk;
260
261 static void set_overlay_wires_tri_indices(void *thunk, uint v1, uint v2, uint v3)
262 {
263         DRWDisplistWireThunk *dwt = (DRWDisplistWireThunk *)thunk;
264         uint indices[3] = {v1, v2, v3};
265
266         for (int i = 0; i < 3; ++i) {
267                 /* TODO: Compute sharpness. For now, only tag real egdes. */
268                 uchar sharpness = 0xFF;
269                 GPU_vertbuf_attr_set(dwt->vbo, dwt->wd_id, indices[i], &sharpness);
270         }
271 }
272
273 static void set_overlay_wires_quad_tri_indices(void *thunk, uint v1, uint v2, uint v3)
274 {
275         DRWDisplistWireThunk *dwt = (DRWDisplistWireThunk *)thunk;
276         uint indices[3] = {v1, v2, v3};
277
278         for (int i = 0; i < 3; ++i) {
279                 /* TODO: Compute sharpness. For now, only tag real egdes. */
280                 uchar sharpness = (i == 0) ? 0x00 : 0xFF;
281                 GPU_vertbuf_attr_set(dwt->vbo, dwt->wd_id, indices[i], &sharpness);
282         }
283 }
284
285 /* TODO reuse the position and normals from other tesselation vertbuf. */
286 void DRW_displist_vertbuf_create_wireframe_data_tess(ListBase *lb, GPUVertBuf *vbo)
287 {
288         static DRWDisplistWireThunk thunk;
289         static GPUVertFormat format = {0};
290         if (format.attr_len == 0) {
291                 thunk.wd_id  = GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
292                 GPU_vertformat_triple_load(&format);
293         }
294
295         GPU_vertbuf_init_with_format(vbo, &format);
296         thunk.vbo = vbo;
297
298         int vert_len = curve_render_surface_tri_len_get(lb) * 3;
299         GPU_vertbuf_data_alloc(thunk.vbo, vert_len);
300
301         thunk.ofs = 0;
302         for (const DispList *dl = lb->first; dl; dl = dl->next) {
303                 thunk.dl = dl;
304                 /* TODO consider non-manifold edges correctly. */
305                 thunk.ofs = displist_indexbufbuilder_tess_set(
306                         set_overlay_wires_tri_indices,
307                         set_overlay_wires_quad_tri_indices,
308                         &thunk, dl, thunk.ofs);
309         }
310
311         if (thunk.ofs < vert_len) {
312                 GPU_vertbuf_data_resize(thunk.vbo, thunk.ofs);
313         }
314 }
315
316 static void surf_uv_quad(const DispList *dl, const uint quad[4], float r_uv[4][2])
317 {
318         int orco_sizeu = dl->nr - 1;
319         int orco_sizev = dl->parts - 1;
320
321         /* exception as handled in convertblender.c too */
322         if (dl->flag & DL_CYCL_U) {
323                 orco_sizeu++;
324         }
325         if (dl->flag & DL_CYCL_V) {
326                 orco_sizev++;
327         }
328
329         for (int i = 0; i < 4; i++) {
330                 /* find uv based on vertex index into grid array */
331                 r_uv[i][0] = (quad[i] / dl->nr) / (float)orco_sizev;
332                 r_uv[i][1] = (quad[i] % dl->nr) / (float)orco_sizeu;
333
334                 /* cyclic correction */
335                 if ((i == 1 || i == 2) && r_uv[i][0] == 0.0f) {
336                         r_uv[i][0] = 1.0f;
337                 }
338                 if ((i == 0 || i == 1) && r_uv[i][1] == 0.0f) {
339                         r_uv[i][1] = 1.0f;
340                 }
341         }
342 }
343
344 static void displist_vertbuf_attr_set_tri_pos_nor_uv(
345         GPUVertBufRaw *pos_step, GPUVertBufRaw *nor_step, GPUVertBufRaw *uv_step,
346         const float v1[3], const float v2[3], const float v3[3],
347         const GPUPackedNormal *n1, const GPUPackedNormal *n2, const GPUPackedNormal *n3,
348         const float uv1[2], const float uv2[2], const float uv3[2])
349 {
350         if (pos_step->size != 0) {
351                 copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v1);
352                 copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v2);
353                 copy_v3_v3(GPU_vertbuf_raw_step(pos_step), v3);
354
355                 *(GPUPackedNormal *)GPU_vertbuf_raw_step(nor_step) = *n1;
356                 *(GPUPackedNormal *)GPU_vertbuf_raw_step(nor_step) = *n2;
357                 *(GPUPackedNormal *)GPU_vertbuf_raw_step(nor_step) = *n3;
358         }
359
360         if (uv_step->size != 0) {
361                 normal_float_to_short_v2(GPU_vertbuf_raw_step(uv_step), uv1);
362                 normal_float_to_short_v2(GPU_vertbuf_raw_step(uv_step), uv2);
363                 normal_float_to_short_v2(GPU_vertbuf_raw_step(uv_step), uv3);
364         }
365 }
366
367 void DRW_displist_vertbuf_create_pos_and_nor_and_uv_tess(
368         ListBase *lb,
369         GPUVertBuf *vbo_pos_nor, GPUVertBuf *vbo_uv)
370 {
371         static GPUVertFormat format_pos_nor = { 0 };
372         static GPUVertFormat format_uv = { 0 };
373         static struct { uint pos, nor, uv; } attr_id;
374         if (format_pos_nor.attr_len == 0) {
375                 /* initialize vertex format */
376                 attr_id.pos = GPU_vertformat_attr_add(&format_pos_nor, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
377                 attr_id.nor = GPU_vertformat_attr_add(&format_pos_nor, "nor", GPU_COMP_I10, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
378                 GPU_vertformat_triple_load(&format_pos_nor);
379                 /* UVs are in [0..1] range. We can compress them. */
380                 attr_id.uv = GPU_vertformat_attr_add(&format_uv, "u", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT);
381         }
382
383         int vbo_len_capacity = curve_render_surface_tri_len_get(lb) * 3;
384
385         GPUVertBufRaw pos_step = {0};
386         GPUVertBufRaw nor_step = {0};
387         GPUVertBufRaw uv_step = {0};
388
389         if (DRW_TEST_ASSIGN_VBO(vbo_pos_nor)) {
390                 GPU_vertbuf_init_with_format(vbo_pos_nor, &format_pos_nor);
391                 GPU_vertbuf_data_alloc(vbo_pos_nor, vbo_len_capacity);
392                 GPU_vertbuf_attr_get_raw_data(vbo_pos_nor, attr_id.pos, &pos_step);
393                 GPU_vertbuf_attr_get_raw_data(vbo_pos_nor, attr_id.nor, &nor_step);
394         }
395         if (DRW_TEST_ASSIGN_VBO(vbo_uv)) {
396                 GPU_vertbuf_init_with_format(vbo_uv, &format_uv);
397                 GPU_vertbuf_data_alloc(vbo_uv, vbo_len_capacity);
398                 GPU_vertbuf_attr_get_raw_data(vbo_uv, attr_id.uv, &uv_step);
399         }
400
401         BKE_displist_normals_add(lb);
402
403         for (const DispList *dl = lb->first; dl; dl = dl->next) {
404                 const bool is_smooth = (dl->rt & CU_SMOOTH) != 0;
405                 if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
406                         const float(*verts)[3] = (float(*)[3])dl->verts;
407                         const float(*nors)[3] = (float(*)[3])dl->nors;
408                         const int *idx = dl->index;
409                         float uv[4][2];
410
411                         if (dl->type == DL_INDEX3) {
412                                 /* Currently 'DL_INDEX3' is always a flat surface with a single normal. */
413                                 const GPUPackedNormal pnor = GPU_normal_convert_i10_v3(dl->nors);
414                                 const float x_max = (float)(dl->nr - 1);
415                                 uv[0][1] = uv[1][1] = uv[2][1] = 0.0f;
416                                 const int i_end = dl->parts;
417                                 for (int i = 0; i < i_end; i++, idx += 3) {
418                                         if (vbo_uv) {
419                                                 uv[0][0] = idx[0] / x_max;
420                                                 uv[1][0] = idx[1] / x_max;
421                                                 uv[2][0] = idx[2] / x_max;
422                                         }
423
424                                         displist_vertbuf_attr_set_tri_pos_nor_uv(
425                                                 &pos_step, &nor_step, &uv_step,
426                                                 verts[idx[0]], verts[idx[2]], verts[idx[1]],
427                                                 &pnor, &pnor, &pnor,
428                                                 uv[0], uv[2], uv[1]);
429                                 }
430                         }
431                         else if (dl->type == DL_SURF) {
432                                 uint quad[4];
433                                 for (int a = 0; a < dl->parts; a++) {
434                                         if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) {
435                                                 break;
436                                         }
437
438                                         int b;
439                                         if (dl->flag & DL_CYCL_U) {
440                                                 quad[0] = dl->nr * a;
441                                                 quad[3] = quad[0] + dl->nr - 1;
442                                                 quad[1] = quad[0] + dl->nr;
443                                                 quad[2] = quad[3] + dl->nr;
444                                                 b = 0;
445                                         }
446                                         else {
447                                                 quad[3] = dl->nr * a;
448                                                 quad[0] = quad[3] + 1;
449                                                 quad[2] = quad[3] + dl->nr;
450                                                 quad[1] = quad[0] + dl->nr;
451                                                 b = 1;
452                                         }
453                                         if ((dl->flag & DL_CYCL_V) && a == dl->parts - 1) {
454                                                 quad[1] -= dl->parts * dl->nr;
455                                                 quad[2] -= dl->parts * dl->nr;
456                                         }
457
458                                         for (; b < dl->nr; b++) {
459                                                 if (vbo_uv) {
460                                                         surf_uv_quad(dl, quad, uv);
461                                                 }
462
463                                                 GPUPackedNormal pnors_quad[4];
464                                                 if (is_smooth) {
465                                                         for (int j = 0; j < 4; j++) {
466                                                                 pnors_quad[j] = GPU_normal_convert_i10_v3(nors[quad[j]]);
467                                                         }
468                                                 }
469                                                 else {
470                                                         float nor_flat[3];
471                                                         normal_quad_v3(nor_flat, verts[quad[0]], verts[quad[1]], verts[quad[2]], verts[quad[3]]);
472                                                         pnors_quad[0] = GPU_normal_convert_i10_v3(nor_flat);
473                                                         pnors_quad[1] = pnors_quad[0];
474                                                         pnors_quad[2] = pnors_quad[0];
475                                                         pnors_quad[3] = pnors_quad[0];
476                                                 }
477
478                                                 displist_vertbuf_attr_set_tri_pos_nor_uv(
479                                                         &pos_step, &nor_step, &uv_step,
480                                                         verts[quad[2]], verts[quad[0]], verts[quad[1]],
481                                                         &pnors_quad[2], &pnors_quad[0], &pnors_quad[1],
482                                                         uv[2], uv[0], uv[1]);
483
484                                                 displist_vertbuf_attr_set_tri_pos_nor_uv(
485                                                         &pos_step, &nor_step, &uv_step,
486                                                         verts[quad[0]], verts[quad[2]], verts[quad[3]],
487                                                         &pnors_quad[0], &pnors_quad[2], &pnors_quad[3],
488                                                         uv[0], uv[2], uv[3]);
489
490                                                 quad[2] = quad[1];
491                                                 quad[1]++;
492                                                 quad[3] = quad[0];
493                                                 quad[0]++;
494                                         }
495                                 }
496                         }
497                         else {
498                                 BLI_assert(dl->type == DL_INDEX4);
499                                 uv[0][0] = uv[0][1] = uv[1][0] = uv[3][1] = 0.0f;
500                                 uv[1][1] = uv[2][0] = uv[2][1] = uv[3][0] = 1.0f;
501
502                                 const int i_end = dl->parts;
503                                 for (int i = 0; i < i_end; i++, idx += 4) {
504                                         const bool is_tri = idx[2] != idx[3];
505
506                                         GPUPackedNormal pnors_idx[4];
507                                         if (is_smooth) {
508                                                 int idx_len = is_tri ? 3 : 4;
509                                                 for (int j = 0; j < idx_len; j++) {
510                                                         pnors_idx[j] = GPU_normal_convert_i10_v3(nors[idx[j]]);
511                                                 }
512                                         }
513                                         else {
514                                                 float nor_flat[3];
515                                                 if (is_tri) {
516                                                         normal_tri_v3(nor_flat, verts[idx[0]], verts[idx[1]], verts[idx[2]]);
517                                                 }
518                                                 else {
519                                                         normal_quad_v3(nor_flat, verts[idx[0]], verts[idx[1]], verts[idx[2]], verts[idx[3]]);
520                                                 }
521                                                 pnors_idx[0] = GPU_normal_convert_i10_v3(nor_flat);
522                                                 pnors_idx[1] = pnors_idx[0];
523                                                 pnors_idx[2] = pnors_idx[0];
524                                                 pnors_idx[3] = pnors_idx[0];
525                                         }
526
527                                         displist_vertbuf_attr_set_tri_pos_nor_uv(
528                                                 &pos_step, &nor_step, &uv_step,
529                                                 verts[idx[0]], verts[idx[2]], verts[idx[1]],
530                                                 &pnors_idx[0], &pnors_idx[2], &pnors_idx[1],
531                                                 uv[0], uv[2], uv[1]);
532
533                                         if (idx[2] != idx[3]) {
534                                                 displist_vertbuf_attr_set_tri_pos_nor_uv(
535                                                         &pos_step, &nor_step, &uv_step,
536                                                         verts[idx[2]], verts[idx[0]], verts[idx[3]],
537                                                         &pnors_idx[2], &pnors_idx[0], &pnors_idx[3],
538                                                         uv[2], uv[0], uv[3]);
539                                         }
540                                 }
541                         }
542                 }
543         }
544         /* Resize and finish. */
545         if (pos_step.size != 0) {
546                 int vbo_len_used = GPU_vertbuf_raw_used(&pos_step);
547                 if (vbo_len_used < vbo_len_capacity) {
548                         GPU_vertbuf_data_resize(vbo_pos_nor, vbo_len_used);
549                 }
550         }
551         if (uv_step.size != 0) {
552                 int vbo_len_used = GPU_vertbuf_raw_used(&uv_step);
553                 if (vbo_len_used < vbo_len_capacity) {
554                         GPU_vertbuf_data_resize(vbo_uv, vbo_len_used);
555                 }
556         }
557 }