DRW: optimize mesh data extraction
[blender.git] / source / blender / draw / intern / draw_cache_extract_mesh.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 Extraction of Mesh data into VBO to feed to GPU.
24  */
25
26 #include "MEM_guardedalloc.h"
27
28 #include "BLI_alloca.h"
29 #include "BLI_bitmap.h"
30 #include "BLI_buffer.h"
31 #include "BLI_edgehash.h"
32 #include "BLI_jitter_2d.h"
33 #include "BLI_math_bits.h"
34 #include "BLI_math_vector.h"
35 #include "BLI_string.h"
36 #include "BLI_task.h"
37 #include "BLI_utildefines.h"
38
39 #include "DNA_mesh_types.h"
40 #include "DNA_meshdata_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_scene_types.h"
43
44 #include "BKE_bvhutils.h"
45 #include "BKE_customdata.h"
46 #include "BKE_deform.h"
47 #include "BKE_editmesh.h"
48 #include "BKE_editmesh_bvh.h"
49 #include "BKE_editmesh_cache.h"
50 #include "BKE_editmesh_tangent.h"
51 #include "BKE_mesh.h"
52 #include "BKE_mesh_runtime.h"
53 #include "BKE_mesh_tangent.h"
54 #include "BKE_modifier.h"
55 #include "BKE_object_deform.h"
56
57 #include "atomic_ops.h"
58
59 #include "bmesh.h"
60
61 #include "GPU_batch.h"
62 #include "GPU_extensions.h"
63
64 #include "DRW_render.h"
65
66 #include "ED_mesh.h"
67 #include "ED_uvedit.h"
68
69 #include "draw_cache_impl.h"
70 #include "draw_cache_inline.h"
71
72 #include "draw_cache_extract.h"
73
74 // #define DEBUG_TIME
75
76 #ifdef DEBUG_TIME
77 #  include "PIL_time_utildefines.h"
78 #endif
79
80 /* ---------------------------------------------------------------------- */
81 /** \name Mesh/BMesh Interface (indirect, partially cached access to complex data).
82  * \{ */
83
84 typedef struct MeshRenderData {
85   eMRExtractType extract_type;
86
87   int poly_len, edge_len, vert_len, loop_len;
88   int edge_loose_len;
89   int vert_loose_len;
90   int loop_loose_len;
91   int tri_len;
92   int mat_len;
93
94   bool use_hide;
95   bool use_subsurf_fdots;
96   bool use_final_mesh;
97
98   /** Use for #MeshStatVis calculation which use world-space coords. */
99   float obmat[4][4];
100
101   const ToolSettings *toolsettings;
102   /* HACK not supposed to be there but it's needed. */
103   struct MeshBatchCache *cache;
104   /** Edit Mesh */
105   BMEditMesh *edit_bmesh;
106   BMesh *bm;
107   EditMeshData *edit_data;
108
109   /* For deformed edit-mesh data. */
110   /* Use for #ME_WRAPPER_TYPE_BMESH. */
111   const float (*bm_vert_coords)[3];
112   const float (*bm_vert_normals)[3];
113   const float (*bm_poly_normals)[3];
114   const float (*bm_poly_centers)[3];
115
116   int *v_origindex, *e_origindex, *p_origindex;
117   int crease_ofs;
118   int bweight_ofs;
119   int freestyle_edge_ofs;
120   int freestyle_face_ofs;
121   /** Mesh */
122   Mesh *me;
123   const MVert *mvert;
124   const MEdge *medge;
125   const MLoop *mloop;
126   const MPoly *mpoly;
127   BMVert *eve_act;
128   BMEdge *eed_act;
129   BMFace *efa_act;
130   BMFace *efa_act_uv;
131   /* Data created on-demand (usually not for #BMesh based data). */
132   MLoopTri *mlooptri;
133   float (*loop_normals)[3];
134   float (*poly_normals)[3];
135   int *lverts, *ledges;
136 } MeshRenderData;
137
138 static void mesh_render_data_update_loose_geom(MeshRenderData *mr,
139                                                const eMRIterType iter_type,
140                                                const eMRDataType UNUSED(data_flag))
141 {
142   if (mr->extract_type != MR_EXTRACT_BMESH) {
143     /* Mesh */
144     if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
145       mr->vert_loose_len = 0;
146       mr->edge_loose_len = 0;
147
148       BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
149
150       mr->ledges = MEM_mallocN(mr->edge_len * sizeof(int), __func__);
151       const MEdge *med = mr->medge;
152       for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) {
153         if (med->flag & ME_LOOSEEDGE) {
154           mr->ledges[mr->edge_loose_len++] = med_index;
155         }
156         /* Tag verts as not loose. */
157         BLI_BITMAP_ENABLE(lvert_map, med->v1);
158         BLI_BITMAP_ENABLE(lvert_map, med->v2);
159       }
160       if (mr->edge_loose_len < mr->edge_len) {
161         mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges));
162       }
163
164       mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
165       for (int v = 0; v < mr->vert_len; v++) {
166         if (!BLI_BITMAP_TEST(lvert_map, v)) {
167           mr->lverts[mr->vert_loose_len++] = v;
168         }
169       }
170       if (mr->vert_loose_len < mr->vert_len) {
171         mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts));
172       }
173
174       MEM_freeN(lvert_map);
175
176       mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2);
177     }
178   }
179   else {
180     /* #BMesh */
181     BMesh *bm = mr->bm;
182     if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
183       int elem_id;
184       BMIter iter;
185       BMVert *eve;
186       BMEdge *ede;
187       mr->vert_loose_len = 0;
188       mr->edge_loose_len = 0;
189
190       mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
191       BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
192         if (eve->e == NULL) {
193           mr->lverts[mr->vert_loose_len++] = elem_id;
194         }
195       }
196       if (mr->vert_loose_len < mr->vert_len) {
197         mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts));
198       }
199
200       mr->ledges = MEM_mallocN(mr->edge_len * sizeof(*mr->ledges), __func__);
201       BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
202         if (ede->l == NULL) {
203           mr->ledges[mr->edge_loose_len++] = elem_id;
204         }
205       }
206       if (mr->edge_loose_len < mr->edge_len) {
207         mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges));
208       }
209
210       mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2;
211     }
212   }
213 }
214
215 /**
216  * Part of the creation of the #MeshRenderData that happens in a thread.
217  */
218 static void mesh_render_data_update_looptris(MeshRenderData *mr,
219                                              const eMRIterType iter_type,
220                                              const eMRDataType data_flag)
221 {
222   Mesh *me = mr->me;
223   if (mr->extract_type != MR_EXTRACT_BMESH) {
224     /* Mesh */
225     if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
226       mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI");
227       BKE_mesh_recalc_looptri(
228           me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mr->mlooptri);
229     }
230   }
231   else {
232     /* #BMesh */
233     if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
234       /* Edit mode ensures this is valid, no need to calculate. */
235       BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL));
236     }
237   }
238 }
239
240 static void mesh_render_data_update_normals(MeshRenderData *mr,
241                                             const eMRIterType UNUSED(iter_type),
242                                             const eMRDataType data_flag)
243 {
244   Mesh *me = mr->me;
245   const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
246   const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI;
247
248   if (mr->extract_type != MR_EXTRACT_BMESH) {
249     /* Mesh */
250     if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
251       mr->poly_normals = MEM_mallocN(sizeof(*mr->poly_normals) * mr->poly_len, __func__);
252       BKE_mesh_calc_normals_poly((MVert *)mr->mvert,
253                                  NULL,
254                                  mr->vert_len,
255                                  mr->mloop,
256                                  mr->mpoly,
257                                  mr->loop_len,
258                                  mr->poly_len,
259                                  mr->poly_normals,
260                                  true);
261     }
262     if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
263       mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
264       short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL);
265       BKE_mesh_normals_loop_split(mr->me->mvert,
266                                   mr->vert_len,
267                                   mr->me->medge,
268                                   mr->edge_len,
269                                   mr->me->mloop,
270                                   mr->loop_normals,
271                                   mr->loop_len,
272                                   mr->me->mpoly,
273                                   mr->poly_normals,
274                                   mr->poly_len,
275                                   is_auto_smooth,
276                                   split_angle,
277                                   NULL,
278                                   clnors,
279                                   NULL);
280     }
281   }
282   else {
283     /* #BMesh */
284     if (data_flag & MR_DATA_POLY_NOR) {
285       /* Use #BMFace.no instead. */
286     }
287     if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
288
289       const float(*vert_coords)[3] = NULL;
290       const float(*vert_normals)[3] = NULL;
291       const float(*poly_normals)[3] = NULL;
292
293       if (mr->edit_data && mr->edit_data->vertexCos) {
294         vert_coords = mr->bm_vert_coords;
295         vert_normals = mr->bm_vert_normals;
296         poly_normals = mr->bm_poly_normals;
297       }
298
299       mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
300       const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL);
301       BM_loops_calc_normal_vcos(mr->bm,
302                                 vert_coords,
303                                 vert_normals,
304                                 poly_normals,
305                                 is_auto_smooth,
306                                 split_angle,
307                                 mr->loop_normals,
308                                 NULL,
309                                 NULL,
310                                 clnors_offset,
311                                 false);
312     }
313   }
314 }
315
316 static MeshRenderData *mesh_render_data_create(Mesh *me,
317                                                const bool is_editmode,
318                                                const bool is_paint_mode,
319                                                const float obmat[4][4],
320                                                const bool do_final,
321                                                const bool do_uvedit,
322                                                const DRW_MeshCDMask *UNUSED(cd_used),
323                                                const ToolSettings *ts,
324                                                const eMRIterType iter_type,
325                                                const eMRDataType data_flag)
326 {
327   MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
328   mr->toolsettings = ts;
329   mr->mat_len = mesh_render_mat_len_get(me);
330
331   copy_m4_m4(mr->obmat, obmat);
332
333   if (is_editmode) {
334     BLI_assert(me->edit_mesh->mesh_eval_cage && me->edit_mesh->mesh_eval_final);
335     mr->bm = me->edit_mesh->bm;
336     mr->edit_bmesh = me->edit_mesh;
337     mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage;
338     mr->edit_data = mr->me->runtime.edit_data;
339
340     if (mr->edit_data) {
341       EditMeshData *emd = mr->edit_data;
342       if (emd->vertexCos) {
343         BKE_editmesh_cache_ensure_vert_normals(mr->edit_bmesh, emd);
344         BKE_editmesh_cache_ensure_poly_normals(mr->edit_bmesh, emd);
345       }
346
347       mr->bm_vert_coords = mr->edit_data->vertexCos;
348       mr->bm_vert_normals = mr->edit_data->vertexNos;
349       mr->bm_poly_normals = mr->edit_data->polyNos;
350       mr->bm_poly_centers = mr->edit_data->polyCos;
351     }
352
353     bool has_mdata = (mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA);
354     bool use_mapped = has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original;
355
356     int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE;
357
358     BM_mesh_elem_index_ensure(mr->bm, bm_ensure_types);
359     BM_mesh_elem_table_ensure(mr->bm, bm_ensure_types & ~BM_LOOP);
360
361     mr->efa_act_uv = EDBM_uv_active_face_get(mr->edit_bmesh, false, false);
362     mr->efa_act = BM_mesh_active_face_get(mr->bm, false, true);
363     mr->eed_act = BM_mesh_active_edge_get(mr->bm);
364     mr->eve_act = BM_mesh_active_vert_get(mr->bm);
365
366     mr->crease_ofs = CustomData_get_offset(&mr->bm->edata, CD_CREASE);
367     mr->bweight_ofs = CustomData_get_offset(&mr->bm->edata, CD_BWEIGHT);
368 #ifdef WITH_FREESTYLE
369     mr->freestyle_edge_ofs = CustomData_get_offset(&mr->bm->edata, CD_FREESTYLE_EDGE);
370     mr->freestyle_face_ofs = CustomData_get_offset(&mr->bm->pdata, CD_FREESTYLE_FACE);
371 #endif
372
373     if (use_mapped) {
374       mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
375       mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
376       mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
377
378       use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
379     }
380
381     mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_BMESH;
382
383     /* Seems like the mesh_eval_final do not have the right origin indices.
384      * Force not mapped in this case. */
385     if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
386       // mr->edit_bmesh = NULL;
387       mr->extract_type = MR_EXTRACT_MESH;
388     }
389   }
390   else {
391     mr->me = me;
392     mr->edit_bmesh = NULL;
393
394     bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original;
395     if (use_mapped) {
396       mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
397       mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
398       mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
399
400       use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
401     }
402
403     mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_MESH;
404   }
405
406   if (mr->extract_type != MR_EXTRACT_BMESH) {
407     /* Mesh */
408     mr->vert_len = mr->me->totvert;
409     mr->edge_len = mr->me->totedge;
410     mr->loop_len = mr->me->totloop;
411     mr->poly_len = mr->me->totpoly;
412     mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
413
414     mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT);
415     mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE);
416     mr->mloop = CustomData_get_layer(&mr->me->ldata, CD_MLOOP);
417     mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY);
418
419     mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
420     mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
421     mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
422   }
423   else {
424     /* #BMesh */
425     BMesh *bm = mr->bm;
426
427     mr->vert_len = bm->totvert;
428     mr->edge_len = bm->totedge;
429     mr->loop_len = bm->totloop;
430     mr->poly_len = bm->totface;
431     mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
432   }
433   mesh_render_data_update_loose_geom(mr, iter_type, data_flag);
434
435   return mr;
436 }
437
438 static void mesh_render_data_free(MeshRenderData *mr)
439 {
440   MEM_SAFE_FREE(mr->mlooptri);
441   MEM_SAFE_FREE(mr->poly_normals);
442   MEM_SAFE_FREE(mr->loop_normals);
443
444   MEM_SAFE_FREE(mr->lverts);
445   MEM_SAFE_FREE(mr->ledges);
446
447   MEM_freeN(mr);
448 }
449
450 BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx)
451 {
452   return ((mr->p_origindex != NULL) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
453              BM_face_at_index(mr->bm, mr->p_origindex[idx]) :
454              NULL;
455 }
456
457 BLI_INLINE BMEdge *bm_original_edge_get(const MeshRenderData *mr, int idx)
458 {
459   return ((mr->e_origindex != NULL) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
460              BM_edge_at_index(mr->bm, mr->e_origindex[idx]) :
461              NULL;
462 }
463
464 BLI_INLINE BMVert *bm_original_vert_get(const MeshRenderData *mr, int idx)
465 {
466   return ((mr->v_origindex != NULL) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
467              BM_vert_at_index(mr->bm, mr->v_origindex[idx]) :
468              NULL;
469 }
470
471 BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve)
472 {
473   const float(*vert_coords)[3] = mr->bm_vert_coords;
474   if (vert_coords != NULL) {
475     return vert_coords[BM_elem_index_get(eve)];
476   }
477   else {
478     UNUSED_VARS(mr);
479     return eve->co;
480   }
481 }
482
483 BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve)
484 {
485   const float(*vert_normals)[3] = mr->bm_vert_normals;
486   if (vert_normals != NULL) {
487     return vert_normals[BM_elem_index_get(eve)];
488   }
489   else {
490     UNUSED_VARS(mr);
491     return eve->no;
492   }
493 }
494
495 BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa)
496 {
497   const float(*poly_normals)[3] = mr->bm_poly_normals;
498   if (poly_normals != NULL) {
499     return poly_normals[BM_elem_index_get(efa)];
500   }
501   else {
502     UNUSED_VARS(mr);
503     return efa->no;
504   }
505 }
506
507 /** \} */
508
509 /* ---------------------------------------------------------------------- */
510 /** \name Mesh Elements Extract: Loop Triangles
511  * \{ */
512
513 typedef struct ExtractTriBMesh_Params {
514   BMLoop *(*looptris)[3];
515   int tri_range[2];
516 } ExtractTriBMesh_Params;
517 typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr,
518                                 const ExtractTriBMesh_Params *params,
519                                 void *data);
520
521 #define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elem_tri, index_tri, params) \
522   CHECK_TYPE(params, const ExtractTriBMesh_Params *); \
523   { \
524     const int _tri_index_end = (params)->tri_range[1]; \
525     BMLoop **elem_tri = (params)->looptris[(params)->tri_range[0]]; \
526     for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
527          index_tri += 1, elem_tri += 3)
528 #define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END }
529
530 typedef struct ExtractTriMesh_Params {
531   const MLoopTri *mlooptri;
532   int tri_range[2];
533 } ExtractTriMesh_Params;
534 typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
535                                const ExtractTriMesh_Params *params,
536                                void *data);
537
538 #define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(elem_tri, index_tri, params) \
539   CHECK_TYPE(params, const ExtractTriMesh_Params *); \
540   { \
541     const int _tri_index_end = (params)->tri_range[1]; \
542     const MLoopTri *elem_tri = &(params)->mlooptri[(params)->tri_range[0]]; \
543     for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
544          index_tri += 1, elem_tri += 1)
545 #define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END }
546
547 /** \} */
548
549 /* ---------------------------------------------------------------------- */
550 /** \name Mesh Elements Extract: Polygons, Loops
551  * \{ */
552
553 typedef struct ExtractPolyBMesh_Params {
554   BMLoop *(*looptris)[3];
555   int poly_range[2];
556 } ExtractPolyBMesh_Params;
557 typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
558                                  const ExtractPolyBMesh_Params *params,
559                                  void *data);
560
561 #define EXTRACT_POLY_FOREACH_BM_BEGIN(elem_poly, index_poly, params, mr) \
562   CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
563   { \
564     BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
565     BMFace **_ftable = mr->bm->ftable; \
566     const int _poly_index_end = (params)->poly_range[1]; \
567     for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
568          index_poly += 1) { \
569       BMFace *elem_poly = _ftable[index_poly]; \
570       (void)elem_poly;
571
572 #define EXTRACT_POLY_FOREACH_BM_END \
573   } \
574   }
575
576 /* Iterate over polygon and loop. */
577 #define EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(elem_loop, index_loop, params, mr) \
578   CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
579   { \
580     BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
581     BMFace **_ftable = mr->bm->ftable; \
582     const int _poly_index_end = (params)->poly_range[1]; \
583     for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
584          index_poly += 1) { \
585       BMFace *elem_face = _ftable[index_poly]; \
586       BMLoop *elem_loop, *l_first; \
587       elem_loop = l_first = BM_FACE_FIRST_LOOP(elem_face); \
588       do { \
589         const int index_loop = BM_elem_index_get(elem_loop); \
590         (void)index_loop; /* Quiet warning when unused. */
591
592 #define EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(elem_loop) \
593   } \
594   while ((elem_loop = elem_loop->next) != l_first) \
595     ; \
596   } \
597   }
598
599 typedef struct ExtractPolyMesh_Params {
600   int poly_range[2];
601 } ExtractPolyMesh_Params;
602 typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
603                                 const ExtractPolyMesh_Params *params,
604                                 void *data);
605
606 #define EXTRACT_POLY_FOREACH_MESH_BEGIN(elem_poly, index_poly, params, mr) \
607   CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
608   { \
609     const MPoly *_mpoly = mr->mpoly; \
610     const int _poly_index_end = (params)->poly_range[1]; \
611     for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
612          index_poly += 1) { \
613       const MPoly *elem_poly = &_mpoly[index_poly]; \
614       (void)elem_poly;
615
616 #define EXTRACT_POLY_FOREACH_MESH_END \
617   } \
618   }
619
620 /* Iterate over polygon and loop. */
621 #define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN( \
622     elem_poly, index_poly, elem_loop, index_loop, params, mr) \
623   CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
624   { \
625     const MPoly *_mpoly = mr->mpoly; \
626     const MLoop *_mloop = mr->mloop; \
627     const int _poly_index_end = (params)->poly_range[1]; \
628     for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
629          index_poly += 1) { \
630       const MPoly *elem_poly = &_mpoly[index_poly]; \
631       const int _index_end = elem_poly->loopstart + elem_poly->totloop; \
632       for (int index_loop = elem_poly->loopstart; index_loop < _index_end; index_loop += 1) { \
633         const MLoop *elem_loop = &_mloop[index_loop]; \
634         (void)elem_loop;
635
636 #define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END \
637   } \
638   } \
639   }
640
641 /** \} */
642
643 /* ---------------------------------------------------------------------- */
644 /** \name Mesh Elements Extract: Loose Edges
645  * \{ */
646
647 typedef struct ExtractLEdgeBMesh_Params {
648   const int *ledge;
649   int ledge_range[2];
650 } ExtractLEdgeBMesh_Params;
651 typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
652                                   const ExtractLEdgeBMesh_Params *params,
653                                   void *data);
654
655 #define EXTRACT_LEDGE_FOREACH_BM_BEGIN(elem_edge, index_ledge, params) \
656   CHECK_TYPE(params, const ExtractLEdgeBMesh_Params *); \
657   { \
658     BLI_assert((mr->bm->elem_table_dirty & BM_EDGE) == 0); \
659     BMEdge **_etable = mr->bm->etable; \
660     const int *_ledge = (params)->ledge; \
661     const int _ledge_index_end = (params)->ledge_range[1]; \
662     for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
663          index_ledge += 1) { \
664       BMEdge *elem_edge = _etable[_ledge[index_ledge]]; \
665       (void)elem_edge; /* Quiet warning when unused. */ \
666       {
667 #define EXTRACT_LEDGE_FOREACH_BM_END \
668   } \
669   } \
670   }
671
672 typedef struct ExtractLEdgeMesh_Params {
673   const int *ledge;
674   int ledge_range[2];
675 } ExtractLEdgeMesh_Params;
676 typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
677                                  const ExtractLEdgeMesh_Params *params,
678                                  void *data);
679
680 #define EXTRACT_LEDGE_FOREACH_MESH_BEGIN(elem_edge, index_ledge, params, mr) \
681   CHECK_TYPE(params, const ExtractLEdgeMesh_Params *); \
682   { \
683     const MEdge *_medge = mr->medge; \
684     const int *_ledge = (params)->ledge; \
685     const int _ledge_index_end = (params)->ledge_range[1]; \
686     for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
687          index_ledge += 1) { \
688       const MEdge *elem_edge = &_medge[_ledge[index_ledge]]; \
689       (void)elem_edge; /* Quiet warning when unused. */ \
690       {
691 #define EXTRACT_LEDGE_FOREACH_MESH_END \
692   } \
693   } \
694   }
695
696 /** \} */
697
698 /* ---------------------------------------------------------------------- */
699 /** \name Mesh Elements Extract: Loose Vertices
700  * \{ */
701
702 typedef struct ExtractLVertBMesh_Params {
703   const int *lvert;
704   int lvert_range[2];
705 } ExtractLVertBMesh_Params;
706 typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
707                                   const ExtractLVertBMesh_Params *params,
708                                   void *data);
709
710 #define EXTRACT_LVERT_FOREACH_BM_BEGIN(elem_vert, index_lvert, params) \
711   CHECK_TYPE(params, const ExtractLVertBMesh_Params *); \
712   { \
713     BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
714     BMVert **vtable = mr->bm->vtable; \
715     const int *lverts = (params)->lvert; \
716     const int _lvert_index_end = (params)->lvert_range[1]; \
717     for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
718          index_lvert += 1) { \
719       BMVert *elem_vert = vtable[lverts[index_lvert]]; \
720       (void)elem_vert; /* Quiet warning when unused. */ \
721       {
722 #define EXTRACT_LVERT_FOREACH_BM_END \
723   } \
724   } \
725   }
726
727 typedef struct ExtractLVertMesh_Params {
728   const int *lvert;
729   int lvert_range[2];
730 } ExtractLVertMesh_Params;
731 typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
732                                  const ExtractLVertMesh_Params *params,
733                                  void *data);
734
735 #define EXTRACT_LVERT_FOREACH_MESH_BEGIN(elem, index_lvert, params, mr) \
736   CHECK_TYPE(params, const ExtractLVertMesh_Params *); \
737   { \
738     const MVert *mvert = mr->mvert; \
739     const int *lverts = (params)->lvert; \
740     const int _lvert_index_end = (params)->lvert_range[1]; \
741     for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
742          index_lvert += 1) { \
743       const MVert *elem = &mvert[lverts[index_lvert]]; \
744       (void)elem; /* Quiet warning when unused. */ \
745       {
746 #define EXTRACT_LVERT_FOREACH_MESH_END \
747   } \
748   } \
749   }
750
751 /** \} */
752
753 /* ---------------------------------------------------------------------- */
754 /** \name Mesh Elements Extract Struct
755  * \{ */
756
757 typedef void *(ExtractInitFn)(const MeshRenderData *mr, void *buffer);
758 typedef void(ExtractFinishFn)(const MeshRenderData *mr, void *buffer, void *data);
759
760 typedef struct MeshExtract {
761   /** Executed on main thread and return user data for iteration functions. */
762   ExtractInitFn *init;
763   /** Executed on one (or more if use_threading) worker thread(s). */
764   ExtractTriBMeshFn *iter_looptri_bm;
765   ExtractTriMeshFn *iter_looptri_mesh;
766   ExtractPolyBMeshFn *iter_poly_bm;
767   ExtractPolyMeshFn *iter_poly_mesh;
768   ExtractLEdgeBMeshFn *iter_ledge_bm;
769   ExtractLEdgeMeshFn *iter_ledge_mesh;
770   ExtractLVertBMeshFn *iter_lvert_bm;
771   ExtractLVertMeshFn *iter_lvert_mesh;
772   /** Executed on one worker thread after all elements iterations. */
773   ExtractFinishFn *finish;
774   /** Used to request common data. */
775   const eMRDataType data_flag;
776   /** Used to know if the element callbacks are thread-safe and can be parallelized. */
777   const bool use_threading;
778 } MeshExtract;
779
780 BLI_INLINE eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
781 {
782   eMRIterType type = 0;
783   SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI);
784   SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY);
785   SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE);
786   SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert_mesh), MR_ITER_LVERT);
787   return type;
788 }
789
790 /** \} */
791
792 /* ---------------------------------------------------------------------- */
793 /** \name Extract Triangles Indices
794  * \{ */
795
796 typedef struct MeshExtract_Tri_Data {
797   GPUIndexBufBuilder elb;
798   int *tri_mat_start;
799   int *tri_mat_end;
800 } MeshExtract_Tri_Data;
801
802 static void *extract_tris_init(const MeshRenderData *mr, void *UNUSED(ibo))
803 {
804   MeshExtract_Tri_Data *data = MEM_callocN(sizeof(*data), __func__);
805
806   size_t mat_tri_idx_size = sizeof(int) * mr->mat_len;
807   data->tri_mat_start = MEM_callocN(mat_tri_idx_size, __func__);
808   data->tri_mat_end = MEM_callocN(mat_tri_idx_size, __func__);
809
810   int *mat_tri_len = data->tri_mat_start;
811   /* Count how many triangle for each material. */
812   if (mr->extract_type == MR_EXTRACT_BMESH) {
813     BMIter iter;
814     BMFace *efa;
815     BM_ITER_MESH (efa, &iter, mr->bm, BM_FACES_OF_MESH) {
816       if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
817         int mat = min_ii(efa->mat_nr, mr->mat_len - 1);
818         mat_tri_len[mat] += efa->len - 2;
819       }
820     }
821   }
822   else {
823     const MPoly *mp = mr->mpoly;
824     for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
825       if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
826         int mat = min_ii(mp->mat_nr, mr->mat_len - 1);
827         mat_tri_len[mat] += mp->totloop - 2;
828       }
829     }
830   }
831   /* Accumulate triangle lengths per material to have correct offsets. */
832   int ofs = mat_tri_len[0];
833   mat_tri_len[0] = 0;
834   for (int i = 1; i < mr->mat_len; i++) {
835     int tmp = mat_tri_len[i];
836     mat_tri_len[i] = ofs;
837     ofs += tmp;
838   }
839
840   memcpy(data->tri_mat_end, mat_tri_len, mat_tri_idx_size);
841
842   int visible_tri_tot = ofs;
843   GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, visible_tri_tot, mr->loop_len);
844
845   return data;
846 }
847
848 static void extract_tris_iter_looptri_bm(const MeshRenderData *mr,
849                                          const struct ExtractTriBMesh_Params *params,
850                                          void *_data)
851 {
852   MeshExtract_Tri_Data *data = _data;
853   const int mat_last = mr->mat_len - 1;
854   EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params)
855   {
856     if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
857       int *mat_tri_ofs = data->tri_mat_end;
858       const int mat = min_ii(elt[0]->f->mat_nr, mat_last);
859       GPU_indexbuf_set_tri_verts(&data->elb,
860                                  mat_tri_ofs[mat]++,
861                                  BM_elem_index_get(elt[0]),
862                                  BM_elem_index_get(elt[1]),
863                                  BM_elem_index_get(elt[2]));
864     }
865   }
866   EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END;
867 }
868
869 static void extract_tris_iter_looptri_mesh(const MeshRenderData *mr,
870                                            const struct ExtractTriMesh_Params *params,
871                                            void *_data)
872 {
873   MeshExtract_Tri_Data *data = _data;
874   const int mat_last = mr->mat_len - 1;
875   EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params)
876   {
877     const MPoly *mp = &mr->mpoly[mlt->poly];
878     if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
879       int *mat_tri_ofs = data->tri_mat_end;
880       const int mat = min_ii(mp->mat_nr, mat_last);
881       GPU_indexbuf_set_tri_verts(
882           &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
883     }
884   }
885   EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END;
886 }
887
888 static void extract_tris_finish(const MeshRenderData *mr, void *ibo, void *_data)
889 {
890   MeshExtract_Tri_Data *data = _data;
891   GPU_indexbuf_build_in_place(&data->elb, ibo);
892   /* HACK: Create ibo sub-ranges and assign them to each #GPUBatch. */
893   if (mr->use_final_mesh && mr->cache->surface_per_mat && mr->cache->surface_per_mat[0]) {
894     BLI_assert(mr->cache->surface_per_mat[0]->elem == ibo);
895     for (int i = 0; i < mr->mat_len; i++) {
896       /* Multiply by 3 because these are triangle indices. */
897       const int start = data->tri_mat_start[i] * 3;
898       const int len = data->tri_mat_end[i] * 3 - data->tri_mat_start[i] * 3;
899       GPUIndexBuf *sub_ibo = GPU_indexbuf_create_subrange(ibo, start, len);
900       /* WARNING: We modify the #GPUBatch here! */
901       GPU_batch_elembuf_set(mr->cache->surface_per_mat[i], sub_ibo, true);
902     }
903   }
904   MEM_freeN(data->tri_mat_start);
905   MEM_freeN(data->tri_mat_end);
906   MEM_freeN(data);
907 }
908
909 static const MeshExtract extract_tris = {
910     .init = extract_tris_init,
911     .iter_looptri_bm = extract_tris_iter_looptri_bm,
912     .iter_looptri_mesh = extract_tris_iter_looptri_mesh,
913     .finish = extract_tris_finish,
914     .data_flag = 0,
915     .use_threading = false,
916 };
917
918 /** \} */
919
920 /* ---------------------------------------------------------------------- */
921 /** \name Extract Edges Indices
922  * \{ */
923
924 static void *extract_lines_init(const MeshRenderData *mr, void *UNUSED(buf))
925 {
926   GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
927   /* Put loose edges at the end. */
928   GPU_indexbuf_init(
929       elb, GPU_PRIM_LINES, mr->edge_len + mr->edge_loose_len, mr->loop_len + mr->loop_loose_len);
930   return elb;
931 }
932
933 static void extract_lines_iter_poly_bm(const MeshRenderData *mr,
934                                        const ExtractPolyBMesh_Params *params,
935                                        void *elb)
936 {
937   /* Using poly & loop iterator would complicate accessing the adjacent loop. */
938   EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
939   {
940     BMLoop *l_iter, *l_first;
941     /* Use #BMLoop.prev to match mesh order (to avoid minor differences in data extraction). */
942     l_iter = l_first = BM_FACE_FIRST_LOOP(f)->prev;
943     do {
944       if (!BM_elem_flag_test(l_iter->e, BM_ELEM_HIDDEN)) {
945         GPU_indexbuf_set_line_verts(elb,
946                                     BM_elem_index_get(l_iter->e),
947                                     BM_elem_index_get(l_iter),
948                                     BM_elem_index_get(l_iter->next));
949       }
950       else {
951         GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(l_iter->e));
952       }
953     } while ((l_iter = l_iter->next) != l_first);
954   }
955   EXTRACT_POLY_FOREACH_BM_END;
956 }
957
958 static void extract_lines_iter_poly_mesh(const MeshRenderData *mr,
959                                          const ExtractPolyMesh_Params *params,
960                                          void *elb)
961 {
962   /* Using poly & loop iterator would complicate accessing the adjacent loop. */
963   const MLoop *mloop = mr->mloop;
964   const MEdge *medge = mr->medge;
965   if (mr->use_hide || (mr->extract_type == MR_EXTRACT_MAPPED) || (mr->e_origindex != NULL)) {
966     EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
967     {
968       const int ml_index_last = mp->loopstart + (mp->totloop - 1);
969       int ml_index = ml_index_last, ml_index_next = mp->loopstart;
970       do {
971         const MLoop *ml = &mloop[ml_index];
972         const MEdge *med = &medge[ml->e];
973         if (!((mr->use_hide && (med->flag & ME_HIDE)) ||
974               ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
975                (mr->e_origindex[ml->e] == ORIGINDEX_NONE)))) {
976           GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next);
977         }
978         else {
979           GPU_indexbuf_set_line_restart(elb, ml->e);
980         }
981       } while ((ml_index = ml_index_next++) != ml_index_last);
982     }
983     EXTRACT_POLY_FOREACH_MESH_END;
984   }
985   else {
986     EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
987     {
988       const int ml_index_last = mp->loopstart + (mp->totloop - 1);
989       int ml_index = ml_index_last, ml_index_next = mp->loopstart;
990       do {
991         const MLoop *ml = &mloop[ml_index];
992         GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next);
993       } while ((ml_index = ml_index_next++) != ml_index_last);
994     }
995     EXTRACT_POLY_FOREACH_MESH_END;
996   }
997 }
998
999 static void extract_lines_iter_ledge_bm(const MeshRenderData *mr,
1000                                         const ExtractLEdgeBMesh_Params *params,
1001                                         void *elb)
1002 {
1003   EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
1004   {
1005     const int l_index_offset = mr->edge_len + ledge_index;
1006     if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
1007       const int l_index = mr->loop_len + ledge_index * 2;
1008       GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1);
1009     }
1010     else {
1011       GPU_indexbuf_set_line_restart(elb, l_index_offset);
1012     }
1013     /* Don't render the edge twice. */
1014     GPU_indexbuf_set_line_restart(elb, BM_elem_index_get(eed));
1015   }
1016   EXTRACT_LEDGE_FOREACH_BM_END;
1017 }
1018
1019 static void extract_lines_iter_ledge_mesh(const MeshRenderData *mr,
1020                                           const ExtractLEdgeMesh_Params *params,
1021                                           void *elb)
1022 {
1023   EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
1024   {
1025     const int l_index_offset = mr->edge_len + ledge_index;
1026     const int e_index = mr->ledges[ledge_index];
1027     if (!((mr->use_hide && (med->flag & ME_HIDE)) ||
1028           ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
1029            (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) {
1030       const int l_index = mr->loop_len + ledge_index * 2;
1031       GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1);
1032     }
1033     else {
1034       GPU_indexbuf_set_line_restart(elb, l_index_offset);
1035     }
1036     /* Don't render the edge twice. */
1037     GPU_indexbuf_set_line_restart(elb, e_index);
1038   }
1039   EXTRACT_LEDGE_FOREACH_MESH_END;
1040 }
1041
1042 static void extract_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb)
1043 {
1044   GPU_indexbuf_build_in_place(elb, ibo);
1045   MEM_freeN(elb);
1046 }
1047
1048 static const MeshExtract extract_lines = {
1049     .init = extract_lines_init,
1050     .iter_poly_bm = extract_lines_iter_poly_bm,
1051     .iter_poly_mesh = extract_lines_iter_poly_mesh,
1052     .iter_ledge_bm = extract_lines_iter_ledge_bm,
1053     .iter_ledge_mesh = extract_lines_iter_ledge_mesh,
1054     .finish = extract_lines_finish,
1055     .data_flag = 0,
1056     .use_threading = false,
1057 };
1058 /** \} */
1059
1060 /* ---------------------------------------------------------------------- */
1061 /** \name Extract Loose Edges Sub Buffer
1062  * \{ */
1063
1064 static void extract_lines_loose_subbuffer(const MeshRenderData *mr)
1065 {
1066   BLI_assert(mr->cache->final.ibo.lines);
1067   /* Multiply by 2 because these are edges indices. */
1068   const int start = mr->edge_len * 2;
1069   const int len = mr->edge_loose_len * 2;
1070   GPU_indexbuf_create_subrange_in_place(
1071       mr->cache->final.ibo.lines_loose, mr->cache->final.ibo.lines, start, len);
1072   mr->cache->no_loose_wire = (len == 0);
1073 }
1074
1075 static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr, void *ibo, void *elb)
1076 {
1077   GPU_indexbuf_build_in_place(elb, ibo);
1078   extract_lines_loose_subbuffer(mr);
1079   MEM_freeN(elb);
1080 }
1081
1082 static const MeshExtract extract_lines_with_lines_loose = {
1083     .init = extract_lines_init,
1084     .iter_poly_bm = extract_lines_iter_poly_bm,
1085     .iter_poly_mesh = extract_lines_iter_poly_mesh,
1086     .iter_ledge_bm = extract_lines_iter_ledge_bm,
1087     .iter_ledge_mesh = extract_lines_iter_ledge_mesh,
1088     .finish = extract_lines_with_lines_loose_finish,
1089     .data_flag = 0,
1090     .use_threading = false,
1091 };
1092
1093 /** \} */
1094
1095 /* ---------------------------------------------------------------------- */
1096 /** \name Extract Point Indices
1097  * \{ */
1098
1099 static void *extract_points_init(const MeshRenderData *mr, void *UNUSED(buf))
1100 {
1101   GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
1102   GPU_indexbuf_init(elb, GPU_PRIM_POINTS, mr->vert_len, mr->loop_len + mr->loop_loose_len);
1103   return elb;
1104 }
1105
1106 BLI_INLINE void vert_set_bm(GPUIndexBufBuilder *elb, BMVert *eve, int l_index)
1107 {
1108   const int v_index = BM_elem_index_get(eve);
1109   if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
1110     GPU_indexbuf_set_point_vert(elb, v_index, l_index);
1111   }
1112   else {
1113     GPU_indexbuf_set_point_restart(elb, v_index);
1114   }
1115 }
1116
1117 BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb,
1118                               const MeshRenderData *mr,
1119                               const int v_index,
1120                               const int l_index)
1121 {
1122   const MVert *mv = &mr->mvert[v_index];
1123   if (!((mr->use_hide && (mv->flag & ME_HIDE)) ||
1124         ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) &&
1125          (mr->v_origindex[v_index] == ORIGINDEX_NONE)))) {
1126     GPU_indexbuf_set_point_vert(elb, v_index, l_index);
1127   }
1128   else {
1129     GPU_indexbuf_set_point_restart(elb, v_index);
1130   }
1131 }
1132
1133 static void extract_points_iter_poly_bm(const MeshRenderData *mr,
1134                                         const ExtractPolyBMesh_Params *params,
1135                                         void *elb)
1136 {
1137   EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
1138   {
1139     vert_set_bm(elb, l->v, l_index);
1140   }
1141   EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
1142 }
1143
1144 static void extract_points_iter_poly_mesh(const MeshRenderData *mr,
1145                                           const ExtractPolyMesh_Params *params,
1146                                           void *elb)
1147 {
1148   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1149   {
1150     vert_set_mesh(elb, mr, ml->v, ml_index);
1151   }
1152   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
1153 }
1154
1155 static void extract_points_iter_ledge_bm(const MeshRenderData *mr,
1156                                          const ExtractLEdgeBMesh_Params *params,
1157                                          void *elb)
1158 {
1159   EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
1160   {
1161     vert_set_bm(elb, eed->v1, mr->loop_len + (ledge_index * 2));
1162     vert_set_bm(elb, eed->v2, mr->loop_len + (ledge_index * 2) + 1);
1163   }
1164   EXTRACT_LEDGE_FOREACH_BM_END;
1165 }
1166
1167 static void extract_points_iter_ledge_mesh(const MeshRenderData *mr,
1168                                            const ExtractLEdgeMesh_Params *params,
1169                                            void *elb)
1170 {
1171   EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
1172   {
1173     vert_set_mesh(elb, mr, med->v1, mr->loop_len + (ledge_index * 2));
1174     vert_set_mesh(elb, mr, med->v2, mr->loop_len + (ledge_index * 2) + 1);
1175   }
1176   EXTRACT_LEDGE_FOREACH_MESH_END;
1177 }
1178
1179 static void extract_points_iter_lvert_bm(const MeshRenderData *mr,
1180                                          const ExtractLVertBMesh_Params *params,
1181                                          void *elb)
1182 {
1183   const int offset = mr->loop_len + (mr->edge_loose_len * 2);
1184   EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
1185   {
1186     vert_set_bm(elb, eve, offset + lvert_index);
1187   }
1188   EXTRACT_LVERT_FOREACH_BM_END;
1189 }
1190
1191 static void extract_points_iter_lvert_mesh(const MeshRenderData *mr,
1192                                            const ExtractLVertMesh_Params *params,
1193                                            void *elb)
1194 {
1195   const int offset = mr->loop_len + (mr->edge_loose_len * 2);
1196   EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
1197   {
1198     vert_set_mesh(elb, mr, mr->lverts[lvert_index], offset + lvert_index);
1199   }
1200   EXTRACT_LVERT_FOREACH_MESH_END;
1201 }
1202
1203 static void extract_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb)
1204 {
1205   GPU_indexbuf_build_in_place(elb, ibo);
1206   MEM_freeN(elb);
1207 }
1208
1209 static const MeshExtract extract_points = {
1210     .init = extract_points_init,
1211     .iter_poly_bm = extract_points_iter_poly_bm,
1212     .iter_poly_mesh = extract_points_iter_poly_mesh,
1213     .iter_ledge_bm = extract_points_iter_ledge_bm,
1214     .iter_ledge_mesh = extract_points_iter_ledge_mesh,
1215     .iter_lvert_bm = extract_points_iter_lvert_bm,
1216     .iter_lvert_mesh = extract_points_iter_lvert_mesh,
1217     .finish = extract_points_finish,
1218     .data_flag = 0,
1219     .use_threading = false,
1220 };
1221
1222 /** \} */
1223
1224 /* ---------------------------------------------------------------------- */
1225 /** \name Extract Facedots Indices
1226  * \{ */
1227
1228 static void *extract_fdots_init(const MeshRenderData *mr, void *UNUSED(buf))
1229 {
1230   GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
1231   GPU_indexbuf_init(elb, GPU_PRIM_POINTS, mr->poly_len, mr->poly_len);
1232   return elb;
1233 }
1234
1235 static void extract_fdots_iter_poly_bm(const MeshRenderData *mr,
1236                                        const ExtractPolyBMesh_Params *params,
1237                                        void *elb)
1238 {
1239   EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
1240   {
1241     if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
1242       GPU_indexbuf_set_point_vert(elb, f_index, f_index);
1243     }
1244     else {
1245       GPU_indexbuf_set_point_restart(elb, f_index);
1246     }
1247   }
1248   EXTRACT_POLY_FOREACH_BM_END;
1249 }
1250
1251 static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr,
1252                                          const ExtractPolyMesh_Params *params,
1253                                          void *elb)
1254 {
1255   if (mr->use_subsurf_fdots) {
1256     /* Check #ME_VERT_FACEDOT. */
1257     EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1258     {
1259       const MVert *mv = &mr->mvert[ml->v];
1260       if ((mv->flag & ME_VERT_FACEDOT) && !(mr->use_hide && (mp->flag & ME_HIDE))) {
1261         GPU_indexbuf_set_point_vert(elb, mp_index, mp_index);
1262       }
1263       else {
1264         GPU_indexbuf_set_point_restart(elb, mp_index);
1265       }
1266     }
1267     EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
1268   }
1269   else {
1270     EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
1271     {
1272       if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
1273         GPU_indexbuf_set_point_vert(elb, mp_index, mp_index);
1274       }
1275       else {
1276         GPU_indexbuf_set_point_restart(elb, mp_index);
1277       }
1278     }
1279     EXTRACT_POLY_FOREACH_MESH_END;
1280   }
1281 }
1282
1283 static void extract_fdots_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *elb)
1284 {
1285   GPU_indexbuf_build_in_place(elb, ibo);
1286   MEM_freeN(elb);
1287 }
1288
1289 static const MeshExtract extract_fdots = {
1290     .init = extract_fdots_init,
1291     .iter_poly_bm = extract_fdots_iter_poly_bm,
1292     .iter_poly_mesh = extract_fdots_iter_poly_mesh,
1293     .finish = extract_fdots_finish,
1294     .data_flag = 0,
1295     .use_threading = false,
1296 };
1297
1298 /** \} */
1299
1300 /* ---------------------------------------------------------------------- */
1301 /** \name Extract Paint Mask Line Indices
1302  * \{ */
1303
1304 typedef struct MeshExtract_LinePaintMask_Data {
1305   GPUIndexBufBuilder elb;
1306   /** One bit per edge set if face is selected. */
1307   BLI_bitmap select_map[0];
1308 } MeshExtract_LinePaintMask_Data;
1309
1310 static void *extract_lines_paint_mask_init(const MeshRenderData *mr, void *UNUSED(buf))
1311 {
1312   size_t bitmap_size = BLI_BITMAP_SIZE(mr->edge_len);
1313   MeshExtract_LinePaintMask_Data *data = MEM_callocN(sizeof(*data) + bitmap_size, __func__);
1314   GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES, mr->edge_len, mr->loop_len);
1315   return data;
1316 }
1317
1318 static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr,
1319                                                     const ExtractPolyMesh_Params *params,
1320                                                     void *_data)
1321 {
1322   MeshExtract_LinePaintMask_Data *data = _data;
1323   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1324   {
1325     const int e_index = ml->e;
1326     const MEdge *me = &mr->medge[e_index];
1327     if (!((mr->use_hide && (me->flag & ME_HIDE)) ||
1328           ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
1329            (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) {
1330
1331       const int ml_index_last = mp->totloop + mp->loopstart - 1;
1332       const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1);
1333       if (mp->flag & ME_FACE_SEL) {
1334         if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, e_index)) {
1335           /* Hide edge as it has more than 2 selected loop. */
1336           GPU_indexbuf_set_line_restart(&data->elb, e_index);
1337         }
1338         else {
1339           /* First selected loop. Set edge visible, overwriting any unselected loop. */
1340           GPU_indexbuf_set_line_verts(&data->elb, e_index, ml_index, ml_index_other);
1341         }
1342       }
1343       else {
1344         /* Set theses unselected loop only if this edge has no other selected loop. */
1345         if (!BLI_BITMAP_TEST(data->select_map, e_index)) {
1346           GPU_indexbuf_set_line_verts(&data->elb, e_index, ml_index, ml_index_other);
1347         }
1348       }
1349     }
1350     else {
1351       GPU_indexbuf_set_line_restart(&data->elb, e_index);
1352     }
1353   }
1354   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
1355 }
1356 static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
1357                                             void *ibo,
1358                                             void *_data)
1359 {
1360   MeshExtract_LinePaintMask_Data *data = _data;
1361
1362   GPU_indexbuf_build_in_place(&data->elb, ibo);
1363   MEM_freeN(data);
1364 }
1365
1366 static const MeshExtract extract_lines_paint_mask = {
1367     .init = extract_lines_paint_mask_init,
1368     .iter_poly_mesh = extract_lines_paint_mask_iter_poly_mesh,
1369     .finish = extract_lines_paint_mask_finish,
1370     .data_flag = 0,
1371     .use_threading = false,
1372 };
1373
1374 /** \} */
1375
1376 /* ---------------------------------------------------------------------- */
1377 /** \name Extract Line Adjacency Indices
1378  * \{ */
1379
1380 #define NO_EDGE INT_MAX
1381
1382 typedef struct MeshExtract_LineAdjacency_Data {
1383   GPUIndexBufBuilder elb;
1384   EdgeHash *eh;
1385   bool is_manifold;
1386   /* Array to convert vert index to any loop index of this vert. */
1387   uint vert_to_loop[0];
1388 } MeshExtract_LineAdjacency_Data;
1389
1390 static void *extract_lines_adjacency_init(const MeshRenderData *mr, void *UNUSED(buf))
1391 {
1392   /* Similar to poly_to_tri_count().
1393    * There is always (loop + triangle - 1) edges inside a polygon.
1394    * Accumulate for all polys and you get : */
1395   uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len;
1396
1397   size_t vert_to_loop_size = sizeof(uint) * mr->vert_len;
1398
1399   MeshExtract_LineAdjacency_Data *data = MEM_callocN(sizeof(*data) + vert_to_loop_size, __func__);
1400   GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, mr->loop_len);
1401   data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
1402   data->is_manifold = true;
1403   return data;
1404 }
1405
1406 BLI_INLINE void lines_adjacency_triangle(
1407     uint v1, uint v2, uint v3, uint l1, uint l2, uint l3, MeshExtract_LineAdjacency_Data *data)
1408 {
1409   GPUIndexBufBuilder *elb = &data->elb;
1410   /* Iterate around the triangle's edges. */
1411   for (int e = 0; e < 3; e++) {
1412     SHIFT3(uint, v3, v2, v1);
1413     SHIFT3(uint, l3, l2, l1);
1414
1415     bool inv_indices = (v2 > v3);
1416     void **pval;
1417     bool value_is_init = BLI_edgehash_ensure_p(data->eh, v2, v3, &pval);
1418     int v_data = POINTER_AS_INT(*pval);
1419     if (!value_is_init || v_data == NO_EDGE) {
1420       /* Save the winding order inside the sign bit. Because the
1421        * Edge-hash sort the keys and we need to compare winding later. */
1422       int value = (int)l1 + 1; /* 0 cannot be signed so add one. */
1423       *pval = POINTER_FROM_INT((inv_indices) ? -value : value);
1424       /* Store loop indices for remaining non-manifold edges. */
1425       data->vert_to_loop[v2] = l2;
1426       data->vert_to_loop[v3] = l3;
1427     }
1428     else {
1429       /* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
1430       *pval = POINTER_FROM_INT(NO_EDGE);
1431       bool inv_opposite = (v_data < 0);
1432       uint l_opposite = (uint)abs(v_data) - 1;
1433       /* TODO Make this part thread-safe. */
1434       if (inv_opposite == inv_indices) {
1435         /* Don't share edge if triangles have non matching winding. */
1436         GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l1);
1437         GPU_indexbuf_add_line_adj_verts(elb, l_opposite, l2, l3, l_opposite);
1438         data->is_manifold = false;
1439       }
1440       else {
1441         GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l_opposite);
1442       }
1443     }
1444   }
1445 }
1446
1447 static void extract_lines_adjacency_iter_looptri_bm(const MeshRenderData *UNUSED(mr),
1448                                                     const struct ExtractTriBMesh_Params *params,
1449                                                     void *data)
1450 {
1451   EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params)
1452   {
1453     if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
1454       lines_adjacency_triangle(BM_elem_index_get(elt[0]->v),
1455                                BM_elem_index_get(elt[1]->v),
1456                                BM_elem_index_get(elt[2]->v),
1457                                BM_elem_index_get(elt[0]),
1458                                BM_elem_index_get(elt[1]),
1459                                BM_elem_index_get(elt[2]),
1460                                data);
1461     }
1462   }
1463   EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END;
1464 }
1465
1466 static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData *mr,
1467                                                       const struct ExtractTriMesh_Params *params,
1468                                                       void *data)
1469 {
1470   EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params)
1471   {
1472     const MPoly *mp = &mr->mpoly[mlt->poly];
1473     if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
1474       lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v,
1475                                mr->mloop[mlt->tri[1]].v,
1476                                mr->mloop[mlt->tri[2]].v,
1477                                mlt->tri[0],
1478                                mlt->tri[1],
1479                                mlt->tri[2],
1480                                data);
1481     }
1482   }
1483   EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END;
1484 }
1485
1486 static void extract_lines_adjacency_finish(const MeshRenderData *mr, void *ibo, void *_data)
1487 {
1488   MeshExtract_LineAdjacency_Data *data = _data;
1489   /* Create edges for remaining non manifold edges. */
1490   EdgeHashIterator *ehi = BLI_edgehashIterator_new(data->eh);
1491   for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
1492     uint v2, v3, l1, l2, l3;
1493     int v_data = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
1494     if (v_data != NO_EDGE) {
1495       BLI_edgehashIterator_getKey(ehi, &v2, &v3);
1496       l1 = (uint)abs(v_data) - 1;
1497       if (v_data < 0) { /* inv_opposite  */
1498         SWAP(uint, v2, v3);
1499       }
1500       l2 = data->vert_to_loop[v2];
1501       l3 = data->vert_to_loop[v3];
1502       GPU_indexbuf_add_line_adj_verts(&data->elb, l1, l2, l3, l1);
1503       data->is_manifold = false;
1504     }
1505   }
1506   BLI_edgehashIterator_free(ehi);
1507   BLI_edgehash_free(data->eh, NULL);
1508
1509   mr->cache->is_manifold = data->is_manifold;
1510
1511   GPU_indexbuf_build_in_place(&data->elb, ibo);
1512   MEM_freeN(data);
1513 }
1514
1515 #undef NO_EDGE
1516
1517 static const MeshExtract extract_lines_adjacency = {
1518     .init = extract_lines_adjacency_init,
1519     .iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm,
1520     .iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh,
1521     .finish = extract_lines_adjacency_finish,
1522     .data_flag = 0,
1523     .use_threading = false,
1524 };
1525
1526 /** \} */
1527
1528 /* ---------------------------------------------------------------------- */
1529 /** \name Extract Edit UV Triangles Indices
1530  * \{ */
1531
1532 typedef struct MeshExtract_EditUvElem_Data {
1533   GPUIndexBufBuilder elb;
1534   bool sync_selection;
1535 } MeshExtract_EditUvElem_Data;
1536
1537 static void *extract_edituv_tris_init(const MeshRenderData *mr, void *UNUSED(ibo))
1538 {
1539   MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
1540   GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, mr->tri_len, mr->loop_len);
1541   data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
1542   return data;
1543 }
1544
1545 BLI_INLINE void edituv_tri_add(
1546     MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, int v1, int v2, int v3)
1547 {
1548   if (!hidden && (data->sync_selection || selected)) {
1549     GPU_indexbuf_add_tri_verts(&data->elb, v1, v2, v3);
1550   }
1551 }
1552
1553 static void extract_edituv_tris_iter_looptri_bm(const MeshRenderData *UNUSED(mr),
1554                                                 const struct ExtractTriBMesh_Params *params,
1555                                                 void *data)
1556 {
1557   EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, _elt_index, params)
1558   {
1559     edituv_tri_add(data,
1560                    BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN),
1561                    BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT),
1562                    BM_elem_index_get(elt[0]),
1563                    BM_elem_index_get(elt[1]),
1564                    BM_elem_index_get(elt[2]));
1565   }
1566   EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END;
1567 }
1568
1569 static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData *mr,
1570                                                   const struct ExtractTriMesh_Params *params,
1571                                                   void *data)
1572 {
1573   EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, _mlt_index, params)
1574   {
1575     const MPoly *mp = &mr->mpoly[mlt->poly];
1576     edituv_tri_add(data,
1577                    (mp->flag & ME_HIDE) != 0,
1578                    (mp->flag & ME_FACE_SEL) != 0,
1579                    mlt->tri[0],
1580                    mlt->tri[1],
1581                    mlt->tri[2]);
1582   }
1583   EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END;
1584 }
1585
1586 static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data)
1587 {
1588   MeshExtract_EditUvElem_Data *extract_data = data;
1589   GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
1590   MEM_freeN(extract_data);
1591 }
1592
1593 static const MeshExtract extract_edituv_tris = {
1594     .init = extract_edituv_tris_init,
1595     .iter_looptri_bm = extract_edituv_tris_iter_looptri_bm,
1596     .iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh,
1597     .finish = extract_edituv_tris_finish,
1598     .data_flag = 0,
1599     .use_threading = false,
1600 };
1601
1602 /** \} */
1603
1604 /* ---------------------------------------------------------------------- */
1605 /** \name Extract Edit UV Line Indices around faces
1606  * \{ */
1607
1608 static void *extract_edituv_lines_init(const MeshRenderData *mr, void *UNUSED(ibo))
1609 {
1610   MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
1611   GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES, mr->loop_len, mr->loop_len);
1612
1613   data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
1614   return data;
1615 }
1616
1617 BLI_INLINE void edituv_edge_add(
1618     MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, int v1, int v2)
1619 {
1620   if (!hidden && (data->sync_selection || selected)) {
1621     GPU_indexbuf_add_line_verts(&data->elb, v1, v2);
1622   }
1623 }
1624
1625 static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *mr,
1626                                               const ExtractPolyBMesh_Params *params,
1627                                               void *data)
1628 {
1629   EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(loop, l_index, params, mr)
1630   {
1631     edituv_edge_add(data,
1632                     BM_elem_flag_test(loop->f, BM_ELEM_HIDDEN),
1633                     BM_elem_flag_test(loop->f, BM_ELEM_SELECT),
1634                     l_index,
1635                     BM_elem_index_get(loop->next));
1636   }
1637   EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(loop);
1638 }
1639
1640 static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr,
1641                                                 const ExtractPolyMesh_Params *params,
1642                                                 void *data)
1643 {
1644   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1645   {
1646     const int ml_index_last = mp->totloop + mp->loopstart - 1;
1647     const int ml_index_next = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1);
1648     const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[ml->e] != ORIGINDEX_NONE);
1649     edituv_edge_add(data,
1650                     (mp->flag & ME_HIDE) != 0 || !real_edge,
1651                     (mp->flag & ME_FACE_SEL) != 0,
1652                     ml_index,
1653                     ml_index_next);
1654   }
1655   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
1656 }
1657
1658 static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data)
1659 {
1660   MeshExtract_EditUvElem_Data *extract_data = data;
1661   GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
1662   MEM_freeN(extract_data);
1663 }
1664
1665 static const MeshExtract extract_edituv_lines = {
1666     .init = extract_edituv_lines_init,
1667     .iter_poly_bm = extract_edituv_lines_iter_poly_bm,
1668     .iter_poly_mesh = extract_edituv_lines_iter_poly_mesh,
1669     .finish = extract_edituv_lines_finish,
1670     .data_flag = 0,
1671     .use_threading = false,
1672 };
1673
1674 /** \} */
1675
1676 /* ---------------------------------------------------------------------- */
1677 /** \name Extract Edit UV Points Indices
1678  * \{ */
1679
1680 static void *extract_edituv_points_init(const MeshRenderData *mr, void *UNUSED(ibo))
1681 {
1682   MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
1683   GPU_indexbuf_init(&data->elb, GPU_PRIM_POINTS, mr->loop_len, mr->loop_len);
1684
1685   data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
1686   return data;
1687 }
1688
1689 BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data,
1690                                  bool hidden,
1691                                  bool selected,
1692                                  int v1)
1693 {
1694   if (!hidden && (data->sync_selection || selected)) {
1695     GPU_indexbuf_add_point_vert(&data->elb, v1);
1696   }
1697 }
1698
1699 static void extract_edituv_points_iter_poly_bm(const MeshRenderData *mr,
1700                                                const ExtractPolyBMesh_Params *params,
1701                                                void *data)
1702 {
1703   EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
1704   {
1705     edituv_point_add(data,
1706                      BM_elem_flag_test(l->f, BM_ELEM_HIDDEN),
1707                      BM_elem_flag_test(l->f, BM_ELEM_SELECT),
1708                      l_index);
1709   }
1710   EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
1711 }
1712
1713 static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr,
1714                                                  const ExtractPolyMesh_Params *params,
1715                                                  void *data)
1716 {
1717   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1718   {
1719     const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
1720                             mr->v_origindex[ml->v] != ORIGINDEX_NONE);
1721     edituv_point_add(
1722         data, ((mp->flag & ME_HIDE) != 0) || !real_vert, (mp->flag & ME_FACE_SEL) != 0, ml_index);
1723   }
1724   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
1725 }
1726
1727 static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *data)
1728 {
1729   MeshExtract_EditUvElem_Data *extract_data = data;
1730   GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
1731   MEM_freeN(extract_data);
1732 }
1733
1734 static const MeshExtract extract_edituv_points = {
1735     .init = extract_edituv_points_init,
1736     .iter_poly_bm = extract_edituv_points_iter_poly_bm,
1737     .iter_poly_mesh = extract_edituv_points_iter_poly_mesh,
1738     .finish = extract_edituv_points_finish,
1739     .data_flag = 0,
1740     .use_threading = false,
1741 };
1742
1743 /** \} */
1744
1745 /* ---------------------------------------------------------------------- */
1746 /** \name Extract Edit UV Facedots Indices
1747  * \{ */
1748
1749 static void *extract_edituv_fdots_init(const MeshRenderData *mr, void *UNUSED(ibo))
1750 {
1751   MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
1752   GPU_indexbuf_init(&data->elb, GPU_PRIM_POINTS, mr->poly_len, mr->poly_len);
1753
1754   data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
1755   return data;
1756 }
1757
1758 BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data,
1759                                    bool hidden,
1760                                    bool selected,
1761                                    int face_index)
1762 {
1763   if (!hidden && (data->sync_selection || selected)) {
1764     GPU_indexbuf_set_point_vert(&data->elb, face_index, face_index);
1765   }
1766   else {
1767     GPU_indexbuf_set_point_restart(&data->elb, face_index);
1768   }
1769 }
1770
1771 static void extract_edituv_fdots_iter_poly_bm(const MeshRenderData *mr,
1772                                               const ExtractPolyBMesh_Params *params,
1773                                               void *data)
1774 {
1775   EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
1776   {
1777     edituv_facedot_add(
1778         data, BM_elem_flag_test(f, BM_ELEM_HIDDEN), BM_elem_flag_test(f, BM_ELEM_SELECT), f_index);
1779   }
1780   EXTRACT_POLY_FOREACH_BM_END;
1781 }
1782
1783 static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr,
1784                                                 const ExtractPolyMesh_Params *params,
1785                                                 void *data)
1786 {
1787   if (mr->use_subsurf_fdots) {
1788     /* Check #ME_VERT_FACEDOT. */
1789     EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1790     {
1791       const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
1792                               mr->p_origindex[mp_index] != ORIGINDEX_NONE);
1793       const bool subd_fdot = (!mr->use_subsurf_fdots ||
1794                               (mr->mvert[ml->v].flag & ME_VERT_FACEDOT) != 0);
1795       edituv_facedot_add(data,
1796                          ((mp->flag & ME_HIDE) != 0) || !real_fdot || !subd_fdot,
1797                          (mp->flag & ME_FACE_SEL) != 0,
1798                          mp_index);
1799     }
1800     EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
1801   }
1802   else {
1803     EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
1804     {
1805       const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
1806                               mr->p_origindex[mp_index] != ORIGINDEX_NONE);
1807       edituv_facedot_add(data,
1808                          ((mp->flag & ME_HIDE) != 0) || !real_fdot,
1809                          (mp->flag & ME_FACE_SEL) != 0,
1810                          mp_index);
1811     }
1812     EXTRACT_POLY_FOREACH_MESH_END;
1813   }
1814 }
1815
1816 static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr), void *ibo, void *_data)
1817 {
1818   MeshExtract_EditUvElem_Data *data = _data;
1819   GPU_indexbuf_build_in_place(&data->elb, ibo);
1820   MEM_freeN(data);
1821 }
1822
1823 static const MeshExtract extract_edituv_fdots = {
1824     .init = extract_edituv_fdots_init,
1825     .iter_poly_bm = extract_edituv_fdots_iter_poly_bm,
1826     .iter_poly_mesh = extract_edituv_fdots_iter_poly_mesh,
1827     .finish = extract_edituv_fdots_finish,
1828     .data_flag = 0,
1829     .use_threading = false,
1830 };
1831
1832 /** \} */
1833
1834 /* ---------------------------------------------------------------------- */
1835 /** \name Extract Position and Vertex Normal
1836  * \{ */
1837
1838 typedef struct PosNorLoop {
1839   float pos[3];
1840   GPUPackedNormal nor;
1841 } PosNorLoop;
1842
1843 typedef struct MeshExtract_PosNor_Data {
1844   PosNorLoop *vbo_data;
1845   GPUPackedNormal packed_nor[];
1846 } MeshExtract_PosNor_Data;
1847
1848 static void *extract_pos_nor_init(const MeshRenderData *mr, void *buf)
1849 {
1850   static GPUVertFormat format = {0};
1851   if (format.attr_len == 0) {
1852     /* WARNING Adjust #PosNorLoop struct accordingly. */
1853     GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1854     GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
1855     GPU_vertformat_alias_add(&format, "vnor");
1856   }
1857   GPUVertBuf *vbo = buf;
1858   GPU_vertbuf_init_with_format(vbo, &format);
1859   GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
1860
1861   /* Pack normals per vert, reduce amount of computation. */
1862   size_t packed_nor_len = sizeof(GPUPackedNormal) * mr->vert_len;
1863   MeshExtract_PosNor_Data *data = MEM_mallocN(sizeof(*data) + packed_nor_len, __func__);
1864   data->vbo_data = (PosNorLoop *)vbo->data;
1865
1866   /* Quicker than doing it for each loop. */
1867   if (mr->extract_type == MR_EXTRACT_BMESH) {
1868     BMIter iter;
1869     BMVert *eve;
1870     int v;
1871     BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) {
1872       data->packed_nor[v] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, eve));
1873     }
1874   }
1875   else {
1876     const MVert *mv = mr->mvert;
1877     for (int v = 0; v < mr->vert_len; v++, mv++) {
1878       data->packed_nor[v] = GPU_normal_convert_i10_s3(mv->no);
1879     }
1880   }
1881   return data;
1882 }
1883
1884 static void extract_pos_nor_iter_poly_bm(const MeshRenderData *mr,
1885                                          const ExtractPolyBMesh_Params *params,
1886                                          void *_data)
1887 {
1888   MeshExtract_PosNor_Data *data = _data;
1889   EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
1890   {
1891     PosNorLoop *vert = &data->vbo_data[l_index];
1892     copy_v3_v3(vert->pos, bm_vert_co_get(mr, l->v));
1893     vert->nor = data->packed_nor[BM_elem_index_get(l->v)];
1894     BMFace *efa = l->f;
1895     vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
1896   }
1897   EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
1898 }
1899
1900 static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr,
1901                                            const ExtractPolyMesh_Params *params,
1902                                            void *_data)
1903 {
1904   MeshExtract_PosNor_Data *data = _data;
1905   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1906   {
1907     PosNorLoop *vert = &data->vbo_data[ml_index];
1908     const MVert *mv = &mr->mvert[ml->v];
1909     copy_v3_v3(vert->pos, mv->co);
1910     vert->nor = data->packed_nor[ml->v];
1911     /* Flag for paint mode overlay. */
1912     if (mp->flag & ME_HIDE || mv->flag & ME_HIDE ||
1913         ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) &&
1914          (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) {
1915       vert->nor.w = -1;
1916     }
1917     else if (mv->flag & SELECT) {
1918       vert->nor.w = 1;
1919     }
1920     else {
1921       vert->nor.w = 0;
1922     }
1923   }
1924   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
1925 }
1926
1927 static void extract_pos_nor_iter_ledge_bm(const MeshRenderData *mr,
1928                                           const ExtractLEdgeBMesh_Params *params,
1929                                           void *_data)
1930 {
1931   MeshExtract_PosNor_Data *data = _data;
1932   EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
1933   {
1934     int l_index = mr->loop_len + ledge_index * 2;
1935     PosNorLoop *vert = &data->vbo_data[l_index];
1936     copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
1937     copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
1938     vert[0].nor = data->packed_nor[BM_elem_index_get(eed->v1)];
1939     vert[1].nor = data->packed_nor[BM_elem_index_get(eed->v2)];
1940   }
1941   EXTRACT_LEDGE_FOREACH_BM_END;
1942 }
1943
1944 static void extract_pos_nor_iter_ledge_mesh(const MeshRenderData *mr,
1945                                             const ExtractLEdgeMesh_Params *params,
1946                                             void *_data)
1947 {
1948   MeshExtract_PosNor_Data *data = _data;
1949   EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
1950   {
1951     const int ml_index = mr->loop_len + ledge_index * 2;
1952     PosNorLoop *vert = &data->vbo_data[ml_index];
1953     copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co);
1954     copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co);
1955     vert[0].nor = data->packed_nor[med->v1];
1956     vert[1].nor = data->packed_nor[med->v2];
1957   }
1958   EXTRACT_LEDGE_FOREACH_MESH_END;
1959 }
1960
1961 static void extract_pos_nor_iter_lvert_bm(const MeshRenderData *mr,
1962                                           const ExtractLVertBMesh_Params *params,
1963                                           void *_data)
1964 {
1965   MeshExtract_PosNor_Data *data = _data;
1966   const int offset = mr->loop_len + (mr->edge_loose_len * 2);
1967   EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
1968   {
1969     const int l_index = offset + lvert_index;
1970     PosNorLoop *vert = &data->vbo_data[l_index];
1971     copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
1972     vert->nor = data->packed_nor[BM_elem_index_get(eve)];
1973   }
1974   EXTRACT_LVERT_FOREACH_BM_END;
1975 }
1976
1977 static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr,
1978                                             const ExtractLVertMesh_Params *params,
1979                                             void *_data)
1980 {
1981   MeshExtract_PosNor_Data *data = _data;
1982   const int offset = mr->loop_len + (mr->edge_loose_len * 2);
1983   EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
1984   {
1985     const int ml_index = offset + lvert_index;
1986     const int v_index = mr->lverts[lvert_index];
1987     PosNorLoop *vert = &data->vbo_data[ml_index];
1988     copy_v3_v3(vert->pos, mv->co);
1989     vert->nor = data->packed_nor[v_index];
1990   }
1991   EXTRACT_LVERT_FOREACH_MESH_END;
1992 }
1993
1994 static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(vbo), void *data)
1995 {
1996   MEM_freeN(data);
1997 }
1998
1999 static const MeshExtract extract_pos_nor = {
2000     .init = extract_pos_nor_init,
2001     .iter_poly_bm = extract_pos_nor_iter_poly_bm,
2002     .iter_poly_mesh = extract_pos_nor_iter_poly_mesh,
2003     .iter_ledge_bm = extract_pos_nor_iter_ledge_bm,
2004     .iter_ledge_mesh = extract_pos_nor_iter_ledge_mesh,
2005     .iter_lvert_bm = extract_pos_nor_iter_lvert_bm,
2006     .iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh,
2007     .finish = extract_pos_nor_finish,
2008     .data_flag = 0,
2009     .use_threading = true,
2010 };
2011 /** \} */
2012
2013 /* ---------------------------------------------------------------------- */
2014 /** \name Extract HQ Loop Normal
2015  * \{ */
2016
2017 typedef struct gpuHQNor {
2018   short x, y, z, w;
2019 } gpuHQNor;
2020
2021 static void *extract_lnor_hq_init(const MeshRenderData *mr, void *buf)
2022 {
2023   static GPUVertFormat format = {0};
2024   if (format.attr_len == 0) {
2025     GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
2026     GPU_vertformat_alias_add(&format, "lnor");
2027   }
2028   GPUVertBuf *vbo = buf;
2029   GPU_vertbuf_init_with_format(vbo, &format);
2030   GPU_vertbuf_data_alloc(vbo, mr->loop_len);
2031
2032   return vbo->data;
2033 }
2034
2035 static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr,
2036                                          const ExtractPolyBMesh_Params *params,
2037                                          void *data)
2038 {
2039   if (mr->loop_normals) {
2040     EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(_l, l_index, params, mr)
2041     {
2042       normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, mr->loop_normals[l_index]);
2043     }
2044     EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(_l);
2045   }
2046   else {
2047     EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
2048     {
2049       if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH)) {
2050         normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_vert_no_get(mr, l->v));
2051       }
2052       else {
2053         normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_face_no_get(mr, l->f));
2054       }
2055     }
2056     EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
2057   }
2058 }
2059
2060 static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr,
2061                                            const ExtractPolyMesh_Params *params,
2062                                            void *data)
2063 {
2064   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
2065   {
2066     gpuHQNor *lnor_data = &((gpuHQNor *)data)[ml_index];
2067     if (mr->loop_normals) {
2068       normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]);
2069     }
2070     else if (mp->flag & ME_SMOOTH) {
2071       copy_v3_v3_short(&lnor_data->x, mr->mvert[ml->v].no);
2072     }
2073     else {
2074       normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]);
2075     }
2076
2077     /* Flag for paint mode overlay.
2078      * Only use #MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals.
2079      * In paint mode it will use the un-mapped data to draw the wire-frame. */
2080     if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED &&
2081                                (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) {
2082       lnor_data->w = -1;
2083     }
2084     else if (mp->flag & ME_FACE_SEL) {
2085       lnor_data->w = 1;
2086     }
2087     else {
2088       lnor_data->w = 0;
2089     }
2090   }
2091   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
2092 }
2093
2094 static const MeshExtract extract_lnor_hq = {
2095     .init = extract_lnor_hq_init,
2096     .iter_poly_bm = extract_lnor_hq_iter_poly_bm,
2097     .iter_poly_mesh = extract_lnor_hq_iter_poly_mesh,
2098     .data_flag = MR_DATA_LOOP_NOR,
2099     .use_threading = true,
2100 };
2101
2102 /** \} */
2103 /* ---------------------------------------------------------------------- */
2104 /** \name Extract Loop Normal
2105  * \{ */
2106
2107 static void *extract_lnor_init(const MeshRenderData *mr, void *buf)
2108 {
2109   static GPUVertFormat format = {0};
2110   if (format.attr_len == 0) {
2111     GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
2112     GPU_vertformat_alias_add(&format, "lnor");
2113   }
2114   GPUVertBuf *vbo = buf;
2115   GPU_vertbuf_init_with_format(vbo, &format);
2116   GPU_vertbuf_data_alloc(vbo, mr->loop_len);
2117
2118   return vbo->data;
2119 }
2120
2121 static void extract_lnor_iter_poly_bm(const MeshRenderData *mr,
2122                                       const ExtractPolyBMesh_Params *params,
2123                                       void *data)
2124 {
2125   if (mr->loop_normals) {
2126     EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
2127     {
2128       ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]);
2129       BMFace *efa = l->f;
2130       ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
2131     }
2132     EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
2133   }
2134   else {
2135     EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
2136     {
2137       if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH)) {
2138         ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, l->v));
2139       }
2140       else {
2141         ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, l->f));
2142       }
2143       BMFace *efa = l->f;
2144       ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
2145     }
2146     EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
2147   }
2148 }
2149
2150 static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
2151                                         const ExtractPolyMesh_Params *params,
2152                                         void *data)
2153 {
2154   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
2155   {
2156     GPUPackedNormal *lnor_data = &((GPUPackedNormal *)data)[ml_index];
2157     if (mr->loop_normals) {
2158       *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]);
2159     }
2160     else if (mp->flag & ME_SMOOTH) {
2161       *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[ml->v].no);
2162     }
2163     else {
2164       *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]);
2165     }
2166
2167     /* Flag for paint mode overlay.
2168      * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals.
2169      * In paint mode it will use the un-mapped data to draw the wire-frame. */
2170     if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED &&
2171                                (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) {
2172       lnor_data->w = -1;
2173     }
2174     else if (mp->flag & ME_FACE_SEL) {
2175       lnor_data->w = 1;
2176     }
2177     else {
2178       lnor_data->w = 0;
2179     }
2180   }
2181   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
2182 }
2183
2184 static const MeshExtract extract_lnor = {
2185     .init = extract_lnor_init,
2186     .iter_poly_bm = extract_lnor_iter_poly_bm,
2187     .iter_poly_mesh = extract_lnor_iter_poly_mesh,
2188     .data_flag = MR_DATA_LOOP_NOR,
2189     .use_threading = true,
2190 };
2191
2192 /** \} */
2193
2194 /* ---------------------------------------------------------------------- */
2195 /** \name Extract UV  layers
2196  * \{ */
2197
2198 static void *extract_uv_init(const MeshRenderData *mr, void *buf)
2199 {
2200   GPUVertFormat format = {0};
2201   GPU_vertformat_deinterleave(&format);
2202
2203   CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
2204   uint32_t uv_layers = mr->cache->cd_used.uv;
2205
2206   /* HACK to fix T68857 */
2207   if (mr->extract_type == MR_EXTRACT_BMESH && mr->cache->cd_used.edit_uv == 1) {
2208     int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
2209     if (layer != -1) {
2210       uv_layers |= (1 << layer);
2211     }
2212   }
2213
2214   for (int i = 0; i < MAX_MTFACE; i++) {
2215     if (uv_layers & (1 << i)) {
2216       char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
2217       const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
2218
2219       GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
2220       /* UV layer name. */
2221       BLI_snprintf(attr_name, sizeof(attr_name), "u%s", attr_safe_name);
2222       GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
2223       /* Auto layer name. */
2224       BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
2225       GPU_vertformat_alias_add(&format, attr_name);
2226       /* Active render layer name. */
2227       if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
2228         GPU_vertformat_alias_add(&format, "u");
2229       }
2230       /* Active display layer name. */
2231       if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
2232         GPU_vertformat_alias_add(&format, "au");
2233         /* Alias to `pos` for edit uvs. */
2234         GPU_vertformat_alias_add(&format, "pos");
2235       }
2236       /* Stencil mask uv layer name. */
2237       if (i == CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV)) {
2238         GPU_vertformat_alias_add(&format, "mu");
2239       }
2240     }
2241   }
2242
2243   int v_len = mr->loop_len;
2244   if (format.attr_len == 0) {
2245     GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
2246     /* VBO will not be used, only allocate minimum of memory. */
2247     v_len = 1;
2248   }
2249
2250   GPUVertBuf *vbo = buf;
2251   GPU_vertbuf_init_with_format(vbo, &format);
2252   GPU_vertbuf_data_alloc(vbo, v_len);
2253
2254   float(*uv_data)[2] = (float(*)[2])vbo->data;
2255   for (int i = 0; i < MAX_MTFACE; i++) {
2256     if (uv_layers & (1 << i)) {
2257       if (mr->extract_type == MR_EXTRACT_BMESH) {
2258         int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPUV, i);
2259         BMIter f_iter;
2260         BMFace *efa;
2261         BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
2262           BMLoop *l_iter, *l_first;
2263           l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
2264           do {
2265             MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs);
2266             memcpy(uv_data, luv->uv, sizeof(*uv_data));
2267             uv_data++;
2268           } while ((l_iter = l_iter->next) != l_first);
2269         }
2270       }
2271       else {
2272         MLoopUV *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i);
2273         for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, uv_data++, layer_data++) {
2274           memcpy(uv_data, layer_data->uv, sizeof(*uv_data));
2275         }
2276       }
2277     }
2278   }
2279
2280   return NULL;
2281 }
2282
2283 static const MeshExtract extract_uv = {
2284     .init = extract_uv_init,
2285     .data_flag = 0,
2286     .use_threading = false,
2287 };
2288
2289 /** \} */
2290
2291 /* ---------------------------------------------------------------------- */
2292 /** \name Extract Tangent layers
2293  * \{ */
2294
2295 static void extract_tan_ex(const MeshRenderData *mr, GPUVertBuf *vbo, const bool do_hq)
2296 {
2297   GPUVertCompType comp_type = do_hq ? GPU_COMP_I16 : GPU_COMP_I10;
2298   GPUVertFetchMode fetch_mode = GPU_FETCH_INT_TO_FLOAT_UNIT;
2299
2300   GPUVertFormat format = {0};
2301   GPU_vertformat_deinterleave(&format);
2302
2303   CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
2304   CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
2305   uint32_t tan_layers = mr->cache->cd_used.tan;
2306   float(*orco)[3] = CustomData_get_layer(cd_vdata, CD_ORCO);
2307   bool orco_allocated = false;
2308   const bool use_orco_tan = mr->cache->cd_used.tan_orco != 0;
2309
2310   int tan_len = 0;
2311   char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME];
2312
2313   for (int i = 0; i < MAX_MTFACE; i++) {
2314     if (tan_layers & (1 << i)) {
2315       char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
2316       const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
2317       GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
2318       /* Tangent layer name. */
2319       BLI_snprintf(attr_name, sizeof(attr_name), "t%s", attr_safe_name);
2320       GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode);
2321       /* Active render layer name. */
2322       if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
2323         GPU_vertformat_alias_add(&format, "t");
2324       }
2325       /* Active display layer name. */
2326       if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
2327         GPU_vertformat_alias_add(&format, "at");
2328       }
2329
2330       BLI_strncpy(tangent_names[tan_len++], layer_name, MAX_CUSTOMDATA_LAYER_NAME);
2331     }
2332   }
2333   if (use_orco_tan && orco == NULL) {
2334     /* If `orco` is not available compute it ourselves */
2335     orco_allocated = true;
2336     orco = MEM_mallocN(sizeof(*orco) * mr->vert_len, __func__);
2337
2338     if (mr->extract_type == MR_EXTRACT_BMESH) {
2339       BMesh *bm = mr->bm;
2340       for (int v = 0; v < mr->vert_len; v++) {
2341         const BMVert *eve = BM_vert_at_index(bm, v);
2342         /* Exceptional case where #bm_vert_co_get can be avoided, as we want the original coords.
2343          * not the distorted ones. */
2344         copy_v3_v3(orco[v], eve->co);
2345       }
2346     }
2347     else {
2348       const MVert *mv = mr->mvert;
2349       for (int v = 0; v < mr->vert_len; v++, mv++) {
2350         copy_v3_v3(orco[v], mv->co);
2351       }
2352     }
2353     BKE_mesh_orco_verts_transform(mr->me, orco, mr->vert_len, 0);
2354   }
2355
2356   /* Start Fresh */
2357   CustomData loop_data;
2358   CustomData_reset(&loop_data);
2359   CustomData *ldata = cd_ldata;
2360   if (tan_len != 0 || use_orco_tan) {
2361     short tangent_mask = 0;
2362     bool calc_active_tangent = false;
2363     if (mr->extract_type == MR_EXTRACT_BMESH) {
2364       BKE_editmesh_loop_tangent_calc(mr->edit_bmesh,
2365                                      calc_active_tangent,
2366                                      tangent_names,
2367                                      tan_len,
2368                                      mr->poly_normals,
2369                                      mr->loop_normals,
2370                                      orco,
2371                                      cd_ldata,
2372                                      mr->loop_len,
2373                                      &tangent_mask);
2374     }
2375     else {
2376       BKE_mesh_calc_loop_tangent_ex(mr->mvert,
2377                                     mr->mpoly,
2378                                     mr->poly_len,
2379                                     mr->mloop,
2380                                     mr->mlooptri,
2381                                     mr->tri_len,
2382                                     cd_ldata,
2383                                     calc_active_tangent,
2384                                     tangent_names,
2385                                     tan_len,
2386                                     mr->poly_normals,
2387                                     mr->loop_normals,
2388                                     orco,
2389                                     &loop_data,
2390                                     mr->loop_len,
2391                                     &tangent_mask);
2392       ldata = &loop_data;
2393     }
2394   }
2395
2396   if (use_orco_tan) {
2397     char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
2398     const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_TANGENT, 0);
2399     GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
2400     BLI_snprintf(attr_name, sizeof(*attr_name), "t%s", attr_safe_name);
2401     GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode);
2402     GPU_vertformat_alias_add(&format, "t");
2403     GPU_vertformat_alias_add(&format, "at");
2404   }
2405
2406   if (orco_allocated) {
2407     MEM_SAFE_FREE(orco);
2408   }
2409
2410   int v_len = mr->loop_len;
2411   if (format.attr_len == 0) {
2412     GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
2413     /* VBO will not be used, only allocate minimum of memory. */
2414     v_len = 1;
2415   }
2416
2417   GPU_vertbuf_init_with_format(vbo, &format);
2418   GPU_vertbuf_data_alloc(vbo, v_len);
2419
2420   if (do_hq) {
2421     short(*tan_data)[4] = (short(*)[4])vbo->data;
2422     for (int i = 0; i < tan_len; i++) {
2423       const char *name = tangent_names[i];
2424       float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(ldata, CD_TANGENT, name);
2425       for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
2426         normal_float_to_short_v3(*tan_data, layer_data[ml_index]);
2427         (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
2428         tan_data++;
2429       }
2430     }
2431     if (use_orco_tan) {
2432       float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(ldata, CD_TANGENT, 0);
2433       for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
2434         normal_float_to_short_v3(*tan_data, layer_data[ml_index]);
2435         (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
2436         tan_data++;
2437       }
2438     }
2439   }
2440   else {
2441     GPUPackedNormal *tan_data = (GPUPackedNormal *)vbo->data;
2442     for (int i = 0; i < tan_len; i++) {
2443       const char *name = tangent_names[i];
2444       float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(ldata, CD_TANGENT, name);
2445       for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
2446         *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]);
2447         tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2;
2448         tan_data++;
2449       }
2450     }
2451     if (use_orco_tan) {
2452       float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(ldata, CD_TANGENT, 0);
2453       for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
2454         *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]);
2455         tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2;
2456         tan_data++;
2457       }
2458     }
2459   }
2460
2461   CustomData_free_layers(ldata, CD_TANGENT, mr->loop_len);
2462   CustomData_free(&loop_data, mr->loop_len);
2463 }
2464
2465 static void *extract_tan_init(const MeshRenderData *mr, void *buf)
2466 {
2467   extract_tan_ex(mr, buf, false);
2468   return NULL;
2469 }
2470
2471 static const MeshExtract extract_tan = {
2472     .init = extract_tan_init,
2473     .data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI,
2474     .use_threading = false,
2475 };
2476
2477 /** \} */
2478
2479 /* ---------------------------------------------------------------------- */
2480 /** \name Extract HQ Tangent layers
2481  * \{ */
2482
2483 static void *extract_tan_hq_init(const MeshRenderData *mr, void *buf)
2484 {
2485   extract_tan_ex(mr, buf, true);
2486   return NULL;
2487 }
2488
2489 static const MeshExtract extract_tan_hq = {
2490     .init = extract_tan_hq_init,
2491     .data_flag = MR_DATA_POLY_NOR | MR_DATA_TAN_LOOP_NOR | MR_DATA_LOOPTRI,
2492     .use_threading = false,
2493 };
2494
2495 /** \} */
2496
2497 /* ---------------------------------------------------------------------- */
2498 /** \name Extract VCol
2499  * \{ */
2500
2501 static void *extract_vcol_init(const MeshRenderData *mr, void *buf)
2502 {
2503   GPUVertFormat format = {0};
2504   GPU_vertformat_deinterleave(&format);
2505
2506   CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
2507   CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
2508   uint32_t vcol_layers = mr->cache->cd_used.vcol;
2509   uint32_t svcol_layers = mr->cache->cd_used.sculpt_vcol;
2510
2511   for (int i = 0; i < MAX_MCOL; i++) {
2512     if (vcol_layers & (1 << i)) {
2513       char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
2514       const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i);
2515       GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
2516
2517       BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
2518       GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
2519
2520       if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) {
2521         GPU_vertformat_alias_add(&format, "c");
2522       }
2523       if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) {
2524         GPU_vertformat_alias_add(&format, "ac");
2525       }
2526
2527       /* Gather number of auto layers. */
2528       /* We only do `vcols` that are not overridden by `uvs` and sculpt vertex colors. */
2529       if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1 &&
2530           CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, layer_name) == -1) {
2531         BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
2532         GPU_vertformat_alias_add(&format, attr_name);
2533       }
2534     }
2535   }
2536
2537   /* Sculpt Vertex Colors */
2538   for (int i = 0; i < 8; i++) {
2539     if (svcol_layers & (1 << i)) {
2540       char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
2541       const char *layer_name = CustomData_get_layer_name(cd_vdata, CD_PROP_COLOR, i);
2542       GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
2543
2544       BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
2545       GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
2546
2547       if (i == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) {
2548         GPU_vertformat_alias_add(&format, "c");
2549       }
2550       if (i == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) {
2551         GPU_vertformat_alias_add(&format, "ac");
2552       }
2553       /* Gather number of auto layers. */
2554       /* We only do `vcols` that are not overridden by `uvs`. */
2555       if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
2556         BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
2557         GPU_vertformat_alias_add(&format, attr_name);
2558       }
2559     }
2560   }
2561
2562   GPUVertBuf *vbo = buf;
2563   GPU_vertbuf_init_with_format(vbo, &format);
2564   GPU_vertbuf_data_alloc(vbo, mr->loop_len);
2565
2566   typedef struct gpuMeshVcol {
2567     ushort r, g, b, a;
2568   } gpuMeshVcol;
2569
2570   gpuMeshVcol *vcol_data = (gpuMeshVcol *)vbo->data;
2571   MLoop *loops = CustomData_get_layer(cd_ldata, CD_MLOOP);
2572
2573   for (int i = 0; i < MAX_MCOL; i++) {
2574     if (vcol_layers & (1 << i)) {
2575       if (mr->extract_type == MR_EXTRACT_BMESH) {
2576         int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPCOL, i);
2577         BMIter f_iter;
2578         BMFace *efa;
2579         BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
2580           BMLoop *l_iter, *l_first;
2581           l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
2582           do {
2583             const MLoopCol *mloopcol = BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs);
2584             vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
2585             vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
2586             vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
2587             vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
2588             vcol_data++;
2589           } while ((l_iter = l_iter->next) != l_first);
2590         }
2591       }
2592       else {
2593         const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
2594         for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, mloopcol++, vcol_data++) {
2595           vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
2596           vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
2597           vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
2598           vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
2599         }
2600       }
2601     }
2602
2603     if (svcol_layers & (1 << i)) {
2604       if (mr->extract_type == MR_EXTRACT_BMESH) {
2605         int cd_ofs = CustomData_get_n_offset(cd_vdata, CD_PROP_COLOR, i);
2606         BMIter f_iter;
2607         BMFace *efa;
2608         BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
2609           BMLoop *l_iter, *l_first;
2610           l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
2611           do {
2612             const MPropCol *prop_col = BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs);
2613             vcol_data->r = unit_float_to_ushort_clamp(prop_col->color[0]);
2614             vcol_data->g = unit_float_to_ushort_clamp(prop_col->color[1]);
2615             vcol_data->b = unit_float_to_ushort_clamp(prop_col->color[2]);
2616             vcol_data->a = unit_float_to_ushort_clamp(prop_col->color[3]);
2617             vcol_data++;
2618           } while ((l_iter = l_iter->next) != l_first);
2619         }
2620       }
2621       else {
2622         MPropCol *vcol = CustomData_get_layer_n(cd_vdata, CD_PROP_COLOR, i);
2623         for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vcol_data++) {
2624           vcol_data->r = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[0]);
2625           vcol_data->g = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[1]);
2626           vcol_data->b = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[2]);
2627           vcol_data->a = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[3]);
2628         }
2629       }
2630
2631       vcol_data += mr->loop_len;
2632     }
2633   }
2634   return NULL;
2635 }
2636
2637 static const MeshExtract extract_vcol = {
2638     .init = extract_vcol_init,
2639     .data_flag = 0,
2640     .use_threading = false,
2641 };
2642
2643 /** \} */
2644
2645 /* ---------------------------------------------------------------------- */
2646 /** \name Extract Orco
2647  * \{ */
2648
2649 typedef struct MeshExtract_Orco_Data {
2650   float (*vbo_data)[4];
2651   float (*orco)[3];
2652 } MeshExtract_Orco_Data;
2653
2654 static void *extract_orco_init(const MeshRenderData *mr, void *buf)
2655 {
2656   static GPUVertFormat format = {0};
2657   if (format.attr_len == 0) {
2658     /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
2659      * attributes. This is a substantial waste of video-ram and should be done another way.
2660      * Unfortunately, at the time of writing, I did not found any other "non disruptive"
2661      * alternative. */
2662     GPU_vertformat_attr_add(&format, "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
2663   }
2664
2665   GPUVertBuf *vbo = buf;
2666   GPU_vertbuf_init_with_format(vbo, &format);
2667   GPU_vertbuf_data_alloc(vbo, mr->loop_len);
2668
2669   CustomData *cd_vdata = &mr->me->vdata;
2670
2671   MeshExtract_Orco_Data *data = MEM_mallocN(sizeof(*data), __func__);
2672   data->vbo_data = (float(*)[4])vbo->data;
2673   data->orco = CustomData_get_layer(cd_vdata, CD_ORCO);
2674   /* Make sure `orco` layer was requested only if needed! */
2675   BLI_assert(data->orco);
2676   return data;
2677 }
2678
2679 static void extract_orco_iter_poly_bm(const MeshRenderData *mr,
2680                                       const ExtractPolyBMesh_Params *params,
2681                                       void *data)
2682 {
2683   MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data;
2684   EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(loop, l_index, params, mr)
2685   {
2686     float *loop_orco = orco_data->vbo_data[l_index];
2687     copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]);
2688     loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
2689   }
2690   EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(loop);
2691 }
2692
2693 static void extract_orco_iter_poly_mesh(const MeshRenderData *mr,
2694                                         const ExtractPolyMesh_Params *params,
2695                                         void *data)
2696 {
2697   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
2698   {
2699     MeshExtract_Orco_Data *orco_data = (MeshExtract_Orco_Data *)data;
2700     float *loop_orco = orco_data->vbo_data[ml_index];
2701     copy_v3_v3(loop_orco, orco_data->orco[ml->v]);
2702     loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
2703   }
2704   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
2705 }
2706
2707 static void extract_orco_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data)
2708 {
2709   MEM_freeN(data);
2710 }
2711
2712 static const MeshExtract extract_orco = {
2713     .init = extract_orco_init,
2714     .iter_poly_bm = extract_orco_iter_poly_bm,
2715     .iter_poly_mesh = extract_orco_iter_poly_mesh,
2716     .finish = extract_orco_finish,
2717     .data_flag = 0,
2718     .use_threading = true,
2719 };
2720
2721 /** \} */
2722
2723 /* ---------------------------------------------------------------------- */
2724 /** \name Extract Edge Factor
2725  * Defines how much an edge is visible.
2726  * \{ */
2727
2728 typedef struct MeshExtract_EdgeFac_Data {
2729   uchar *vbo_data;
2730   bool use_edge_render;
2731   /* Number of loop per edge. */
2732   uchar edge_loop_count[0];
2733 } MeshExtract_EdgeFac_Data;
2734
2735 static float loop_edge_factor_get(const float f_no[3],
2736                                   const float v_co[3],
2737                                   const float v_no[3],
2738                                   const float v_next_co[3])
2739 {
2740   float enor[3], evec[3];
2741   sub_v3_v3v3(evec, v_next_co, v_co);
2742   cross_v3_v3v3(enor, v_no, evec);
2743   normalize_v3(enor);
2744   float d = fabsf(dot_v3v3(enor, f_no));
2745   /* Re-scale to the slider range. */
2746   d *= (1.0f / 0.065f);
2747   CLAMP(d, 0.0f, 1.0f);
2748   return d;
2749 }
2750
2751 static void *extract_edge_fac_init(const MeshRenderData *mr, void *buf)
2752 {
2753   static GPUVertFormat format = {0};
2754   if (format.attr_len == 0) {
2755     GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
2756   }
2757   GPUVertBuf *vbo = buf;
2758   GPU_vertbuf_init_with_format(vbo, &format);
2759   GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
2760
2761   MeshExtract_EdgeFac_Data *data;
2762
2763   if (mr->extract_type == MR_EXTRACT_MESH) {
2764     size_t edge_loop_count_size = sizeof(uint32_t) * mr->edge_len;
2765     data = MEM_callocN(sizeof(*data) + edge_loop_count_size, __func__);
2766
2767     /* HACK(fclem) Detecting the need for edge render.
2768      * We could have a flag in the mesh instead or check the modifier stack. */
2769     const MEdge *med = mr->medge;
2770     for (int e_index = 0; e_index < mr->edge_len; e_index++, med++) {
2771       if ((med->flag & ME_EDGERENDER) == 0) {
2772         data->use_edge_render = true;
2773         break;
2774       }
2775     }
2776   }
2777   else {
2778     data = MEM_callocN(sizeof(*data), __func__);
2779     /* HACK to bypass non-manifold check in mesh_edge_fac_finish(). */
2780     data->use_edge_render = true;
2781   }
2782
2783   data->vbo_data = vbo->data;
2784   return data;
2785 }
2786
2787 static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr,
2788                                           const ExtractPolyBMesh_Params *params,
2789                                           void *_data)
2790 {
2791   MeshExtract_EdgeFac_Data *data = _data;
2792   EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
2793   {
2794     if (BM_edge_is_manifold(l->e)) {
2795       float ratio = loop_edge_factor_get(bm_face_no_get(mr, l->f),
2796                                          bm_vert_co_get(mr, l->v),
2797                                          bm_vert_no_get(mr, l->v),
2798                                          bm_vert_co_get(mr, l->next->v));
2799       data->vbo_data[l_index] = ratio * 253 + 1;
2800     }
2801     else {
2802       data->vbo_data[l_index] = 255;
2803     }
2804   }
2805   EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
2806 }
2807
2808 static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr,
2809                                             const ExtractPolyMesh_Params *params,
2810                                             void *_data)
2811 {
2812   MeshExtract_EdgeFac_Data *data = (MeshExtract_EdgeFac_Data *)_data;
2813
2814   if (data->use_edge_render) {
2815     EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
2816     {
2817       const MEdge *med = &mr->medge[ml->e];
2818       data->vbo_data[ml_index] = (med->flag & ME_EDGERENDER) ? 255 : 0;
2819     }
2820     EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
2821   }
2822   else {
2823     EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
2824     {
2825       /* Count loop per edge to detect non-manifold. */
2826       if (data->edge_loop_count[ml->e] < 3) {
2827         data->edge_loop_count[ml->e]++;
2828       }
2829       if (data->edge_loop_count[ml->e] == 2) {
2830         /* Manifold */
2831         const int ml_index_last = mp->totloop + mp->loopstart - 1;
2832         const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1);
2833         const MLoop *ml_next = &mr->mloop[ml_index_other];
2834         const MVert *v1 = &mr->mvert[ml->v];
2835         const MVert *v2 = &mr->mvert[ml_next->v];
2836         float vnor_f[3];
2837         normal_short_to_float_v3(vnor_f, v1->no);
2838         float ratio = loop_edge_factor_get(mr->poly_normals[mp_index], v1->co, vnor_f, v2->co);
2839         data->vbo_data[ml_index] = ratio * 253 + 1;
2840       }
2841       else {
2842         /* Non-manifold */
2843         data->vbo_data[ml_index] = 255;
2844       }
2845     }
2846     EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
2847   }
2848 }
2849
2850 static void extract_edge_fac_iter_ledge_bm(const MeshRenderData *mr,
2851                                            const ExtractLEdgeBMesh_Params *params,
2852                                            void *_data)
2853 {
2854   MeshExtract_EdgeFac_Data *data = _data;
2855   EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
2856   {
2857     data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255;
2858     data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255;
2859   }
2860   EXTRACT_LEDGE_FOREACH_BM_END;
2861 }
2862
2863 static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr,
2864                                              const ExtractLEdgeMesh_Params *params,
2865                                              void *_data)
2866 {
2867   MeshExtract_EdgeFac_Data *data = _data;
2868   EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
2869   {
2870     data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255;
2871     data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255;
2872   }
2873   EXTRACT_LEDGE_FOREACH_MESH_END;
2874 }
2875
2876 static void extract_edge_fac_finish(const MeshRenderData *mr, void *buf, void *_data)
2877 {
2878   MeshExtract_EdgeFac_Data *data = _data;
2879
2880   if (GPU_crappy_amd_driver()) {
2881     GPUVertBuf *vbo = (GPUVertBuf *)buf;
2882     /* Some AMD drivers strangely crash with VBO's with a one byte format.
2883      * To workaround we reinitialize the VBO with another format and convert
2884      * all bytes to floats. */
2885     static GPUVertFormat format = {0};
2886     if (format.attr_len == 0) {
2887       GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
2888     }
2889     /* We keep the data reference in data->vbo_data. */
2890     vbo->data = NULL;
2891     GPU_vertbuf_clear(vbo);
2892
2893     int buf_len = mr->loop_len + mr->loop_loose_len;
2894     GPU_vertbuf_init_with_format(vbo, &format);
2895     GPU_vertbuf_data_alloc(vbo, buf_len);
2896
2897     float *fdata = (float *)vbo->data;
2898     for (int ml_index = 0; ml_index < buf_len; ml_index++, fdata++) {
2899       *fdata = data->vbo_data[ml_index] / 255.0f;
2900     }
2901     /* Free old byte data. */
2902     MEM_freeN(data->vbo_data);
2903   }
2904   MEM_freeN(data);
2905 }
2906
2907 static const MeshExtract extract_edge_fac = {
2908     .init = extract_edge_fac_init,
2909     .iter_poly_bm = extract_edge_fac_iter_poly_bm,
2910     .iter_poly_mesh = extract_edge_fac_iter_poly_mesh,
2911     .iter_ledge_bm = extract_edge_fac_iter_ledge_bm,
2912     .iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh,
2913     .finish = extract_edge_fac_finish,
2914     .data_flag = MR_DATA_POLY_NOR,
2915     .use_threading = false,
2916 };
2917
2918 /** \} */
2919 /* ---------------------------------------------------------------------- */
2920 /** \name Extract Vertex Weight
2921  * \{ */
2922
2923 typedef struct MeshExtract_Weight_Data {
2924   float *vbo_data;
2925   const DRW_MeshWeightState *wstate;
2926   const MDeformVert *dvert; /* For #Mesh. */
2927   int cd_ofs;               /* For #BMesh. */
2928 } MeshExtract_Weight_Data;
2929
2930 static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate)
2931 {
2932   /* Error state. */
2933   if ((wstate->defgroup_active < 0) && (wstate->defgroup_len > 0)) {
2934     return -2.0f;
2935   }
2936   else if (dvert == NULL) {
2937     return (wstate->alert_mode != OB_DRAW_GROUPUSER_NONE) ? -1.0f : 0.0f;
2938   }
2939
2940   float input = 0.0f;
2941   if (wstate->flags & DRW_MESH_WEIGHT_STATE_MULTIPAINT) {
2942     /* Multi-Paint feature */
2943     bool is_normalized = (wstate->flags & (DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE |
2944                                            DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE));
2945     input = BKE_defvert_multipaint_collective_weight(dvert,
2946                                                      wstate->defgroup_len,
2947                                                      wstate->defgroup_sel,
2948                                                      wstate->defgroup_sel_count,
2949                                                      is_normalized);
2950     /* make it black if the selected groups have no weight on a vertex */
2951     if (input == 0.0f) {
2952       return -1.0f;
2953     }
2954   }
2955   else {
2956     /* default, non tricky behavior */
2957     input = BKE_defvert_find_weight(dvert, wstate->defgroup_active);
2958
2959     if (input == 0.0f) {
2960       switch (wstate->alert_mode) {
2961         case OB_DRAW_GROUPUSER_ACTIVE:
2962           return -1.0f;
2963           break;
2964         case OB_DRAW_GROUPUSER_ALL:
2965           if (BKE_defvert_is_weight_zero(dvert, wstate->defgroup_len)) {
2966             return -1.0f;
2967           }
2968           break;
2969       }
2970     }
2971   }
2972
2973   /* Lock-Relative: display the fraction of current weight vs total unlocked weight. */
2974   if (wstate->flags & DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE) {
2975     input = BKE_defvert_lock_relative_weight(
2976         input, dvert, wstate->defgroup_len, wstate->defgroup_locked, wstate->defgroup_unlocked);
2977   }
2978
2979   CLAMP(input, 0.0f, 1.0f);
2980   return input;
2981 }
2982
2983 static void *extract_weights_init(const MeshRenderData *mr, void *buf)
2984 {
2985   static GPUVertFormat format = {0};
2986   if (format.attr_len == 0) {
2987     GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
2988   }
2989   GPUVertBuf *vbo = buf;
2990   GPU_vertbuf_init_with_format(vbo, &format);
2991   GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
2992
2993   MeshExtract_Weight_Data *data = MEM_callocN(sizeof(*data), __func__);
2994   data->vbo_data = (float *)vbo->data;
2995   data->wstate = &mr->cache->weight_state;
2996
2997   if (data->wstate->defgroup_active == -1) {
2998     /* Nothing to show. */
2999     data->dvert = NULL;
3000     data->cd_ofs = -1;
3001   }
3002   else if (mr->extract_type == MR_EXTRACT_BMESH) {
3003     data->dvert = NULL;
3004     data->cd_ofs = CustomData_get_offset(&mr->bm->vdata, CD_MDEFORMVERT);
3005   }
3006   else {
3007     data->dvert = CustomData_get_layer(&mr->me->vdata, CD_MDEFORMVERT);
3008     data->cd_ofs = -1;
3009   }
3010   return data;
3011 }
3012
3013 static void extract_weights_iter_poly_bm(const MeshRenderData *mr,
3014                                          const ExtractPolyBMesh_Params *params,
3015                                          void *_data)
3016 {
3017   MeshExtract_Weight_Data *data = _data;
3018   if (data->cd_ofs != -1) {
3019     EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
3020     {
3021       const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(l->v, data->cd_ofs);
3022       data->vbo_data[l_index] = evaluate_vertex_weight(dvert, data->wstate);
3023     }
3024     EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
3025   }
3026   else {
3027     EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
3028     {
3029       data->vbo_data[l_index] = evaluate_vertex_weight(NULL, data->wstate);
3030     }
3031     EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
3032   }
3033 }
3034
3035 static void extract_weights_iter_poly_mesh(const MeshRenderData *mr,
3036                                            const ExtractPolyMesh_Params *params,
3037                                            void *_data)
3038 {
3039   MeshExtract_Weight_Data *data = _data;
3040   if (data->dvert != NULL) {
3041     EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
3042     {
3043       const MDeformVert *dvert = &data->dvert[ml->v];
3044       data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate);
3045     }
3046     EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
3047   }
3048   else {
3049     const MDeformVert *dvert = NULL;
3050     EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
3051     {
3052       data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate);
3053     }
3054     EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
3055   }
3056 }
3057
3058 static void extract_weights_finish(const MeshRenderData *UNUSED(mr), void *UNUSED(buf), void *data)
3059 {
3060   MEM_freeN(data);
3061 }
3062
3063 static const MeshExtract extract_weights = {
3064     .init = extract_weights_init,
3065     .iter_poly_bm = extract_weights_iter_poly_bm,
3066     .iter_poly_mesh = extract_weights_iter_poly_mesh,
3067     .finish = extract_weights_finish,
3068     .data_flag = 0,
3069     .use_threading = true,
3070 };
3071
3072 /** \} */
3073
3074 /* ---------------------------------------------------------------------- */
3075 /** \name Extract Edit Mode Data / Flags
3076  * \{ */
3077
3078 typedef struct EditLoopData {
3079   uchar v_flag;
3080   uchar e_flag;
3081   uchar crease;
3082   uchar bweight;
3083 } EditLoopData;
3084
3085 static void mesh_render_data_face_flag(const MeshRenderData *mr,
3086                                        BMFace *efa,
3087                                        const int cd_ofs,
3088                                        EditLoopData *eattr)
3089 {
3090   if (efa == mr->efa_act) {
3091     eattr->v_flag |= VFLAG_FACE_ACTIVE;
3092   }
3093   if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
3094     eattr->v_flag |= VFLAG_FACE_SELECTED;
3095   }
3096
3097   if (efa == mr->efa_act_uv) {
3098     eattr->v_flag |= VFLAG_FACE_UV_ACTIVE;
3099   }
3100   if ((cd_ofs != -1) && uvedit_face_select_test_ex(mr->toolsettings, (BMFace *)efa, cd_ofs)) {
3101     eattr->v_flag |= VFLAG_FACE_UV_SELECT;
3102   }
3103
3104 #ifdef WITH_FREESTYLE
3105   if (mr->freestyle_face_ofs != -1) {
3106     const FreestyleFace *ffa = BM_ELEM_CD_GET_VOID_P(efa, mr->freestyle_face_ofs);
3107     if (ffa->flag & FREESTYLE_FACE_MARK) {
3108       eattr->v_flag |= VFLAG_FACE_FREESTYLE;
3109     }
3110   }
3111 #endif
3112 }
3113
3114 static void mesh_render_data_edge_flag(const MeshRenderData *mr, BMEdge *eed, EditLoopData *eattr)
3115 {
3116   const ToolSettings *ts = mr->toolsettings;
3117   const bool is_vertex_select_mode = (ts != NULL) && (ts->selectmode & SCE_SELECT_VERTEX) != 0;
3118   const bool is_face_only_select_mode = (ts != NULL) && (ts->selectmode == SCE_SELECT_FACE);
3119
3120   if (eed == mr->eed_act) {
3121     eattr->e_flag |= VFLAG_EDGE_ACTIVE;
3122   }
3123   if (!is_vertex_select_mode && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
3124     eattr->e_flag |= VFLAG_EDGE_SELECTED;
3125   }
3126   if (is_vertex_select_mode && BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) &&
3127       BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) {
3128     eattr->e_flag |= VFLAG_EDGE_SELECTED;
3129     eattr->e_flag |= VFLAG_VERT_SELECTED;
3130   }
3131   if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
3132     eattr->e_flag |= VFLAG_EDGE_SEAM;
3133   }
3134   if (!BM_elem_flag_test(eed, BM_ELEM_SMOOTH)) {
3135     eattr->e_flag |= VFLAG_EDGE_SHARP;
3136   }
3137
3138   /* Use active edge color for active face edges because
3139    * specular highlights make it hard to see T55456#510873.
3140    *
3141    * This isn't ideal since it can't be used when mixing edge/face modes
3142    * but it's still better then not being able to see the active face. */
3143   if (is_face_only_select_mode) {
3144     if (mr->efa_act != NULL) {
3145       if (BM_edge_in_face(eed, mr->efa_act)) {
3146         eattr->e_flag |= VFLAG_EDGE_ACTIVE;
3147       }
3148     }
3149   }
3150
3151   /* Use a byte for value range */
3152   if (mr->crease_ofs != -1) {
3153     float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->crease_ofs);
3154     if (crease > 0) {
3155       eattr->crease = (uchar)(crease * 255.0f);
3156     }
3157   }
3158   /* Use a byte for value range */
3159   if (mr->bweight_ofs != -1) {
3160     float bweight = BM_ELEM_CD_GET_FLOAT(eed, mr->bweight_ofs);
3161     if (bweight > 0) {
3162       eattr->bweight = (uchar)(bweight * 255.0f);
3163     }
3164   }
3165 #ifdef WITH_FREESTYLE
3166   if (mr->freestyle_edge_ofs != -1) {
3167     const FreestyleEdge *fed = BM_ELEM_CD_GET_VOID_P(eed, mr->freestyle_edge_ofs);
3168     if (fed->flag & FREESTYLE_EDGE_MARK) {
3169       eattr->e_flag |= VFLAG_EDGE_FREESTYLE;
3170     }
3171   }
3172 #endif
3173 }
3174
3175 static void mesh_render_data_loop_flag(const MeshRenderData *mr,
3176                                        BMLoop *l,
3177                                        const int cd_ofs,
3178                                        EditLoopData *eattr)
3179 {
3180   if (cd_ofs == -1) {
3181     return;
3182   }
3183   MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_ofs);
3184   if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) {
3185     eattr->v_flag |= VFLAG_VERT_UV_PINNED;
3186   }
3187   if (uvedit_uv_select_test_ex(mr->toolsettings, l, cd_ofs)) {
3188     eattr->v_flag |= VFLAG_VERT_UV_SELECT;
3189   }
3190 }
3191
3192 static void mesh_render_data_loop_edge_flag(const MeshRenderData *mr,
3193                                             BMLoop *l,
3194                                             const int cd_ofs,
3195                                             EditLoopData *eattr)
3196 {
3197   if (cd_ofs == -1) {
3198     return;
3199   }
3200   if (uvedit_edge_select_test_ex(mr->toolsettings, l, cd_ofs)) {
3201     eattr->v_flag |= VFLAG_EDGE_UV_SELECT;
3202     eattr->v_flag |= VFLAG_VERT_UV_SELECT;
3203   }
3204 }
3205
3206 static void mesh_render_data_vert_flag(const MeshRenderData *mr, BMVert *eve, EditLoopData *eattr)
3207 {
3208   if (eve == mr->eve_act) {
3209     eattr->e_flag |= VFLAG_VERT_ACTIVE;
3210   }
3211   if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
3212     eattr->e_flag |= VFLAG_VERT_SELECTED;
3213   }
3214 }
3215
3216 static void *extract_edit_data_init(const MeshRenderData *mr, void *buf)
3217 {
3218   static GPUVertFormat format = {0};
3219   if (format.attr_len == 0) {
3220     /* WARNING: Adjust #EditLoopData struct accordingly. */
3221     GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
3222     GPU_vertformat_alias_add(&format, "flag");
3223   }
3224   GPUVertBuf *vbo = buf;
3225   GPU_vertbuf_init_with_format(vbo, &format);
3226   GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
3227   return vbo->data;
3228 }
3229
3230 static void extract_edit_data_iter_poly_bm(const MeshRenderData *mr,
3231                                            const ExtractPolyBMesh_Params *params,
3232                                            void *_data)
3233 {
3234
3235   EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
3236   {
3237     EditLoopData *data = (EditLoopData *)_data + l_index;
3238     memset(data, 0x0, sizeof(*data));
3239     mesh_render_data_face_flag(mr, l->f, -1, data);
3240     mesh_render_data_edge_flag(mr, l->e, data);
3241     mesh_render_data_vert_flag(mr, l->v, data);
3242   }
3243   EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
3244 }
3245
3246 static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr,
3247                                              const ExtractPolyMesh_Params *params,
3248                                              void *_data)
3249 {
3250   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
3251   {
3252     EditLoopData *data = (EditLoopData *)_data + ml_index;
3253     memset(data, 0x0, sizeof(*data));
3254     BMFace *efa = bm_original_face_get(mr, mp_index);
3255     BMEdge *eed = bm_original_edge_get(mr, ml->e);
3256     BMVert *eve = bm_original_vert_get(mr, ml->v);
3257     if (efa) {
3258       mesh_render_data_face_flag(mr, efa, -1, data);
3259     }
3260     if (eed) {
3261       mesh_render_data_edge_flag(mr, eed, data);
3262     }
3263     if (eve) {
3264       mesh_render_data_vert_flag(mr, eve, data);
3265     }
3266   }
3267   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
3268 }
3269
3270 static void extract_edit_data_iter_ledge_bm(const MeshRenderData *mr,
3271                                             const ExtractLEdgeBMesh_Params *params,
3272                                             void *_data)
3273 {
3274   EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
3275   {
3276     EditLoopData *data = (EditLoopData *)_data + mr->loop_len + (ledge_index * 2);
3277     memset(data, 0x0, sizeof(*data) * 2);
3278     mesh_render_data_edge_flag(mr, eed, &data[0]);
3279     data[1] = data[0];
3280     mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
3281     mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
3282   }
3283   EXTRACT_LEDGE_FOREACH_BM_END;
3284 }
3285
3286 static void extract_edit_data_iter_ledge_mesh(const MeshRenderData *mr,
3287                                               const ExtractLEdgeMesh_Params *params,
3288                                               void *_data)
3289 {
3290   EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
3291   {
3292     EditLoopData *data = (EditLoopData *)_data + mr->loop_len + ledge_index * 2;
3293     memset(data, 0x0, sizeof(*data) * 2);
3294     const int e_index = mr->ledges[ledge_index];
3295     BMEdge *eed = bm_original_edge_get(mr, e_index);
3296     BMVert *eve1 = bm_original_vert_get(mr, med->v1);
3297     BMVert *eve2 = bm_original_vert_get(mr, med->v2);
3298     if (eed) {
3299       mesh_render_data_edge_flag(mr, eed, &data[0]);
3300       data[1] = data[0];
3301     }
3302     if (eve1) {
3303       mesh_render_data_vert_flag(mr, eve1, &data[0]);
3304     }
3305     if (eve2) {
3306       mesh_render_data_vert_flag(mr, eve2, &data[1]);
3307     }
3308   }
3309   EXTRACT_LEDGE_FOREACH_MESH_END;
3310 }
3311
3312 static void extract_edit_data_iter_lvert_bm(const MeshRenderData *mr,
3313                                             const ExtractLVertBMesh_Params *params,
3314                                             void *_data)
3315 {
3316   const int offset = mr->loop_len + (mr->edge_loose_len * 2);
3317   EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
3318   {
3319     EditLoopData *data = (EditLoopData *)_data + offset + lvert_index;
3320     memset(data, 0x0, sizeof(*data));
3321     mesh_render_data_vert_flag(mr, eve, data);
3322   }
3323   EXTRACT_LVERT_FOREACH_BM_END;
3324 }
3325
3326 static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr,
3327                                               const ExtractLVertMesh_Params *params,
3328                                               void *_data)
3329 {
3330   const int offset = mr->loop_len + (mr->edge_loose_len * 2);
3331   EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
3332   {
3333     EditLoopData *data = (EditLoopData *)_data + offset + lvert_index;
3334     memset(data, 0x0, sizeof(*data));
3335     const int v_index = mr->lverts[lvert_index];
3336     BMVert *eve = bm_original_vert_get(mr, v_index);
3337     if (eve) {
3338       mesh_render_data_vert_flag(mr, eve, data);
3339     }
3340   }
3341   EXTRACT_LVERT_FOREACH_MESH_END;
3342 }
3343
3344 static const MeshExtract extract_edit_data = {
3345     .init = extract_edit_data_init,
3346     .iter_poly_bm = extract_edit_data_iter_poly_bm,
3347     .iter_poly_mesh = extract_edit_data_iter_poly_mesh,
3348     .iter_ledge_bm = extract_edit_data_iter_ledge_bm,
3349     .iter_ledge_mesh = extract_edit_data_iter_ledge_mesh,
3350     .iter_lvert_bm = extract_edit_data_iter_lvert_bm,
3351     .iter_lvert_mesh = extract_edit_data_iter_lvert_mesh,
3352     .data_flag = 0,
3353     .use_threading = true,
3354 };
3355
3356 /** \} */
3357
3358 /* ---------------------------------------------------------------------- */
3359 /** \name Extract Edit UV Data / Flags
3360  * \{ */
3361
3362 typedef struct MeshExtract_EditUVData_Data {
3363   EditLoopData *vbo_data;
3364   int cd_ofs;
3365 } MeshExtract_EditUVData_Data;
3366
3367 static void *extract_edituv_data_init(const MeshRenderData *mr, void *buf)
3368 {
3369   static GPUVertFormat format = {0};
3370   if (format.attr_len == 0) {
3371     /* WARNING: Adjust #EditLoopData struct accordingly. */
3372     GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
3373     GPU_vertformat_alias_add(&format, "flag");
3374   }
3375
3376   GPUVertBuf *vbo = buf;
3377   GPU_vertbuf_init_with_format(vbo, &format);
3378   GPU_vertbuf_data_alloc(vbo, mr->loop_len);
3379
3380   CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
3381
3382   MeshExtract_EditUVData_Data *data = MEM_callocN(sizeof(*data), __func__);
3383   data->vbo_data = (EditLoopData *)vbo->data;
3384   data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV);
3385   return data;
3386 }
3387
3388 static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr,
3389                                              const ExtractPolyBMesh_Params *params,
3390                                              void *_data)
3391 {
3392   EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(l, l_index, params, mr)
3393   {
3394     MeshExtract_EditUVData_Data *data = _data;
3395     EditLoopData *eldata = &data->vbo_data[l_index];
3396     memset(eldata, 0x0, sizeof(*eldata));
3397     mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata);
3398     mesh_render_data_face_flag(mr, l->f, data->cd_ofs, eldata);
3399     mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata);
3400   }
3401   EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(l);
3402 }
3403
3404 static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr,
3405                                                const ExtractPolyMesh_Params *params,
3406                                                void *_data)
3407 {
3408   MeshExtract_EditUVData_Data *data = _data;
3409   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
3410   {
3411     EditLoopData *eldata = &data->vbo_data[ml_index];
3412     memset(eldata, 0x0, sizeof(*eldata));
3413     BMFace *efa = bm_original_face_get(mr, mp_index);
3414     if (efa) {
3415       BMEdge *eed = bm_original_edge_get(mr, ml->e);
3416       BMVert *eve = bm_original_vert_get(mr, ml->v);
3417       if (eed && eve) {
3418         /* Loop on an edge endpoint. */
3419         BMLoop *l = BM_face_edge_share_loop(efa, eed);
3420         mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata);
3421         mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata);
3422       }
3423       else {
3424         if (eed == NULL) {
3425           /* Find if the loop's vert is not part of an edit edge.
3426            * For this, we check if the previous loop was on an edge. */
3427           const int ml_index_last = mp->loopstart + mp->totloop - 1;
3428           const int l_prev = (ml_index == mp->loopstart) ? ml_index_last : (ml_index - 1);
3429           const MLoop *ml_prev = &mr->mloop[l_prev];
3430           eed = bm_original_edge_get(mr, ml_prev->e);
3431         }
3432         if (eed) {
3433           /* Mapped points on an edge between two edit verts. */
3434           BMLoop *l = BM_face_edge_share_loop(efa, eed);
3435           mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata);
3436         }
3437       }
3438     }
3439   }
3440   EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END;
3441 }