Blender  V2.93
draw_cache_extract_mesh.c
Go to the documentation of this file.
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 
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 #include "BKE_paint.h"
57 
58 #include "atomic_ops.h"
59 
60 #include "bmesh.h"
61 
62 #include "GPU_batch.h"
63 #include "GPU_capabilities.h"
64 
65 #include "DRW_render.h"
66 
67 #include "ED_mesh.h"
68 #include "ED_uvedit.h"
69 
70 #include "draw_cache_impl.h"
71 #include "draw_cache_inline.h"
72 
73 #include "draw_cache_extract.h"
74 
75 // #define DEBUG_TIME
76 
77 #ifdef DEBUG_TIME
78 # include "PIL_time_utildefines.h"
79 #endif
80 
81 /* ---------------------------------------------------------------------- */
85 typedef struct MeshRenderData {
87 
92  int tri_len;
93  int mat_len;
94 
95  bool use_hide;
98 
100  float obmat[4][4];
101 
107 
108  /* For deformed edit-mesh data. */
109  /* Use for #ME_WRAPPER_TYPE_BMESH. */
110  const float (*bm_vert_coords)[3];
111  const float (*bm_vert_normals)[3];
112  const float (*bm_poly_normals)[3];
113  const float (*bm_poly_centers)[3];
114 
122  const MVert *mvert;
123  const MEdge *medge;
124  const MLoop *mloop;
125  const MPoly *mpoly;
130  /* Data created on-demand (usually not for #BMesh based data). */
134  int *lverts, *ledges;
136 
138  const eMRIterType iter_type,
139  const eMRDataType UNUSED(data_flag))
140 {
141  if (mr->extract_type != MR_EXTRACT_BMESH) {
142  /* Mesh */
143  if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
144  mr->vert_loose_len = 0;
145  mr->edge_loose_len = 0;
146 
147  BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
148 
149  mr->ledges = MEM_mallocN(mr->edge_len * sizeof(int), __func__);
150  const MEdge *med = mr->medge;
151  for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) {
152  if (med->flag & ME_LOOSEEDGE) {
153  mr->ledges[mr->edge_loose_len++] = med_index;
154  }
155  /* Tag verts as not loose. */
156  BLI_BITMAP_ENABLE(lvert_map, med->v1);
157  BLI_BITMAP_ENABLE(lvert_map, med->v2);
158  }
159  if (mr->edge_loose_len < mr->edge_len) {
160  mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges));
161  }
162 
163  mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
164  for (int v = 0; v < mr->vert_len; v++) {
165  if (!BLI_BITMAP_TEST(lvert_map, v)) {
166  mr->lverts[mr->vert_loose_len++] = v;
167  }
168  }
169  if (mr->vert_loose_len < mr->vert_len) {
170  mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts));
171  }
172 
173  MEM_freeN(lvert_map);
174 
175  mr->loop_loose_len = mr->vert_loose_len + (mr->edge_loose_len * 2);
176  }
177  }
178  else {
179  /* #BMesh */
180  BMesh *bm = mr->bm;
181  if (iter_type & (MR_ITER_LEDGE | MR_ITER_LVERT)) {
182  int elem_id;
183  BMIter iter;
184  BMVert *eve;
185  BMEdge *ede;
186  mr->vert_loose_len = 0;
187  mr->edge_loose_len = 0;
188 
189  mr->lverts = MEM_mallocN(mr->vert_len * sizeof(*mr->lverts), __func__);
190  BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
191  if (eve->e == NULL) {
192  mr->lverts[mr->vert_loose_len++] = elem_id;
193  }
194  }
195  if (mr->vert_loose_len < mr->vert_len) {
196  mr->lverts = MEM_reallocN(mr->lverts, mr->vert_loose_len * sizeof(*mr->lverts));
197  }
198 
199  mr->ledges = MEM_mallocN(mr->edge_len * sizeof(*mr->ledges), __func__);
200  BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
201  if (ede->l == NULL) {
202  mr->ledges[mr->edge_loose_len++] = elem_id;
203  }
204  }
205  if (mr->edge_loose_len < mr->edge_len) {
206  mr->ledges = MEM_reallocN(mr->ledges, mr->edge_loose_len * sizeof(*mr->ledges));
207  }
208 
209  mr->loop_loose_len = mr->vert_loose_len + mr->edge_loose_len * 2;
210  }
211  }
212 }
213 
218  const eMRIterType iter_type,
219  const eMRDataType data_flag)
220 {
221  Mesh *me = mr->me;
222  if (mr->extract_type != MR_EXTRACT_BMESH) {
223  /* Mesh */
224  if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
225  mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI");
227  me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, mr->mlooptri);
228  }
229  }
230  else {
231  /* #BMesh */
232  if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
233  /* Edit mode ensures this is valid, no need to calculate. */
234  BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL));
235  }
236  }
237 }
238 
240  const eMRIterType UNUSED(iter_type),
241  const eMRDataType data_flag)
242 {
243  Mesh *me = mr->me;
244  const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
245  const float split_angle = is_auto_smooth ? me->smoothresh : (float)M_PI;
246 
247  if (mr->extract_type != MR_EXTRACT_BMESH) {
248  /* Mesh */
250  mr->poly_normals = MEM_mallocN(sizeof(*mr->poly_normals) * mr->poly_len, __func__);
252  NULL,
253  mr->vert_len,
254  mr->mloop,
255  mr->mpoly,
256  mr->loop_len,
257  mr->poly_len,
258  mr->poly_normals,
259  true);
260  }
261  if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
262  mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
263  short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL);
265  mr->vert_len,
266  mr->me->medge,
267  mr->edge_len,
268  mr->me->mloop,
269  mr->loop_normals,
270  mr->loop_len,
271  mr->me->mpoly,
272  mr->poly_normals,
273  mr->poly_len,
274  is_auto_smooth,
275  split_angle,
276  NULL,
277  clnors,
278  NULL);
279  }
280  }
281  else {
282  /* #BMesh */
283  if (data_flag & MR_DATA_POLY_NOR) {
284  /* Use #BMFace.no instead. */
285  }
286  if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
287 
288  const float(*vert_coords)[3] = NULL;
289  const float(*vert_normals)[3] = NULL;
290  const float(*poly_normals)[3] = NULL;
291 
292  if (mr->edit_data && mr->edit_data->vertexCos) {
293  vert_coords = mr->bm_vert_coords;
294  vert_normals = mr->bm_vert_normals;
295  poly_normals = mr->bm_poly_normals;
296  }
297 
298  mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
299  const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL);
301  vert_coords,
302  vert_normals,
303  poly_normals,
304  is_auto_smooth,
305  split_angle,
306  mr->loop_normals,
307  NULL,
308  NULL,
309  clnors_offset,
310  false);
311  }
312  }
313 }
314 
320  const bool is_editmode,
321  const bool is_paint_mode,
322  const bool is_mode_active,
323  const float obmat[4][4],
324  const bool do_final,
325  const bool do_uvedit,
326  const DRW_MeshCDMask *UNUSED(cd_used),
327  const ToolSettings *ts,
328  const eMRIterType iter_type,
329  const eMRDataType data_flag)
330 {
331  MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
332  mr->toolsettings = ts;
334 
335  copy_m4_m4(mr->obmat, obmat);
336 
337  if (is_editmode) {
339  mr->bm = me->edit_mesh->bm;
340  mr->edit_bmesh = me->edit_mesh;
341  mr->me = (do_final) ? me->edit_mesh->mesh_eval_final : me->edit_mesh->mesh_eval_cage;
342  mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL;
343 
344  if (mr->edit_data) {
345  EditMeshData *emd = mr->edit_data;
346  if (emd->vertexCos) {
349  }
350 
353  mr->bm_poly_normals = mr->edit_data->polyNos;
354  mr->bm_poly_centers = mr->edit_data->polyCos;
355  }
356 
357  bool has_mdata = is_mode_active && (mr->me->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA);
358  bool use_mapped = is_mode_active &&
359  (has_mdata && !do_uvedit && mr->me && !mr->me->runtime.is_original);
360 
361  int bm_ensure_types = BM_VERT | BM_EDGE | BM_LOOP | BM_FACE;
362 
363  BM_mesh_elem_index_ensure(mr->bm, bm_ensure_types);
364  BM_mesh_elem_table_ensure(mr->bm, bm_ensure_types & ~BM_LOOP);
365 
366  mr->efa_act_uv = EDBM_uv_active_face_get(mr->edit_bmesh, false, false);
367  mr->efa_act = BM_mesh_active_face_get(mr->bm, false, true);
370 
373 #ifdef WITH_FREESTYLE
376 #endif
377 
378  if (use_mapped) {
379  mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
380  mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
381  mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
382 
383  use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
384  }
385 
386  mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_BMESH;
387 
388  /* Seems like the mesh_eval_final do not have the right origin indices.
389  * Force not mapped in this case. */
390  if (has_mdata && do_final && me->edit_mesh->mesh_eval_final != me->edit_mesh->mesh_eval_cage) {
391  // mr->edit_bmesh = NULL;
393  }
394  }
395  else {
396  mr->me = me;
397  mr->edit_bmesh = NULL;
398 
399  bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original;
400  if (use_mapped) {
401  mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
402  mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
403  mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
404 
405  use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
406  }
407 
408  mr->extract_type = use_mapped ? MR_EXTRACT_MAPPED : MR_EXTRACT_MESH;
409  }
410 
411  if (mr->extract_type != MR_EXTRACT_BMESH) {
412  /* Mesh */
413  mr->vert_len = mr->me->totvert;
414  mr->edge_len = mr->me->totedge;
415  mr->loop_len = mr->me->totloop;
416  mr->poly_len = mr->me->totpoly;
417  mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
418 
419  mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT);
420  mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE);
422  mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY);
423 
424  mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
425  mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
426  mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
427  }
428  else {
429  /* #BMesh */
430  BMesh *bm = mr->bm;
431 
432  mr->vert_len = bm->totvert;
433  mr->edge_len = bm->totedge;
434  mr->loop_len = bm->totloop;
435  mr->poly_len = bm->totface;
436  mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
437  }
438  mesh_render_data_update_loose_geom(mr, iter_type, data_flag);
439 
440  return mr;
441 }
442 
444 {
445  MEM_SAFE_FREE(mr->mlooptri);
448 
449  MEM_SAFE_FREE(mr->lverts);
450  MEM_SAFE_FREE(mr->ledges);
451 
452  MEM_freeN(mr);
453 }
454 
456 {
457  return ((mr->p_origindex != NULL) && (mr->p_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
458  BM_face_at_index(mr->bm, mr->p_origindex[idx]) :
459  NULL;
460 }
461 
463 {
464  return ((mr->e_origindex != NULL) && (mr->e_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
465  BM_edge_at_index(mr->bm, mr->e_origindex[idx]) :
466  NULL;
467 }
468 
470 {
471  return ((mr->v_origindex != NULL) && (mr->v_origindex[idx] != ORIGINDEX_NONE) && mr->bm) ?
472  BM_vert_at_index(mr->bm, mr->v_origindex[idx]) :
473  NULL;
474 }
475 
476 BLI_INLINE const float *bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve)
477 {
478  const float(*vert_coords)[3] = mr->bm_vert_coords;
479  if (vert_coords != NULL) {
480  return vert_coords[BM_elem_index_get(eve)];
481  }
482 
483  UNUSED_VARS(mr);
484  return eve->co;
485 }
486 
487 BLI_INLINE const float *bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve)
488 {
489  const float(*vert_normals)[3] = mr->bm_vert_normals;
490  if (vert_normals != NULL) {
491  return vert_normals[BM_elem_index_get(eve)];
492  }
493 
494  UNUSED_VARS(mr);
495  return eve->no;
496 }
497 
498 BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *efa)
499 {
500  const float(*poly_normals)[3] = mr->bm_poly_normals;
501  if (poly_normals != NULL) {
502  return poly_normals[BM_elem_index_get(efa)];
503  }
504 
505  UNUSED_VARS(mr);
506  return efa->no;
507 }
508 
511 /* ---------------------------------------------------------------------- */
515 typedef struct ExtractTriBMesh_Params {
516  BMLoop *(*looptris)[3];
517  int tri_range[2];
519 typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr,
521  void *data);
522 
523 #define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elem_tri, index_tri, params) \
524  CHECK_TYPE(params, const ExtractTriBMesh_Params *); \
525  { \
526  const int _tri_index_end = (params)->tri_range[1]; \
527  BMLoop **elem_tri = (params)->looptris[(params)->tri_range[0]]; \
528  for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
529  index_tri += 1, elem_tri += 3)
530 #define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END }
531 
532 typedef struct ExtractTriMesh_Params {
534  int tri_range[2];
536 typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
538  void *data);
539 
540 #define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(elem_tri, index_tri, params) \
541  CHECK_TYPE(params, const ExtractTriMesh_Params *); \
542  { \
543  const int _tri_index_end = (params)->tri_range[1]; \
544  const MLoopTri *elem_tri = &(params)->mlooptri[(params)->tri_range[0]]; \
545  for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
546  index_tri += 1, elem_tri += 1)
547 #define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END }
548 
551 /* ---------------------------------------------------------------------- */
555 typedef struct ExtractPolyBMesh_Params {
556  BMLoop *(*looptris)[3];
557  int poly_range[2];
559 typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
561  void *data);
562 
563 #define EXTRACT_POLY_FOREACH_BM_BEGIN(elem_poly, index_poly, params, mr) \
564  CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
565  { \
566  BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
567  BMFace **_ftable = mr->bm->ftable; \
568  const int _poly_index_end = (params)->poly_range[1]; \
569  for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
570  index_poly += 1) { \
571  BMFace *elem_poly = _ftable[index_poly]; \
572  (void)elem_poly;
573 
574 #define EXTRACT_POLY_FOREACH_BM_END \
575  } \
576  }
577 
578 /* Iterate over polygon and loop. */
579 #define EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(elem_loop, index_loop, params, mr) \
580  CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
581  { \
582  BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
583  BMFace **_ftable = mr->bm->ftable; \
584  const int _poly_index_end = (params)->poly_range[1]; \
585  for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
586  index_poly += 1) { \
587  BMFace *elem_face = _ftable[index_poly]; \
588  BMLoop *elem_loop, *l_first; \
589  elem_loop = l_first = BM_FACE_FIRST_LOOP(elem_face); \
590  do { \
591  const int index_loop = BM_elem_index_get(elem_loop); \
592  (void)index_loop; /* Quiet warning when unused. */
593 
594 #define EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(elem_loop) \
595  } \
596  while ((elem_loop = elem_loop->next) != l_first) \
597  ; \
598  } \
599  }
600 
601 typedef struct ExtractPolyMesh_Params {
602  int poly_range[2];
604 typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
606  void *data);
607 
608 #define EXTRACT_POLY_FOREACH_MESH_BEGIN(elem_poly, index_poly, params, mr) \
609  CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
610  { \
611  const MPoly *_mpoly = mr->mpoly; \
612  const int _poly_index_end = (params)->poly_range[1]; \
613  for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
614  index_poly += 1) { \
615  const MPoly *elem_poly = &_mpoly[index_poly]; \
616  (void)elem_poly;
617 
618 #define EXTRACT_POLY_FOREACH_MESH_END \
619  } \
620  }
621 
622 /* Iterate over polygon and loop. */
623 #define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN( \
624  elem_poly, index_poly, elem_loop, index_loop, params, mr) \
625  CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
626  { \
627  const MPoly *_mpoly = mr->mpoly; \
628  const MLoop *_mloop = mr->mloop; \
629  const int _poly_index_end = (params)->poly_range[1]; \
630  for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
631  index_poly += 1) { \
632  const MPoly *elem_poly = &_mpoly[index_poly]; \
633  const int _index_end = elem_poly->loopstart + elem_poly->totloop; \
634  for (int index_loop = elem_poly->loopstart; index_loop < _index_end; index_loop += 1) { \
635  const MLoop *elem_loop = &_mloop[index_loop]; \
636  (void)elem_loop;
637 
638 #define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END \
639  } \
640  } \
641  }
642 
645 /* ---------------------------------------------------------------------- */
649 typedef struct ExtractLEdgeBMesh_Params {
650  const int *ledge;
651  int ledge_range[2];
653 typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
655  void *data);
656 
657 #define EXTRACT_LEDGE_FOREACH_BM_BEGIN(elem_edge, index_ledge, params) \
658  CHECK_TYPE(params, const ExtractLEdgeBMesh_Params *); \
659  { \
660  BLI_assert((mr->bm->elem_table_dirty & BM_EDGE) == 0); \
661  BMEdge **_etable = mr->bm->etable; \
662  const int *_ledge = (params)->ledge; \
663  const int _ledge_index_end = (params)->ledge_range[1]; \
664  for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
665  index_ledge += 1) { \
666  BMEdge *elem_edge = _etable[_ledge[index_ledge]]; \
667  (void)elem_edge; /* Quiet warning when unused. */ \
668  {
669 #define EXTRACT_LEDGE_FOREACH_BM_END \
670  } \
671  } \
672  }
673 
674 typedef struct ExtractLEdgeMesh_Params {
675  const int *ledge;
676  int ledge_range[2];
678 typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
680  void *data);
681 
682 #define EXTRACT_LEDGE_FOREACH_MESH_BEGIN(elem_edge, index_ledge, params, mr) \
683  CHECK_TYPE(params, const ExtractLEdgeMesh_Params *); \
684  { \
685  const MEdge *_medge = mr->medge; \
686  const int *_ledge = (params)->ledge; \
687  const int _ledge_index_end = (params)->ledge_range[1]; \
688  for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
689  index_ledge += 1) { \
690  const MEdge *elem_edge = &_medge[_ledge[index_ledge]]; \
691  (void)elem_edge; /* Quiet warning when unused. */ \
692  {
693 #define EXTRACT_LEDGE_FOREACH_MESH_END \
694  } \
695  } \
696  }
697 
700 /* ---------------------------------------------------------------------- */
704 typedef struct ExtractLVertBMesh_Params {
705  const int *lvert;
706  int lvert_range[2];
708 typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
710  void *data);
711 
712 #define EXTRACT_LVERT_FOREACH_BM_BEGIN(elem_vert, index_lvert, params) \
713  CHECK_TYPE(params, const ExtractLVertBMesh_Params *); \
714  { \
715  BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
716  BMVert **vtable = mr->bm->vtable; \
717  const int *lverts = (params)->lvert; \
718  const int _lvert_index_end = (params)->lvert_range[1]; \
719  for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
720  index_lvert += 1) { \
721  BMVert *elem_vert = vtable[lverts[index_lvert]]; \
722  (void)elem_vert; /* Quiet warning when unused. */ \
723  {
724 #define EXTRACT_LVERT_FOREACH_BM_END \
725  } \
726  } \
727  }
728 
729 typedef struct ExtractLVertMesh_Params {
730  const int *lvert;
731  int lvert_range[2];
733 typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
735  void *data);
736 
737 #define EXTRACT_LVERT_FOREACH_MESH_BEGIN(elem, index_lvert, params, mr) \
738  CHECK_TYPE(params, const ExtractLVertMesh_Params *); \
739  { \
740  const MVert *mvert = mr->mvert; \
741  const int *lverts = (params)->lvert; \
742  const int _lvert_index_end = (params)->lvert_range[1]; \
743  for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
744  index_lvert += 1) { \
745  const MVert *elem = &mvert[lverts[index_lvert]]; \
746  (void)elem; /* Quiet warning when unused. */ \
747  {
748 #define EXTRACT_LVERT_FOREACH_MESH_END \
749  } \
750  } \
751  }
752 
755 /* ---------------------------------------------------------------------- */
759 typedef void *(ExtractInitFn)(const MeshRenderData *mr,
760  struct MeshBatchCache *cache,
761  void *buffer);
762 typedef void(ExtractFinishFn)(const MeshRenderData *mr,
763  struct MeshBatchCache *cache,
764  void *buffer,
765  void *data);
766 
767 typedef struct MeshExtract {
784  const bool use_threading;
786 
788 {
789  eMRIterType type = 0;
790  SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI);
791  SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY);
792  SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE);
793  SET_FLAG_FROM_TEST(type, (ext->iter_lvert_bm || ext->iter_lvert_mesh), MR_ITER_LVERT);
794  return type;
795 }
796 
799 /* ---------------------------------------------------------------------- */
803 typedef struct MeshExtract_Tri_Data {
808 
809 static void *extract_tris_init(const MeshRenderData *mr,
810  struct MeshBatchCache *UNUSED(cache),
811  void *UNUSED(ibo))
812 {
813  MeshExtract_Tri_Data *data = MEM_callocN(sizeof(*data), __func__);
814 
815  size_t mat_tri_idx_size = sizeof(int) * mr->mat_len;
816  data->tri_mat_start = MEM_callocN(mat_tri_idx_size, __func__);
817  data->tri_mat_end = MEM_callocN(mat_tri_idx_size, __func__);
818 
819  int *mat_tri_len = data->tri_mat_start;
820  /* Count how many triangle for each material. */
821  if (mr->extract_type == MR_EXTRACT_BMESH) {
822  BMIter iter;
823  BMFace *efa;
824  BM_ITER_MESH (efa, &iter, mr->bm, BM_FACES_OF_MESH) {
825  if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
826  int mat = min_ii(efa->mat_nr, mr->mat_len - 1);
827  mat_tri_len[mat] += efa->len - 2;
828  }
829  }
830  }
831  else {
832  const MPoly *mp = mr->mpoly;
833  for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
834  if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
835  int mat = min_ii(mp->mat_nr, mr->mat_len - 1);
836  mat_tri_len[mat] += mp->totloop - 2;
837  }
838  }
839  }
840  /* Accumulate triangle lengths per material to have correct offsets. */
841  int ofs = mat_tri_len[0];
842  mat_tri_len[0] = 0;
843  for (int i = 1; i < mr->mat_len; i++) {
844  int tmp = mat_tri_len[i];
845  mat_tri_len[i] = ofs;
846  ofs += tmp;
847  }
848 
849  memcpy(data->tri_mat_end, mat_tri_len, mat_tri_idx_size);
850 
851  int visible_tri_tot = ofs;
852  GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, visible_tri_tot, mr->loop_len);
853 
854  return data;
855 }
856 
858  const struct ExtractTriBMesh_Params *params,
859  void *_data)
860 {
861  MeshExtract_Tri_Data *data = _data;
862  const int mat_last = mr->mat_len - 1;
864  {
865  if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
866  int *mat_tri_ofs = data->tri_mat_end;
867  const int mat = min_ii(elt[0]->f->mat_nr, mat_last);
869  mat_tri_ofs[mat]++,
870  BM_elem_index_get(elt[0]),
871  BM_elem_index_get(elt[1]),
872  BM_elem_index_get(elt[2]));
873  }
874  }
876 }
877 
879  const struct ExtractTriMesh_Params *params,
880  void *_data)
881 {
882  MeshExtract_Tri_Data *data = _data;
883  const int mat_last = mr->mat_len - 1;
885  {
886  const MPoly *mp = &mr->mpoly[mlt->poly];
887  if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
888  int *mat_tri_ofs = data->tri_mat_end;
889  const int mat = min_ii(mp->mat_nr, mat_last);
891  &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]);
892  }
893  }
895 }
896 
897 static void extract_tris_finish(const MeshRenderData *mr,
898  struct MeshBatchCache *cache,
899  void *ibo,
900  void *_data)
901 {
902  MeshExtract_Tri_Data *data = _data;
903  GPU_indexbuf_build_in_place(&data->elb, ibo);
904 
905  /* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch
906  * is created before the surfaces-per-material. */
907  if (mr->use_final_mesh && cache->final.tris_per_mat) {
908  MeshBufferCache *mbc = &cache->final;
909  for (int i = 0; i < mr->mat_len; i++) {
910  /* These IBOs have not been queried yet but we create them just in case they are needed
911  * later since they are not tracked by mesh_buffer_cache_create_requested(). */
912  if (mbc->tris_per_mat[i] == NULL) {
913  mbc->tris_per_mat[i] = GPU_indexbuf_calloc();
914  }
915  /* Multiply by 3 because these are triangle indices. */
916  const int mat_start = data->tri_mat_start[i];
917  const int mat_end = data->tri_mat_end[i];
918  const int start = mat_start * 3;
919  const int len = (mat_end - mat_start) * 3;
921  }
922  }
923  MEM_freeN(data->tri_mat_start);
924  MEM_freeN(data->tri_mat_end);
925  MEM_freeN(data);
926 }
927 
928 static const MeshExtract extract_tris = {
930  .iter_looptri_bm = extract_tris_iter_looptri_bm,
931  .iter_looptri_mesh = extract_tris_iter_looptri_mesh,
932  .finish = extract_tris_finish,
933  .data_flag = 0,
934  .use_threading = false,
935 };
936 
939 /* ---------------------------------------------------------------------- */
943 static void *extract_lines_init(const MeshRenderData *mr,
944  struct MeshBatchCache *UNUSED(cache),
945  void *UNUSED(buf))
946 {
947  GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
948  /* Put loose edges at the end. */
950  elb, GPU_PRIM_LINES, mr->edge_len + mr->edge_loose_len, mr->loop_len + mr->loop_loose_len);
951  return elb;
952 }
953 
956  void *elb)
957 {
958  /* Using poly & loop iterator would complicate accessing the adjacent loop. */
959  EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
960  {
961  BMLoop *l_iter, *l_first;
962  /* Use #BMLoop.prev to match mesh order (to avoid minor differences in data extraction). */
963  l_iter = l_first = BM_FACE_FIRST_LOOP(f)->prev;
964  do {
965  if (!BM_elem_flag_test(l_iter->e, BM_ELEM_HIDDEN)) {
967  BM_elem_index_get(l_iter->e),
968  BM_elem_index_get(l_iter),
969  BM_elem_index_get(l_iter->next));
970  }
971  else {
973  }
974  } while ((l_iter = l_iter->next) != l_first);
975  }
977 }
978 
981  void *elb)
982 {
983  /* Using poly & loop iterator would complicate accessing the adjacent loop. */
984  const MLoop *mloop = mr->mloop;
985  const MEdge *medge = mr->medge;
986  if (mr->use_hide || (mr->extract_type == MR_EXTRACT_MAPPED) || (mr->e_origindex != NULL)) {
987  EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
988  {
989  const int ml_index_last = mp->loopstart + (mp->totloop - 1);
990  int ml_index = ml_index_last, ml_index_next = mp->loopstart;
991  do {
992  const MLoop *ml = &mloop[ml_index];
993  const MEdge *med = &medge[ml->e];
994  if (!((mr->use_hide && (med->flag & ME_HIDE)) ||
995  ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
996  (mr->e_origindex[ml->e] == ORIGINDEX_NONE)))) {
997  GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next);
998  }
999  else {
1000  GPU_indexbuf_set_line_restart(elb, ml->e);
1001  }
1002  } while ((ml_index = ml_index_next++) != ml_index_last);
1003  }
1005  }
1006  else {
1007  EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
1008  {
1009  const int ml_index_last = mp->loopstart + (mp->totloop - 1);
1010  int ml_index = ml_index_last, ml_index_next = mp->loopstart;
1011  do {
1012  const MLoop *ml = &mloop[ml_index];
1013  GPU_indexbuf_set_line_verts(elb, ml->e, ml_index, ml_index_next);
1014  } while ((ml_index = ml_index_next++) != ml_index_last);
1015  }
1017  }
1018 }
1019 
1022  void *elb)
1023 {
1024  EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
1025  {
1026  const int l_index_offset = mr->edge_len + ledge_index;
1027  if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
1028  const int l_index = mr->loop_len + ledge_index * 2;
1029  GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1);
1030  }
1031  else {
1032  GPU_indexbuf_set_line_restart(elb, l_index_offset);
1033  }
1034  /* Don't render the edge twice. */
1036  }
1038 }
1039 
1042  void *elb)
1043 {
1044  EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
1045  {
1046  const int l_index_offset = mr->edge_len + ledge_index;
1047  const int e_index = mr->ledges[ledge_index];
1048  if (!((mr->use_hide && (med->flag & ME_HIDE)) ||
1049  ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
1050  (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) {
1051  const int l_index = mr->loop_len + ledge_index * 2;
1052  GPU_indexbuf_set_line_verts(elb, l_index_offset, l_index, l_index + 1);
1053  }
1054  else {
1055  GPU_indexbuf_set_line_restart(elb, l_index_offset);
1056  }
1057  /* Don't render the edge twice. */
1058  GPU_indexbuf_set_line_restart(elb, e_index);
1059  }
1061 }
1062 
1064  struct MeshBatchCache *UNUSED(cache),
1065  void *ibo,
1066  void *elb)
1067 {
1068  GPU_indexbuf_build_in_place(elb, ibo);
1069  MEM_freeN(elb);
1070 }
1071 
1072 static const MeshExtract extract_lines = {
1074  .iter_poly_bm = extract_lines_iter_poly_bm,
1075  .iter_poly_mesh = extract_lines_iter_poly_mesh,
1076  .iter_ledge_bm = extract_lines_iter_ledge_bm,
1077  .iter_ledge_mesh = extract_lines_iter_ledge_mesh,
1078  .finish = extract_lines_finish,
1079  .data_flag = 0,
1080  .use_threading = false,
1081 };
1084 /* ---------------------------------------------------------------------- */
1088 static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshBatchCache *cache)
1089 {
1090  BLI_assert(cache->final.ibo.lines);
1091  /* Multiply by 2 because these are edges indices. */
1092  const int start = mr->edge_len * 2;
1093  const int len = mr->edge_loose_len * 2;
1095  cache->final.ibo.lines_loose, cache->final.ibo.lines, start, len);
1096  cache->no_loose_wire = (len == 0);
1097 }
1098 
1100  struct MeshBatchCache *cache,
1101  void *ibo,
1102  void *elb)
1103 {
1104  GPU_indexbuf_build_in_place(elb, ibo);
1105  extract_lines_loose_subbuffer(mr, cache);
1106  MEM_freeN(elb);
1107 }
1108 
1111  .iter_poly_bm = extract_lines_iter_poly_bm,
1112  .iter_poly_mesh = extract_lines_iter_poly_mesh,
1113  .iter_ledge_bm = extract_lines_iter_ledge_bm,
1114  .iter_ledge_mesh = extract_lines_iter_ledge_mesh,
1116  .data_flag = 0,
1117  .use_threading = false,
1118 };
1119 
1122 /* ---------------------------------------------------------------------- */
1126 static void *extract_points_init(const MeshRenderData *mr,
1127  struct MeshBatchCache *UNUSED(cache),
1128  void *UNUSED(buf))
1129 {
1130  GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
1132  return elb;
1133 }
1134 
1135 BLI_INLINE void vert_set_bm(GPUIndexBufBuilder *elb, BMVert *eve, int l_index)
1136 {
1137  const int v_index = BM_elem_index_get(eve);
1138  if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
1139  GPU_indexbuf_set_point_vert(elb, v_index, l_index);
1140  }
1141  else {
1142  GPU_indexbuf_set_point_restart(elb, v_index);
1143  }
1144 }
1145 
1147  const MeshRenderData *mr,
1148  const int v_index,
1149  const int l_index)
1150 {
1151  const MVert *mv = &mr->mvert[v_index];
1152  if (!((mr->use_hide && (mv->flag & ME_HIDE)) ||
1153  ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) &&
1154  (mr->v_origindex[v_index] == ORIGINDEX_NONE)))) {
1155  GPU_indexbuf_set_point_vert(elb, v_index, l_index);
1156  }
1157  else {
1158  GPU_indexbuf_set_point_restart(elb, v_index);
1159  }
1160 }
1161 
1164  void *elb)
1165 {
1167  {
1168  vert_set_bm(elb, l->v, l_index);
1169  }
1171 }
1172 
1175  void *elb)
1176 {
1177  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1178  {
1179  vert_set_mesh(elb, mr, ml->v, ml_index);
1180  }
1182 }
1183 
1186  void *elb)
1187 {
1188  EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
1189  {
1190  vert_set_bm(elb, eed->v1, mr->loop_len + (ledge_index * 2));
1191  vert_set_bm(elb, eed->v2, mr->loop_len + (ledge_index * 2) + 1);
1192  }
1194 }
1195 
1198  void *elb)
1199 {
1200  EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
1201  {
1202  vert_set_mesh(elb, mr, med->v1, mr->loop_len + (ledge_index * 2));
1203  vert_set_mesh(elb, mr, med->v2, mr->loop_len + (ledge_index * 2) + 1);
1204  }
1206 }
1207 
1210  void *elb)
1211 {
1212  const int offset = mr->loop_len + (mr->edge_loose_len * 2);
1213  EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
1214  {
1215  vert_set_bm(elb, eve, offset + lvert_index);
1216  }
1218 }
1219 
1222  void *elb)
1223 {
1224  const int offset = mr->loop_len + (mr->edge_loose_len * 2);
1225  EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
1226  {
1227  vert_set_mesh(elb, mr, mr->lverts[lvert_index], offset + lvert_index);
1228  }
1230 }
1231 
1233  struct MeshBatchCache *UNUSED(cache),
1234  void *ibo,
1235  void *elb)
1236 {
1237  GPU_indexbuf_build_in_place(elb, ibo);
1238  MEM_freeN(elb);
1239 }
1240 
1241 static const MeshExtract extract_points = {
1243  .iter_poly_bm = extract_points_iter_poly_bm,
1244  .iter_poly_mesh = extract_points_iter_poly_mesh,
1245  .iter_ledge_bm = extract_points_iter_ledge_bm,
1246  .iter_ledge_mesh = extract_points_iter_ledge_mesh,
1247  .iter_lvert_bm = extract_points_iter_lvert_bm,
1248  .iter_lvert_mesh = extract_points_iter_lvert_mesh,
1249  .finish = extract_points_finish,
1250  .data_flag = 0,
1251  .use_threading = false,
1252 };
1253 
1256 /* ---------------------------------------------------------------------- */
1260 static void *extract_fdots_init(const MeshRenderData *mr,
1261  struct MeshBatchCache *UNUSED(cache),
1262  void *UNUSED(buf))
1263 {
1264  GPUIndexBufBuilder *elb = MEM_mallocN(sizeof(*elb), __func__);
1266  return elb;
1267 }
1268 
1271  void *elb)
1272 {
1273  EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
1274  {
1275  if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
1276  GPU_indexbuf_set_point_vert(elb, f_index, f_index);
1277  }
1278  else {
1279  GPU_indexbuf_set_point_restart(elb, f_index);
1280  }
1281  }
1283 }
1284 
1287  void *elb)
1288 {
1289  if (mr->use_subsurf_fdots) {
1290  /* Check #ME_VERT_FACEDOT. */
1291  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1292  {
1293  const MVert *mv = &mr->mvert[ml->v];
1294  if ((mv->flag & ME_VERT_FACEDOT) && !(mr->use_hide && (mp->flag & ME_HIDE))) {
1295  GPU_indexbuf_set_point_vert(elb, mp_index, mp_index);
1296  }
1297  else {
1298  GPU_indexbuf_set_point_restart(elb, mp_index);
1299  }
1300  }
1302  }
1303  else {
1304  EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
1305  {
1306  if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
1307  GPU_indexbuf_set_point_vert(elb, mp_index, mp_index);
1308  }
1309  else {
1310  GPU_indexbuf_set_point_restart(elb, mp_index);
1311  }
1312  }
1314  }
1315 }
1316 
1318  struct MeshBatchCache *UNUSED(cache),
1319  void *ibo,
1320  void *elb)
1321 {
1322  GPU_indexbuf_build_in_place(elb, ibo);
1323  MEM_freeN(elb);
1324 }
1325 
1326 static const MeshExtract extract_fdots = {
1328  .iter_poly_bm = extract_fdots_iter_poly_bm,
1329  .iter_poly_mesh = extract_fdots_iter_poly_mesh,
1330  .finish = extract_fdots_finish,
1331  .data_flag = 0,
1332  .use_threading = false,
1333 };
1334 
1337 /* ---------------------------------------------------------------------- */
1346 
1348  struct MeshBatchCache *UNUSED(cache),
1349  void *UNUSED(buf))
1350 {
1351  size_t bitmap_size = BLI_BITMAP_SIZE(mr->edge_len);
1352  MeshExtract_LinePaintMask_Data *data = MEM_callocN(sizeof(*data) + bitmap_size, __func__);
1354  return data;
1355 }
1356 
1359  void *_data)
1360 {
1362  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1363  {
1364  const int e_index = ml->e;
1365  const MEdge *me = &mr->medge[e_index];
1366  if (!((mr->use_hide && (me->flag & ME_HIDE)) ||
1367  ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
1368  (mr->e_origindex[e_index] == ORIGINDEX_NONE)))) {
1369 
1370  const int ml_index_last = mp->totloop + mp->loopstart - 1;
1371  const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1);
1372  if (mp->flag & ME_FACE_SEL) {
1373  if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, e_index)) {
1374  /* Hide edge as it has more than 2 selected loop. */
1375  GPU_indexbuf_set_line_restart(&data->elb, e_index);
1376  }
1377  else {
1378  /* First selected loop. Set edge visible, overwriting any unselected loop. */
1379  GPU_indexbuf_set_line_verts(&data->elb, e_index, ml_index, ml_index_other);
1380  }
1381  }
1382  else {
1383  /* Set these unselected loop only if this edge has no other selected loop. */
1384  if (!BLI_BITMAP_TEST(data->select_map, e_index)) {
1385  GPU_indexbuf_set_line_verts(&data->elb, e_index, ml_index, ml_index_other);
1386  }
1387  }
1388  }
1389  else {
1390  GPU_indexbuf_set_line_restart(&data->elb, e_index);
1391  }
1392  }
1394 }
1396  struct MeshBatchCache *UNUSED(cache),
1397  void *ibo,
1398  void *_data)
1399 {
1401 
1402  GPU_indexbuf_build_in_place(&data->elb, ibo);
1403  MEM_freeN(data);
1404 }
1405 
1408  .iter_poly_mesh = extract_lines_paint_mask_iter_poly_mesh,
1410  .data_flag = 0,
1411  .use_threading = false,
1412 };
1413 
1416 /* ---------------------------------------------------------------------- */
1420 #define NO_EDGE INT_MAX
1421 
1426  /* Array to convert vert index to any loop index of this vert. */
1429 
1431  struct MeshBatchCache *UNUSED(cache),
1432  void *UNUSED(buf))
1433 {
1434  /* Similar to poly_to_tri_count().
1435  * There is always (loop + triangle - 1) edges inside a polygon.
1436  * Accumulate for all polys and you get : */
1437  uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len;
1438 
1439  size_t vert_to_loop_size = sizeof(uint) * mr->vert_len;
1440 
1441  MeshExtract_LineAdjacency_Data *data = MEM_callocN(sizeof(*data) + vert_to_loop_size, __func__);
1442  GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, mr->loop_len);
1443  data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
1444  data->is_manifold = true;
1445  return data;
1446 }
1447 
1450 {
1451  GPUIndexBufBuilder *elb = &data->elb;
1452  /* Iterate around the triangle's edges. */
1453  for (int e = 0; e < 3; e++) {
1454  SHIFT3(uint, v3, v2, v1);
1455  SHIFT3(uint, l3, l2, l1);
1456 
1457  bool inv_indices = (v2 > v3);
1458  void **pval;
1459  bool value_is_init = BLI_edgehash_ensure_p(data->eh, v2, v3, &pval);
1460  int v_data = POINTER_AS_INT(*pval);
1461  if (!value_is_init || v_data == NO_EDGE) {
1462  /* Save the winding order inside the sign bit. Because the
1463  * Edge-hash sort the keys and we need to compare winding later. */
1464  int value = (int)l1 + 1; /* 0 cannot be signed so add one. */
1465  *pval = POINTER_FROM_INT((inv_indices) ? -value : value);
1466  /* Store loop indices for remaining non-manifold edges. */
1467  data->vert_to_loop[v2] = l2;
1468  data->vert_to_loop[v3] = l3;
1469  }
1470  else {
1471  /* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
1472  *pval = POINTER_FROM_INT(NO_EDGE);
1473  bool inv_opposite = (v_data < 0);
1474  uint l_opposite = (uint)abs(v_data) - 1;
1475  /* TODO Make this part thread-safe. */
1476  if (inv_opposite == inv_indices) {
1477  /* Don't share edge if triangles have non matching winding. */
1478  GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l1);
1479  GPU_indexbuf_add_line_adj_verts(elb, l_opposite, l2, l3, l_opposite);
1480  data->is_manifold = false;
1481  }
1482  else {
1483  GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l_opposite);
1484  }
1485  }
1486  }
1487 }
1488 
1490  const struct ExtractTriBMesh_Params *params,
1491  void *data)
1492 {
1494  {
1495  if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
1497  BM_elem_index_get(elt[1]->v),
1498  BM_elem_index_get(elt[2]->v),
1499  BM_elem_index_get(elt[0]),
1500  BM_elem_index_get(elt[1]),
1501  BM_elem_index_get(elt[2]),
1502  data);
1503  }
1504  }
1506 }
1507 
1509  const struct ExtractTriMesh_Params *params,
1510  void *data)
1511 {
1513  {
1514  const MPoly *mp = &mr->mpoly[mlt->poly];
1515  if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
1516  lines_adjacency_triangle(mr->mloop[mlt->tri[0]].v,
1517  mr->mloop[mlt->tri[1]].v,
1518  mr->mloop[mlt->tri[2]].v,
1519  mlt->tri[0],
1520  mlt->tri[1],
1521  mlt->tri[2],
1522  data);
1523  }
1524  }
1526 }
1527 
1529  struct MeshBatchCache *cache,
1530  void *ibo,
1531  void *_data)
1532 {
1534  /* Create edges for remaining non manifold edges. */
1537  uint v2, v3, l1, l2, l3;
1538  int v_data = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
1539  if (v_data != NO_EDGE) {
1540  BLI_edgehashIterator_getKey(ehi, &v2, &v3);
1541  l1 = (uint)abs(v_data) - 1;
1542  if (v_data < 0) { /* inv_opposite */
1543  SWAP(uint, v2, v3);
1544  }
1545  l2 = data->vert_to_loop[v2];
1546  l3 = data->vert_to_loop[v3];
1547  GPU_indexbuf_add_line_adj_verts(&data->elb, l1, l2, l3, l1);
1548  data->is_manifold = false;
1549  }
1550  }
1552  BLI_edgehash_free(data->eh, NULL);
1553 
1554  cache->is_manifold = data->is_manifold;
1555 
1556  GPU_indexbuf_build_in_place(&data->elb, ibo);
1557  MEM_freeN(data);
1558 }
1559 
1560 #undef NO_EDGE
1561 
1564  .iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm,
1565  .iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh,
1567  .data_flag = 0,
1568  .use_threading = false,
1569 };
1570 
1573 /* ---------------------------------------------------------------------- */
1581 
1583  struct MeshBatchCache *UNUSED(cache),
1584  void *UNUSED(ibo))
1585 {
1586  MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
1588  data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
1589  return data;
1590 }
1591 
1593  MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, int v1, int v2, int v3)
1594 {
1595  if (!hidden && (data->sync_selection || selected)) {
1596  GPU_indexbuf_add_tri_verts(&data->elb, v1, v2, v3);
1597  }
1598 }
1599 
1601  const struct ExtractTriBMesh_Params *params,
1602  void *data)
1603 {
1605  {
1607  BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN),
1608  BM_elem_flag_test(elt[0]->f, BM_ELEM_SELECT),
1609  BM_elem_index_get(elt[0]),
1610  BM_elem_index_get(elt[1]),
1611  BM_elem_index_get(elt[2]));
1612  }
1614 }
1615 
1617  const struct ExtractTriMesh_Params *params,
1618  void *data)
1619 {
1621  {
1622  const MPoly *mp = &mr->mpoly[mlt->poly];
1624  (mp->flag & ME_HIDE) != 0,
1625  (mp->flag & ME_FACE_SEL) != 0,
1626  mlt->tri[0],
1627  mlt->tri[1],
1628  mlt->tri[2]);
1629  }
1631 }
1632 
1634  struct MeshBatchCache *UNUSED(cache),
1635  void *ibo,
1636  void *data)
1637 {
1638  MeshExtract_EditUvElem_Data *extract_data = data;
1639  GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
1640  MEM_freeN(extract_data);
1641 }
1642 
1645  .iter_looptri_bm = extract_edituv_tris_iter_looptri_bm,
1646  .iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh,
1647  .finish = extract_edituv_tris_finish,
1648  .data_flag = 0,
1649  .use_threading = false,
1650 };
1651 
1654 /* ---------------------------------------------------------------------- */
1659  struct MeshBatchCache *UNUSED(cache),
1660  void *UNUSED(ibo))
1661 {
1662  MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
1664 
1665  data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
1666  return data;
1667 }
1668 
1670  MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, int v1, int v2)
1671 {
1672  if (!hidden && (data->sync_selection || selected)) {
1674  }
1675 }
1676 
1679  void *data)
1680 {
1682  {
1686  l_index,
1687  BM_elem_index_get(loop->next));
1688  }
1690 }
1691 
1694  void *data)
1695 {
1696  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1697  {
1698  const int ml_index_last = mp->totloop + mp->loopstart - 1;
1699  const int ml_index_next = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1);
1700  const bool real_edge = (mr->e_origindex == NULL || mr->e_origindex[ml->e] != ORIGINDEX_NONE);
1702  (mp->flag & ME_HIDE) != 0 || !real_edge,
1703  (mp->flag & ME_FACE_SEL) != 0,
1704  ml_index,
1705  ml_index_next);
1706  }
1708 }
1709 
1711  struct MeshBatchCache *UNUSED(cache),
1712  void *ibo,
1713  void *data)
1714 {
1715  MeshExtract_EditUvElem_Data *extract_data = data;
1716  GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
1717  MEM_freeN(extract_data);
1718 }
1719 
1722  .iter_poly_bm = extract_edituv_lines_iter_poly_bm,
1723  .iter_poly_mesh = extract_edituv_lines_iter_poly_mesh,
1724  .finish = extract_edituv_lines_finish,
1725  .data_flag = 0,
1726  .use_threading = false,
1727 };
1728 
1731 /* ---------------------------------------------------------------------- */
1736  struct MeshBatchCache *UNUSED(cache),
1737  void *UNUSED(ibo))
1738 {
1739  MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
1741 
1742  data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
1743  return data;
1744 }
1745 
1747  bool hidden,
1748  bool selected,
1749  int v1)
1750 {
1751  if (!hidden && (data->sync_selection || selected)) {
1753  }
1754 }
1755 
1758  void *data)
1759 {
1761  {
1765  l_index);
1766  }
1768 }
1769 
1772  void *data)
1773 {
1774  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1775  {
1776  const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
1777  mr->v_origindex[ml->v] != ORIGINDEX_NONE);
1779  data, ((mp->flag & ME_HIDE) != 0) || !real_vert, (mp->flag & ME_FACE_SEL) != 0, ml_index);
1780  }
1782 }
1783 
1785  struct MeshBatchCache *UNUSED(cache),
1786  void *ibo,
1787  void *data)
1788 {
1789  MeshExtract_EditUvElem_Data *extract_data = data;
1790  GPU_indexbuf_build_in_place(&extract_data->elb, ibo);
1791  MEM_freeN(extract_data);
1792 }
1793 
1796  .iter_poly_bm = extract_edituv_points_iter_poly_bm,
1797  .iter_poly_mesh = extract_edituv_points_iter_poly_mesh,
1798  .finish = extract_edituv_points_finish,
1799  .data_flag = 0,
1800  .use_threading = false,
1801 };
1802 
1805 /* ---------------------------------------------------------------------- */
1810  struct MeshBatchCache *UNUSED(cache),
1811  void *UNUSED(ibo))
1812 {
1813  MeshExtract_EditUvElem_Data *data = MEM_callocN(sizeof(*data), __func__);
1815 
1816  data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
1817  return data;
1818 }
1819 
1821  bool hidden,
1822  bool selected,
1823  int face_index)
1824 {
1825  if (!hidden && (data->sync_selection || selected)) {
1826  GPU_indexbuf_set_point_vert(&data->elb, face_index, face_index);
1827  }
1828  else {
1829  GPU_indexbuf_set_point_restart(&data->elb, face_index);
1830  }
1831 }
1832 
1835  void *data)
1836 {
1837  EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
1838  {
1841  }
1843 }
1844 
1847  void *data)
1848 {
1849  if (mr->use_subsurf_fdots) {
1850  /* Check #ME_VERT_FACEDOT. */
1851  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1852  {
1853  const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
1854  mr->p_origindex[mp_index] != ORIGINDEX_NONE);
1855  const bool subd_fdot = (!mr->use_subsurf_fdots ||
1856  (mr->mvert[ml->v].flag & ME_VERT_FACEDOT) != 0);
1858  ((mp->flag & ME_HIDE) != 0) || !real_fdot || !subd_fdot,
1859  (mp->flag & ME_FACE_SEL) != 0,
1860  mp_index);
1861  }
1863  }
1864  else {
1865  EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
1866  {
1867  const bool real_fdot = (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
1868  mr->p_origindex[mp_index] != ORIGINDEX_NONE);
1870  ((mp->flag & ME_HIDE) != 0) || !real_fdot,
1871  (mp->flag & ME_FACE_SEL) != 0,
1872  mp_index);
1873  }
1875  }
1876 }
1877 
1879  struct MeshBatchCache *UNUSED(cache),
1880  void *ibo,
1881  void *_data)
1882 {
1884  GPU_indexbuf_build_in_place(&data->elb, ibo);
1885  MEM_freeN(data);
1886 }
1887 
1890  .iter_poly_bm = extract_edituv_fdots_iter_poly_bm,
1891  .iter_poly_mesh = extract_edituv_fdots_iter_poly_mesh,
1892  .finish = extract_edituv_fdots_finish,
1893  .data_flag = 0,
1894  .use_threading = false,
1895 };
1896 
1899 /* ---------------------------------------------------------------------- */
1903 typedef struct PosNorLoop {
1904  float pos[3];
1907 
1908 typedef struct MeshExtract_PosNor_Data {
1912 
1913 static void *extract_pos_nor_init(const MeshRenderData *mr,
1914  struct MeshBatchCache *UNUSED(cache),
1915  void *buf)
1916 {
1917  static GPUVertFormat format = {0};
1918  if (format.attr_len == 0) {
1919  /* WARNING Adjust #PosNorLoop struct accordingly. */
1922  GPU_vertformat_alias_add(&format, "vnor");
1923  }
1924  GPUVertBuf *vbo = buf;
1927 
1928  /* Pack normals per vert, reduce amount of computation. */
1929  size_t packed_nor_len = sizeof(GPUNormal) * mr->vert_len;
1930  MeshExtract_PosNor_Data *data = MEM_mallocN(sizeof(*data) + packed_nor_len, __func__);
1931  data->vbo_data = (PosNorLoop *)GPU_vertbuf_get_data(vbo);
1932 
1933  /* Quicker than doing it for each loop. */
1934  if (mr->extract_type == MR_EXTRACT_BMESH) {
1935  BMIter iter;
1936  BMVert *eve;
1937  int v;
1938  BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) {
1939  data->normals[v].low = GPU_normal_convert_i10_v3(bm_vert_no_get(mr, eve));
1940  }
1941  }
1942  else {
1943  const MVert *mv = mr->mvert;
1944  for (int v = 0; v < mr->vert_len; v++, mv++) {
1945  data->normals[v].low = GPU_normal_convert_i10_s3(mv->no);
1946  }
1947  }
1948  return data;
1949 }
1950 
1953  void *_data)
1954 {
1955  MeshExtract_PosNor_Data *data = _data;
1957  {
1958  PosNorLoop *vert = &data->vbo_data[l_index];
1959  copy_v3_v3(vert->pos, bm_vert_co_get(mr, l->v));
1960  vert->nor = data->normals[BM_elem_index_get(l->v)].low;
1961  BMFace *efa = l->f;
1962  vert->nor.w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
1963  }
1965 }
1966 
1969  void *_data)
1970 {
1971  MeshExtract_PosNor_Data *data = _data;
1972  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
1973  {
1974  PosNorLoop *vert = &data->vbo_data[ml_index];
1975  const MVert *mv = &mr->mvert[ml->v];
1976  copy_v3_v3(vert->pos, mv->co);
1977  vert->nor = data->normals[ml->v].low;
1978  /* Flag for paint mode overlay. */
1979  if (mp->flag & ME_HIDE || mv->flag & ME_HIDE ||
1980  ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) &&
1981  (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) {
1982  vert->nor.w = -1;
1983  }
1984  else if (mv->flag & SELECT) {
1985  vert->nor.w = 1;
1986  }
1987  else {
1988  vert->nor.w = 0;
1989  }
1990  }
1992 }
1993 
1996  void *_data)
1997 {
1998  MeshExtract_PosNor_Data *data = _data;
1999  EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
2000  {
2001  int l_index = mr->loop_len + ledge_index * 2;
2002  PosNorLoop *vert = &data->vbo_data[l_index];
2003  copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
2004  copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
2005  vert[0].nor = data->normals[BM_elem_index_get(eed->v1)].low;
2006  vert[1].nor = data->normals[BM_elem_index_get(eed->v2)].low;
2007  }
2009 }
2010 
2013  void *_data)
2014 {
2015  MeshExtract_PosNor_Data *data = _data;
2016  EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
2017  {
2018  const int ml_index = mr->loop_len + ledge_index * 2;
2019  PosNorLoop *vert = &data->vbo_data[ml_index];
2020  copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co);
2021  copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co);
2022  vert[0].nor = data->normals[med->v1].low;
2023  vert[1].nor = data->normals[med->v2].low;
2024  }
2026 }
2027 
2030  void *_data)
2031 {
2032  MeshExtract_PosNor_Data *data = _data;
2033  const int offset = mr->loop_len + (mr->edge_loose_len * 2);
2034  EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
2035  {
2036  const int l_index = offset + lvert_index;
2037  PosNorLoop *vert = &data->vbo_data[l_index];
2038  copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
2039  vert->nor = data->normals[BM_elem_index_get(eve)].low;
2040  }
2042 }
2043 
2046  void *_data)
2047 {
2048  MeshExtract_PosNor_Data *data = _data;
2049  const int offset = mr->loop_len + (mr->edge_loose_len * 2);
2050  EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
2051  {
2052  const int ml_index = offset + lvert_index;
2053  const int v_index = mr->lverts[lvert_index];
2054  PosNorLoop *vert = &data->vbo_data[ml_index];
2055  copy_v3_v3(vert->pos, mv->co);
2056  vert->nor = data->normals[v_index].low;
2057  }
2059 }
2060 
2062  struct MeshBatchCache *UNUSED(cache),
2063  void *UNUSED(vbo),
2064  void *data)
2065 {
2066  MEM_freeN(data);
2067 }
2068 
2071  .iter_poly_bm = extract_pos_nor_iter_poly_bm,
2072  .iter_poly_mesh = extract_pos_nor_iter_poly_mesh,
2073  .iter_ledge_bm = extract_pos_nor_iter_ledge_bm,
2074  .iter_ledge_mesh = extract_pos_nor_iter_ledge_mesh,
2075  .iter_lvert_bm = extract_pos_nor_iter_lvert_bm,
2076  .iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh,
2077  .finish = extract_pos_nor_finish,
2078  .data_flag = 0,
2079  .use_threading = true,
2080 };
2083 /* ---------------------------------------------------------------------- */
2087 typedef struct PosNorHQLoop {
2088  float pos[3];
2089  short nor[4];
2091 
2096 
2098  struct MeshBatchCache *UNUSED(cache),
2099  void *buf)
2100 {
2101  static GPUVertFormat format = {0};
2102  if (format.attr_len == 0) {
2103  /* WARNING Adjust #PosNorHQLoop struct accordingly. */
2106  GPU_vertformat_alias_add(&format, "vnor");
2107  }
2108  GPUVertBuf *vbo = buf;
2111 
2112  /* Pack normals per vert, reduce amount of computation. */
2113  size_t packed_nor_len = sizeof(GPUNormal) * mr->vert_len;
2114  MeshExtract_PosNorHQ_Data *data = MEM_mallocN(sizeof(*data) + packed_nor_len, __func__);
2115  data->vbo_data = (PosNorHQLoop *)GPU_vertbuf_get_data(vbo);
2116 
2117  /* Quicker than doing it for each loop. */
2118  if (mr->extract_type == MR_EXTRACT_BMESH) {
2119  BMIter iter;
2120  BMVert *eve;
2121  int v;
2122  BM_ITER_MESH_INDEX (eve, &iter, mr->bm, BM_VERTS_OF_MESH, v) {
2123  normal_float_to_short_v3(data->normals[v].high, bm_vert_no_get(mr, eve));
2124  }
2125  }
2126  else {
2127  const MVert *mv = mr->mvert;
2128  for (int v = 0; v < mr->vert_len; v++, mv++) {
2129  copy_v3_v3_short(data->normals[v].high, mv->no);
2130  }
2131  }
2132  return data;
2133 }
2134 
2137  void *_data)
2138 {
2141  {
2142  PosNorHQLoop *vert = &data->vbo_data[l_index];
2143  copy_v3_v3(vert->pos, bm_vert_co_get(mr, l->v));
2144  copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(l->v)].high);
2145 
2146  BMFace *efa = l->f;
2147  vert->nor[3] = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
2148  }
2150 }
2151 
2154  void *_data)
2155 {
2157  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
2158  {
2159  PosNorHQLoop *vert = &data->vbo_data[ml_index];
2160  const MVert *mv = &mr->mvert[ml->v];
2161  copy_v3_v3(vert->pos, mv->co);
2162  copy_v3_v3_short(vert->nor, data->normals[ml->v].high);
2163 
2164  /* Flag for paint mode overlay. */
2165  if (mp->flag & ME_HIDE || mv->flag & ME_HIDE ||
2166  ((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->v_origindex) &&
2167  (mr->v_origindex[ml->v] == ORIGINDEX_NONE))) {
2168  vert->nor[3] = -1;
2169  }
2170  else if (mv->flag & SELECT) {
2171  vert->nor[3] = 1;
2172  }
2173  else {
2174  vert->nor[3] = 0;
2175  }
2176  }
2178 }
2179 
2182  void *_data)
2183 {
2185  EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
2186  {
2187  int l_index = mr->loop_len + ledge_index * 2;
2188  PosNorHQLoop *vert = &data->vbo_data[l_index];
2189  copy_v3_v3(vert[0].pos, bm_vert_co_get(mr, eed->v1));
2190  copy_v3_v3(vert[1].pos, bm_vert_co_get(mr, eed->v2));
2191  copy_v3_v3_short(vert[0].nor, data->normals[BM_elem_index_get(eed->v1)].high);
2192  vert[0].nor[3] = 0;
2193  copy_v3_v3_short(vert[1].nor, data->normals[BM_elem_index_get(eed->v2)].high);
2194  vert[1].nor[3] = 0;
2195  }
2197 }
2198 
2201  void *_data)
2202 {
2204  EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
2205  {
2206  const int ml_index = mr->loop_len + ledge_index * 2;
2207  PosNorHQLoop *vert = &data->vbo_data[ml_index];
2208  copy_v3_v3(vert[0].pos, mr->mvert[med->v1].co);
2209  copy_v3_v3(vert[1].pos, mr->mvert[med->v2].co);
2210  copy_v3_v3_short(vert[0].nor, data->normals[med->v1].high);
2211  vert[0].nor[3] = 0;
2212  copy_v3_v3_short(vert[1].nor, data->normals[med->v2].high);
2213  vert[1].nor[3] = 0;
2214  }
2216 }
2217 
2220  void *_data)
2221 {
2223  const int offset = mr->loop_len + (mr->edge_loose_len * 2);
2224  EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
2225  {
2226  const int l_index = offset + lvert_index;
2227  PosNorHQLoop *vert = &data->vbo_data[l_index];
2228  copy_v3_v3(vert->pos, bm_vert_co_get(mr, eve));
2229  copy_v3_v3_short(vert->nor, data->normals[BM_elem_index_get(eve)].high);
2230  vert->nor[3] = 0;
2231  }
2233 }
2234 
2237  void *_data)
2238 {
2240  const int offset = mr->loop_len + (mr->edge_loose_len * 2);
2241  EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
2242  {
2243  const int ml_index = offset + lvert_index;
2244  const int v_index = mr->lverts[lvert_index];
2245  PosNorHQLoop *vert = &data->vbo_data[ml_index];
2246  copy_v3_v3(vert->pos, mv->co);
2247  copy_v3_v3_short(vert->nor, data->normals[v_index].high);
2248  vert->nor[3] = 0;
2249  }
2251 }
2252 
2254  struct MeshBatchCache *UNUSED(cache),
2255  void *UNUSED(vbo),
2256  void *data)
2257 {
2258  MEM_freeN(data);
2259 }
2260 
2263  .iter_poly_bm = extract_pos_nor_hq_iter_poly_bm,
2264  .iter_poly_mesh = extract_pos_nor_hq_iter_poly_mesh,
2265  .iter_ledge_bm = extract_pos_nor_hq_iter_ledge_bm,
2266  .iter_ledge_mesh = extract_pos_nor_hq_iter_ledge_mesh,
2267  .iter_lvert_bm = extract_pos_nor_hq_iter_lvert_bm,
2268  .iter_lvert_mesh = extract_pos_nor_hq_iter_lvert_mesh,
2269  .finish = extract_pos_nor_hq_finish,
2270  .data_flag = 0,
2271  .use_threading = true,
2272 };
2273 
2275 /* ---------------------------------------------------------------------- */
2279 typedef struct gpuHQNor {
2280  short x, y, z, w;
2282 
2283 static void *extract_lnor_hq_init(const MeshRenderData *mr,
2284  struct MeshBatchCache *UNUSED(cache),
2285  void *buf)
2286 {
2287  static GPUVertFormat format = {0};
2288  if (format.attr_len == 0) {
2290  GPU_vertformat_alias_add(&format, "lnor");
2291  }
2292  GPUVertBuf *vbo = buf;
2294  GPU_vertbuf_data_alloc(vbo, mr->loop_len);
2295 
2296  return GPU_vertbuf_get_data(vbo);
2297 }
2298 
2301  void *data)
2302 {
2303  if (mr->loop_normals) {
2305  {
2306  normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, mr->loop_normals[l_index]);
2307  }
2309  }
2310  else {
2312  {
2314  normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_vert_no_get(mr, l->v));
2315  }
2316  else {
2317  normal_float_to_short_v3(&((gpuHQNor *)data)[l_index].x, bm_face_no_get(mr, l->f));
2318  }
2319  }
2321  }
2322 }
2323 
2326  void *data)
2327 {
2328  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
2329  {
2330  gpuHQNor *lnor_data = &((gpuHQNor *)data)[ml_index];
2331  if (mr->loop_normals) {
2332  normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]);
2333  }
2334  else if (mp->flag & ME_SMOOTH) {
2335  copy_v3_v3_short(&lnor_data->x, mr->mvert[ml->v].no);
2336  }
2337  else {
2338  normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]);
2339  }
2340 
2341  /* Flag for paint mode overlay.
2342  * Only use #MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals.
2343  * In paint mode it will use the un-mapped data to draw the wire-frame. */
2344  if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED &&
2345  (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) {
2346  lnor_data->w = -1;
2347  }
2348  else if (mp->flag & ME_FACE_SEL) {
2349  lnor_data->w = 1;
2350  }
2351  else {
2352  lnor_data->w = 0;
2353  }
2354  }
2356 }
2357 
2360  .iter_poly_bm = extract_lnor_hq_iter_poly_bm,
2361  .iter_poly_mesh = extract_lnor_hq_iter_poly_mesh,
2362  .data_flag = MR_DATA_LOOP_NOR,
2363  .use_threading = true,
2364 };
2365 
2367 /* ---------------------------------------------------------------------- */
2371 static void *extract_lnor_init(const MeshRenderData *mr,
2372  struct MeshBatchCache *UNUSED(cache),
2373  void *buf)
2374 {
2375  static GPUVertFormat format = {0};
2376  if (format.attr_len == 0) {
2378  GPU_vertformat_alias_add(&format, "lnor");
2379  }
2380  GPUVertBuf *vbo = buf;
2382  GPU_vertbuf_data_alloc(vbo, mr->loop_len);
2383 
2384  return GPU_vertbuf_get_data(vbo);
2385 }
2386 
2389  void *data)
2390 {
2391  if (mr->loop_normals) {
2393  {
2394  ((GPUPackedNormal *)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]);
2395  BMFace *efa = l->f;
2396  ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
2397  }
2399  }
2400  else {
2402  {
2405  }
2406  else {
2408  }
2409  BMFace *efa = l->f;
2410  ((GPUPackedNormal *)data)[l_index].w = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ? -1 : 0;
2411  }
2413  }
2414 }
2415 
2418  void *data)
2419 {
2420  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
2421  {
2422  GPUPackedNormal *lnor_data = &((GPUPackedNormal *)data)[ml_index];
2423  if (mr->loop_normals) {
2424  *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]);
2425  }
2426  else if (mp->flag & ME_SMOOTH) {
2427  *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[ml->v].no);
2428  }
2429  else {
2430  *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]);
2431  }
2432 
2433  /* Flag for paint mode overlay.
2434  * Only use MR_EXTRACT_MAPPED in edit mode where it is used to display the edge-normals.
2435  * In paint mode it will use the un-mapped data to draw the wire-frame. */
2436  if (mp->flag & ME_HIDE || (mr->edit_bmesh && mr->extract_type == MR_EXTRACT_MAPPED &&
2437  (mr->v_origindex) && mr->v_origindex[ml->v] == ORIGINDEX_NONE)) {
2438  lnor_data->w = -1;
2439  }
2440  else if (mp->flag & ME_FACE_SEL) {
2441  lnor_data->w = 1;
2442  }
2443  else {
2444  lnor_data->w = 0;
2445  }
2446  }
2448 }
2449 
2450 static const MeshExtract extract_lnor = {
2452  .iter_poly_bm = extract_lnor_iter_poly_bm,
2453  .iter_poly_mesh = extract_lnor_iter_poly_mesh,
2454  .data_flag = MR_DATA_LOOP_NOR,
2455  .use_threading = true,
2456 };
2457 
2460 /* ---------------------------------------------------------------------- */
2464 static void *extract_uv_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
2465 {
2466  GPUVertFormat format = {0};
2468 
2469  CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
2470  uint32_t uv_layers = cache->cd_used.uv;
2471  /* HACK to fix T68857 */
2472  if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) {
2473  int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
2474  if (layer != -1) {
2475  uv_layers |= (1 << layer);
2476  }
2477  }
2478 
2479  for (int i = 0; i < MAX_MTFACE; i++) {
2480  if (uv_layers & (1 << i)) {
2481  char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
2482  const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
2483 
2484  GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
2485  /* UV layer name. */
2486  BLI_snprintf(attr_name, sizeof(attr_name), "u%s", attr_safe_name);
2488  /* Auto layer name. */
2489  BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
2490  GPU_vertformat_alias_add(&format, attr_name);
2491  /* Active render layer name. */
2492  if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
2494  }
2495  /* Active display layer name. */
2496  if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
2498  /* Alias to `pos` for edit uvs. */
2500  }
2501  /* Stencil mask uv layer name. */
2502  if (i == CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV)) {
2504  }
2505  }
2506  }
2507 
2508  int v_len = mr->loop_len;
2509  if (format.attr_len == 0) {
2511  /* VBO will not be used, only allocate minimum of memory. */
2512  v_len = 1;
2513  }
2514 
2515  GPUVertBuf *vbo = buf;
2517  GPU_vertbuf_data_alloc(vbo, v_len);
2518 
2519  float(*uv_data)[2] = (float(*)[2])GPU_vertbuf_get_data(vbo);
2520  for (int i = 0; i < MAX_MTFACE; i++) {
2521  if (uv_layers & (1 << i)) {
2522  if (mr->extract_type == MR_EXTRACT_BMESH) {
2523  int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPUV, i);
2524  BMIter f_iter;
2525  BMFace *efa;
2526  BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
2527  BMLoop *l_iter, *l_first;
2528  l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
2529  do {
2530  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs);
2531  memcpy(uv_data, luv->uv, sizeof(*uv_data));
2532  uv_data++;
2533  } while ((l_iter = l_iter->next) != l_first);
2534  }
2535  }
2536  else {
2537  MLoopUV *layer_data = CustomData_get_layer_n(cd_ldata, CD_MLOOPUV, i);
2538  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, uv_data++, layer_data++) {
2539  memcpy(uv_data, layer_data->uv, sizeof(*uv_data));
2540  }
2541  }
2542  }
2543  }
2544 
2545  return NULL;
2546 }
2547 
2548 static const MeshExtract extract_uv = {
2549  .init = extract_uv_init,
2550  .data_flag = 0,
2551  .use_threading = false,
2552 };
2553 
2556 /* ---------------------------------------------------------------------- */
2560 static void extract_tan_ex(const MeshRenderData *mr,
2561  struct MeshBatchCache *cache,
2562  GPUVertBuf *vbo,
2563  const bool do_hq)
2564 {
2565  GPUVertCompType comp_type = do_hq ? GPU_COMP_I16 : GPU_COMP_I10;
2567 
2568  GPUVertFormat format = {0};
2570 
2571  CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
2572  CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
2573  uint32_t tan_layers = cache->cd_used.tan;
2574  float(*orco)[3] = CustomData_get_layer(cd_vdata, CD_ORCO);
2575  bool orco_allocated = false;
2576  const bool use_orco_tan = cache->cd_used.tan_orco != 0;
2577 
2578  int tan_len = 0;
2579  char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME];
2580 
2581  for (int i = 0; i < MAX_MTFACE; i++) {
2582  if (tan_layers & (1 << i)) {
2583  char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
2584  const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
2585  GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
2586  /* Tangent layer name. */
2587  BLI_snprintf(attr_name, sizeof(attr_name), "t%s", attr_safe_name);
2588  GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode);
2589  /* Active render layer name. */
2590  if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
2592  }
2593  /* Active display layer name. */
2594  if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
2596  }
2597 
2598  BLI_strncpy(tangent_names[tan_len++], layer_name, MAX_CUSTOMDATA_LAYER_NAME);
2599  }
2600  }
2601  if (use_orco_tan && orco == NULL) {
2602  /* If `orco` is not available compute it ourselves */
2603  orco_allocated = true;
2604  orco = MEM_mallocN(sizeof(*orco) * mr->vert_len, __func__);
2605 
2606  if (mr->extract_type == MR_EXTRACT_BMESH) {
2607  BMesh *bm = mr->bm;
2608  for (int v = 0; v < mr->vert_len; v++) {
2609  const BMVert *eve = BM_vert_at_index(bm, v);
2610  /* Exceptional case where #bm_vert_co_get can be avoided, as we want the original coords.
2611  * not the distorted ones. */
2612  copy_v3_v3(orco[v], eve->co);
2613  }
2614  }
2615  else {
2616  const MVert *mv = mr->mvert;
2617  for (int v = 0; v < mr->vert_len; v++, mv++) {
2618  copy_v3_v3(orco[v], mv->co);
2619  }
2620  }
2621  BKE_mesh_orco_verts_transform(mr->me, orco, mr->vert_len, 0);
2622  }
2623 
2624  /* Start Fresh */
2625  CustomData loop_data;
2626  CustomData_reset(&loop_data);
2627  if (tan_len != 0 || use_orco_tan) {
2628  short tangent_mask = 0;
2629  bool calc_active_tangent = false;
2630  if (mr->extract_type == MR_EXTRACT_BMESH) {
2632  calc_active_tangent,
2633  tangent_names,
2634  tan_len,
2635  mr->poly_normals,
2636  mr->loop_normals,
2637  orco,
2638  &loop_data,
2639  mr->loop_len,
2640  &tangent_mask);
2641  }
2642  else {
2644  mr->mpoly,
2645  mr->poly_len,
2646  mr->mloop,
2647  mr->mlooptri,
2648  mr->tri_len,
2649  cd_ldata,
2650  calc_active_tangent,
2651  tangent_names,
2652  tan_len,
2653  mr->poly_normals,
2654  mr->loop_normals,
2655  orco,
2656  &loop_data,
2657  mr->loop_len,
2658  &tangent_mask);
2659  }
2660  }
2661 
2662  if (use_orco_tan) {
2663  char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
2664  const char *layer_name = CustomData_get_layer_name(&loop_data, CD_TANGENT, 0);
2665  GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
2666  BLI_snprintf(attr_name, sizeof(*attr_name), "t%s", attr_safe_name);
2667  GPU_vertformat_attr_add(&format, attr_name, comp_type, 4, fetch_mode);
2670  }
2671 
2672  if (orco_allocated) {
2673  MEM_SAFE_FREE(orco);
2674  }
2675 
2676  int v_len = mr->loop_len;
2677  if (format.attr_len == 0) {
2679  /* VBO will not be used, only allocate minimum of memory. */
2680  v_len = 1;
2681  }
2682 
2684  GPU_vertbuf_data_alloc(vbo, v_len);
2685 
2686  if (do_hq) {
2687  short(*tan_data)[4] = (short(*)[4])GPU_vertbuf_get_data(vbo);
2688  for (int i = 0; i < tan_len; i++) {
2689  const char *name = tangent_names[i];
2690  float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(
2691  &loop_data, CD_TANGENT, name);
2692  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
2693  normal_float_to_short_v3(*tan_data, layer_data[ml_index]);
2694  (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
2695  tan_data++;
2696  }
2697  }
2698  if (use_orco_tan) {
2699  float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0);
2700  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
2701  normal_float_to_short_v3(*tan_data, layer_data[ml_index]);
2702  (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
2703  tan_data++;
2704  }
2705  }
2706  }
2707  else {
2709  for (int i = 0; i < tan_len; i++) {
2710  const char *name = tangent_names[i];
2711  float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(
2712  &loop_data, CD_TANGENT, name);
2713  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
2714  *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]);
2715  tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2;
2716  tan_data++;
2717  }
2718  }
2719  if (use_orco_tan) {
2720  float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0);
2721  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
2722  *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]);
2723  tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2;
2724  tan_data++;
2725  }
2726  }
2727  }
2728 
2729  CustomData_free(&loop_data, mr->loop_len);
2730 }
2731 
2732 static void *extract_tan_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
2733 {
2734  extract_tan_ex(mr, cache, buf, false);
2735  return NULL;
2736 }
2737 
2738 static const MeshExtract extract_tan = {
2741  .use_threading = false,
2742 };
2743 
2746 /* ---------------------------------------------------------------------- */
2750 static void *extract_tan_hq_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
2751 {
2752  extract_tan_ex(mr, cache, buf, true);
2753  return NULL;
2754 }
2755 
2756 static const MeshExtract extract_tan_hq = {
2759  .use_threading = false,
2760 };
2761 
2764 /* ---------------------------------------------------------------------- */
2769  struct MeshBatchCache *UNUSED(cache),
2770  void *buf)
2771 {
2772  GPUVertFormat format = {0};
2773 
2774  CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
2775  CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
2776  CustomData *cd_pdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata;
2777 
2778  float *cd_mask = CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
2779  int *cd_face_set = CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
2780 
2781  if (format.attr_len == 0) {
2784  }
2785 
2786  GPUVertBuf *vbo = buf;
2788  GPU_vertbuf_data_alloc(vbo, mr->loop_len);
2789 
2790  typedef struct gpuSculptData {
2791  uint8_t face_set_color[4];
2792  float mask;
2793  } gpuSculptData;
2794 
2795  gpuSculptData *vbo_data = (gpuSculptData *)GPU_vertbuf_get_data(vbo);
2796  MLoop *loops = CustomData_get_layer(cd_ldata, CD_MLOOP);
2797 
2798  if (mr->extract_type == MR_EXTRACT_BMESH) {
2799  int cd_mask_ofs = CustomData_get_offset(cd_vdata, CD_PAINT_MASK);
2800  int cd_face_set_ofs = CustomData_get_offset(cd_pdata, CD_SCULPT_FACE_SETS);
2801  BMIter f_iter;
2802  BMFace *efa;
2803  BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
2804  BMLoop *l_iter, *l_first;
2805  l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
2806  do {
2807  float v_mask = 0.0f;
2808  if (cd_mask) {
2809  v_mask = BM_ELEM_CD_GET_FLOAT(l_iter->v, cd_mask_ofs);
2810  }
2811  vbo_data->mask = v_mask;
2812  uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
2813  if (cd_face_set) {
2814  const int face_set_id = BM_ELEM_CD_GET_INT(l_iter->f, cd_face_set_ofs);
2815  if (face_set_id != mr->me->face_sets_color_default) {
2817  face_set_id, mr->me->face_sets_color_seed, face_set_color);
2818  }
2819  }
2820  copy_v3_v3_uchar(vbo_data->face_set_color, face_set_color);
2821  vbo_data++;
2822  } while ((l_iter = l_iter->next) != l_first);
2823  }
2824  }
2825  else {
2826  int mp_loop = 0;
2827  for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) {
2828  const MPoly *p = &mr->mpoly[mp_index];
2829  for (int l = 0; l < p->totloop; l++) {
2830  float v_mask = 0.0f;
2831  if (cd_mask) {
2832  v_mask = cd_mask[loops[mp_loop].v];
2833  }
2834  vbo_data->mask = v_mask;
2835 
2836  uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
2837  if (cd_face_set) {
2838  const int face_set_id = cd_face_set[mp_index];
2839  /* Skip for the default color Face Set to render it white. */
2840  if (face_set_id != mr->me->face_sets_color_default) {
2842  face_set_id, mr->me->face_sets_color_seed, face_set_color);
2843  }
2844  }
2845  copy_v3_v3_uchar(vbo_data->face_set_color, face_set_color);
2846  mp_loop++;
2847  vbo_data++;
2848  }
2849  }
2850  }
2851 
2852  return NULL;
2853 }
2854 
2857  .data_flag = 0,
2858  /* TODO: enable threading. */
2859  .use_threading = false,
2860 };
2861 
2864 /* ---------------------------------------------------------------------- */
2868 static void *extract_vcol_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
2869 {
2870  GPUVertFormat format = {0};
2872 
2873  CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
2874  CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
2875  uint32_t vcol_layers = cache->cd_used.vcol;
2876  uint32_t svcol_layers = cache->cd_used.sculpt_vcol;
2877 
2878  for (int i = 0; i < MAX_MCOL; i++) {
2879  if (vcol_layers & (1 << i)) {
2880  char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
2881  const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPCOL, i);
2882  GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
2883 
2884  BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
2886 
2887  if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) {
2889  }
2890  if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) {
2892  }
2893 
2894  /* Gather number of auto layers. */
2895  /* We only do `vcols` that are not overridden by `uvs` and sculpt vertex colors. */
2896  if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1 &&
2897  CustomData_get_named_layer_index(cd_vdata, CD_PROP_COLOR, layer_name) == -1) {
2898  BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
2899  GPU_vertformat_alias_add(&format, attr_name);
2900  }
2901  }
2902  }
2903 
2904  /* Sculpt Vertex Colors */
2905  if (U.experimental.use_sculpt_vertex_colors) {
2906  for (int i = 0; i < 8; i++) {
2907  if (svcol_layers & (1 << i)) {
2908  char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
2909  const char *layer_name = CustomData_get_layer_name(cd_vdata, CD_PROP_COLOR, i);
2910  GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
2911 
2912  BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
2914 
2915  if (i == CustomData_get_render_layer(cd_vdata, CD_PROP_COLOR)) {
2917  }
2918  if (i == CustomData_get_active_layer(cd_vdata, CD_PROP_COLOR)) {
2920  }
2921  /* Gather number of auto layers. */
2922  /* We only do `vcols` that are not overridden by `uvs`. */
2923  if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
2924  BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
2925  GPU_vertformat_alias_add(&format, attr_name);
2926  }
2927  }
2928  }
2929  }
2930 
2931  GPUVertBuf *vbo = buf;
2933  GPU_vertbuf_data_alloc(vbo, mr->loop_len);
2934 
2935  typedef struct gpuMeshVcol {
2936  ushort r, g, b, a;
2937  } gpuMeshVcol;
2938 
2939  gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo);
2940  MLoop *loops = CustomData_get_layer(cd_ldata, CD_MLOOP);
2941 
2942  for (int i = 0; i < MAX_MCOL; i++) {
2943  if (vcol_layers & (1 << i)) {
2944  if (mr->extract_type == MR_EXTRACT_BMESH) {
2945  int cd_ofs = CustomData_get_n_offset(cd_ldata, CD_MLOOPCOL, i);
2946  BMIter f_iter;
2947  BMFace *efa;
2948  BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
2949  BMLoop *l_iter, *l_first;
2950  l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
2951  do {
2952  const MLoopCol *mloopcol = BM_ELEM_CD_GET_VOID_P(l_iter, cd_ofs);
2953  vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
2954  vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
2955  vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
2956  vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
2957  vcol_data++;
2958  } while ((l_iter = l_iter->next) != l_first);
2959  }
2960  }
2961  else {
2962  const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
2963  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, mloopcol++, vcol_data++) {
2964  vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
2965  vcol_data->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
2966  vcol_data->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
2967  vcol_data->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
2968  }
2969  }
2970  }
2971 
2972  if (svcol_layers & (1 << i) && U.experimental.use_sculpt_vertex_colors) {
2973  if (mr->extract_type == MR_EXTRACT_BMESH) {
2974  int cd_ofs = CustomData_get_n_offset(cd_vdata, CD_PROP_COLOR, i);
2975  BMIter f_iter;
2976  BMFace *efa;
2977  BM_ITER_MESH (efa, &f_iter, mr->bm, BM_FACES_OF_MESH) {
2978  BMLoop *l_iter, *l_first;
2979  l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
2980  do {
2981  const MPropCol *prop_col = BM_ELEM_CD_GET_VOID_P(l_iter->v, cd_ofs);
2982  vcol_data->r = unit_float_to_ushort_clamp(prop_col->color[0]);
2983  vcol_data->g = unit_float_to_ushort_clamp(prop_col->color[1]);
2984  vcol_data->b = unit_float_to_ushort_clamp(prop_col->color[2]);
2985  vcol_data->a = unit_float_to_ushort_clamp(prop_col->color[3]);
2986  vcol_data++;
2987  } while ((l_iter = l_iter->next) != l_first);
2988  }
2989  }
2990  else {
2991  MPropCol *vcol = CustomData_get_layer_n(cd_vdata, CD_PROP_COLOR, i);
2992  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++, vcol_data++) {
2993  vcol_data->r = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[0]);
2994  vcol_data->g = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[1]);
2995  vcol_data->b = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[2]);
2996  vcol_data->a = unit_float_to_ushort_clamp(vcol[loops[ml_index].v].color[3]);
2997  }
2998  }
2999  }
3000  }
3001  return NULL;
3002 }
3003 
3004 static const MeshExtract extract_vcol = {
3006  .data_flag = 0,
3007  .use_threading = false,
3008 };
3009 
3012 /* ---------------------------------------------------------------------- */
3016 typedef struct MeshExtract_Orco_Data {
3018  float (*orco)[3];
3020 
3021 static void *extract_orco_init(const MeshRenderData *mr,
3022  struct MeshBatchCache *UNUSED(cache),
3023  void *buf)
3024 {
3025  static GPUVertFormat format = {0};
3026  if (format.attr_len == 0) {
3027  /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
3028  * attributes. This is a substantial waste of video-ram and should be done another way.
3029  * Unfortunately, at the time of writing, I did not found any other "non disruptive"
3030  * alternative. */
3032  }
3033 
3034  GPUVertBuf *vbo = buf;
3036  GPU_vertbuf_data_alloc(vbo, mr->loop_len);
3037 
3038  CustomData *cd_vdata = &mr->me->vdata;
3039 
3040  MeshExtract_Orco_Data *data = MEM_mallocN(sizeof(*data), __func__);
3041  data->vbo_data = (float(*)[4])GPU_vertbuf_get_data(vbo);
3042  data->orco = CustomData_get_layer(cd_vdata, CD_ORCO);
3043  /* Make sure `orco` layer was requested only if needed! */
3044  BLI_assert(data->orco);
3045  return data;
3046 }
3047 
3050  void *data)
3051 {
3054  {
3055  float *loop_orco = orco_data->vbo_data[l_index];
3056  copy_v3_v3(loop_orco, orco_data->orco[BM_elem_index_get(loop->v)]);
3057  loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
3058  }
3060 }
3061 
3064  void *data)
3065 {
3066  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
3067  {
3069  float *loop_orco = orco_data->vbo_data[ml_index];
3070  copy_v3_v3(loop_orco, orco_data->orco[ml->v]);
3071  loop_orco[3] = 0.0; /* Tag as not a generic attribute. */
3072  }
3074 }
3075 
3077  struct MeshBatchCache *UNUSED(cache),
3078  void *UNUSED(buf),
3079  void *data)
3080 {
3081  MEM_freeN(data);
3082 }
3083 
3084 static const MeshExtract extract_orco = {
3086  .iter_poly_bm = extract_orco_iter_poly_bm,
3087  .iter_poly_mesh = extract_orco_iter_poly_mesh,
3088  .finish = extract_orco_finish,
3089  .data_flag = 0,
3090  .use_threading = true,
3091 };
3092 
3095 /* ---------------------------------------------------------------------- */
3103  /* Number of loop per edge. */
3106 
3107 static float loop_edge_factor_get(const float f_no[3],
3108  const float v_co[3],
3109  const float v_no[3],
3110  const float v_next_co[3])
3111 {
3112  float enor[3], evec[3];
3113  sub_v3_v3v3(evec, v_next_co, v_co);
3114  cross_v3_v3v3(enor, v_no, evec);
3115  normalize_v3(enor);
3116  float d = fabsf(dot_v3v3(enor, f_no));
3117  /* Re-scale to the slider range. */
3118  d *= (1.0f / 0.065f);
3119  CLAMP(d, 0.0f, 1.0f);
3120  return d;
3121 }
3122 
3123 static void *extract_edge_fac_init(const MeshRenderData *mr,
3124  struct MeshBatchCache *UNUSED(cache),
3125  void *buf)
3126 {
3127  static GPUVertFormat format = {0};
3128  if (format.attr_len == 0) {
3130  }
3131  GPUVertBuf *vbo = buf;
3134 
3136 
3137  if (mr->extract_type == MR_EXTRACT_MESH) {
3138  size_t edge_loop_count_size = sizeof(uint32_t) * mr->edge_len;
3139  data = MEM_callocN(sizeof(*data) + edge_loop_count_size, __func__);
3140 
3141  /* HACK(fclem) Detecting the need for edge render.
3142  * We could have a flag in the mesh instead or check the modifier stack. */
3143  const MEdge *med = mr->medge;
3144  for (int e_index = 0; e_index < mr->edge_len; e_index++, med++) {
3145  if ((med->flag & ME_EDGERENDER) == 0) {
3146  data->use_edge_render = true;
3147  break;
3148  }
3149  }
3150  }
3151  else {
3152  data = MEM_callocN(sizeof(*data), __func__);
3153  /* HACK to bypass non-manifold check in mesh_edge_fac_finish(). */
3154  data->use_edge_render = true;
3155  }
3156 
3157  data->vbo_data = GPU_vertbuf_get_data(vbo);
3158  return data;
3159 }
3160 
3163  void *_data)
3164 {
3165  MeshExtract_EdgeFac_Data *data = _data;
3167  {
3168  if (BM_edge_is_manifold(l->e)) {
3169  float ratio = loop_edge_factor_get(bm_face_no_get(mr, l->f),
3170  bm_vert_co_get(mr, l->v),
3171  bm_vert_no_get(mr, l->v),
3172  bm_vert_co_get(mr, l->next->v));
3173  data->vbo_data[l_index] = ratio * 253 + 1;
3174  }
3175  else {
3176  data->vbo_data[l_index] = 255;
3177  }
3178  }
3180 }
3181 
3184  void *_data)
3185 {
3187 
3188  if (data->use_edge_render) {
3189  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
3190  {
3191  const MEdge *med = &mr->medge[ml->e];
3192  data->vbo_data[ml_index] = (med->flag & ME_EDGERENDER) ? 255 : 0;
3193  }
3195  }
3196  else {
3197  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
3198  {
3199  /* Count loop per edge to detect non-manifold. */
3200  if (data->edge_loop_count[ml->e] < 3) {
3201  data->edge_loop_count[ml->e]++;
3202  }
3203  if (data->edge_loop_count[ml->e] == 2) {
3204  /* Manifold */
3205  const int ml_index_last = mp->totloop + mp->loopstart - 1;
3206  const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1);
3207  const MLoop *ml_next = &mr->mloop[ml_index_other];
3208  const MVert *v1 = &mr->mvert[ml->v];
3209  const MVert *v2 = &mr->mvert[ml_next->v];
3210  float vnor_f[3];
3211  normal_short_to_float_v3(vnor_f, v1->no);
3212  float ratio = loop_edge_factor_get(mr->poly_normals[mp_index], v1->co, vnor_f, v2->co);
3213  data->vbo_data[ml_index] = ratio * 253 + 1;
3214  }
3215  else {
3216  /* Non-manifold */
3217  data->vbo_data[ml_index] = 255;
3218  }
3219  }
3221  }
3222 }
3223 
3226  void *_data)
3227 {
3228  MeshExtract_EdgeFac_Data *data = _data;
3229  EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
3230  {
3231  data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255;
3232  data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255;
3233  }
3235 }
3236 
3239  void *_data)
3240 {
3241  MeshExtract_EdgeFac_Data *data = _data;
3242  EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
3243  {
3244  data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255;
3245  data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255;
3246  }
3248 }
3249 
3251  struct MeshBatchCache *UNUSED(cache),
3252  void *buf,
3253  void *_data)
3254 {
3255  MeshExtract_EdgeFac_Data *data = _data;
3256 
3257  if (GPU_crappy_amd_driver()) {
3258  GPUVertBuf *vbo = (GPUVertBuf *)buf;
3259  /* Some AMD drivers strangely crash with VBO's with a one byte format.
3260  * To workaround we reinitialize the VBO with another format and convert
3261  * all bytes to floats. */
3262  static GPUVertFormat format = {0};
3263  if (format.attr_len == 0) {
3265  }
3266  /* We keep the data reference in data->vbo_data. */
3267  data->vbo_data = GPU_vertbuf_steal_data(vbo);
3268  GPU_vertbuf_clear(vbo);
3269 
3270  int buf_len = mr->loop_len + mr->loop_loose_len;
3272  GPU_vertbuf_data_alloc(vbo, buf_len);
3273 
3274  float *fdata = (float *)GPU_vertbuf_get_data(vbo);
3275  for (int ml_index = 0; ml_index < buf_len; ml_index++, fdata++) {
3276  *fdata = data->vbo_data[ml_index] / 255.0f;
3277  }
3278  /* Free old byte data. */
3279  MEM_freeN(data->vbo_data);
3280  }
3281  MEM_freeN(data);
3282 }
3283 
3286  .iter_poly_bm = extract_edge_fac_iter_poly_bm,
3287  .iter_poly_mesh = extract_edge_fac_iter_poly_mesh,
3288  .iter_ledge_bm = extract_edge_fac_iter_ledge_bm,
3289  .iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh,
3290  .finish = extract_edge_fac_finish,
3291  .data_flag = MR_DATA_POLY_NOR,
3292  .use_threading = false,
3293 };
3294 
3296 /* ---------------------------------------------------------------------- */
3300 typedef struct MeshExtract_Weight_Data {
3301  float *vbo_data;
3303  const MDeformVert *dvert; /* For #Mesh. */
3304  int cd_ofs; /* For #BMesh. */
3306 
3307 static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate)
3308 {
3309  /* Error state. */
3310  if ((wstate->defgroup_active < 0) && (wstate->defgroup_len > 0)) {
3311  return -2.0f;
3312  }
3313  if (dvert == NULL) {
3314  return (wstate->alert_mode != OB_DRAW_GROUPUSER_NONE) ? -1.0f : 0.0f;
3315  }
3316 
3317  float input = 0.0f;
3318  if (wstate->flags & DRW_MESH_WEIGHT_STATE_MULTIPAINT) {
3319  /* Multi-Paint feature */
3320  bool is_normalized = (wstate->flags & (DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE |
3323  wstate->defgroup_len,
3324  wstate->defgroup_sel,
3325  wstate->defgroup_sel_count,
3326  is_normalized);
3327  /* make it black if the selected groups have no weight on a vertex */
3328  if (input == 0.0f) {
3329  return -1.0f;
3330  }
3331  }
3332  else {
3333  /* default, non tricky behavior */
3334  input = BKE_defvert_find_weight(dvert, wstate->defgroup_active);
3335 
3336  if (input == 0.0f) {
3337  switch (wstate->alert_mode) {
3339  return -1.0f;
3340  break;
3341  case OB_DRAW_GROUPUSER_ALL:
3342  if (BKE_defvert_is_weight_zero(dvert, wstate->defgroup_len)) {
3343  return -1.0f;
3344  }
3345  break;
3346  }
3347  }
3348  }
3349 
3350  /* Lock-Relative: display the fraction of current weight vs total unlocked weight. */
3353  input, dvert, wstate->defgroup_len, wstate->defgroup_locked, wstate->defgroup_unlocked);
3354  }
3355 
3356  CLAMP(input, 0.0f, 1.0f);
3357  return input;
3358 }
3359 
3360 static void *extract_weights_init(const MeshRenderData *mr,
3361  struct MeshBatchCache *cache,
3362  void *buf)
3363 {
3364  static GPUVertFormat format = {0};
3365  if (format.attr_len == 0) {
3367  }
3368  GPUVertBuf *vbo = buf;
3371 
3372  MeshExtract_Weight_Data *data = MEM_callocN(sizeof(*data), __func__);
3373  data->vbo_data = (float *)GPU_vertbuf_get_data(vbo);
3374  data->wstate = &cache->weight_state;
3375 
3376  if (data->wstate->defgroup_active == -1) {
3377  /* Nothing to show. */
3378  data->dvert = NULL;
3379  data->cd_ofs = -1;
3380  }
3381  else if (mr->extract_type == MR_EXTRACT_BMESH) {
3382  data->dvert = NULL;
3383  data->cd_ofs = CustomData_get_offset(&mr->bm->vdata, CD_MDEFORMVERT);
3384  }
3385  else {
3386  data->dvert = CustomData_get_layer(&mr->me->vdata, CD_MDEFORMVERT);
3387  data->cd_ofs = -1;
3388  }
3389  return data;
3390 }
3391 
3394  void *_data)
3395 {
3396  MeshExtract_Weight_Data *data = _data;
3397  if (data->cd_ofs != -1) {
3399  {
3400  const MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(l->v, data->cd_ofs);
3401  data->vbo_data[l_index] = evaluate_vertex_weight(dvert, data->wstate);
3402  }
3404  }
3405  else {
3407  {
3408  data->vbo_data[l_index] = evaluate_vertex_weight(NULL, data->wstate);
3409  }
3411  }
3412 }
3413 
3416  void *_data)
3417 {
3418  MeshExtract_Weight_Data *data = _data;
3419  if (data->dvert != NULL) {
3420  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
3421  {
3422  const MDeformVert *dvert = &data->dvert[ml->v];
3423  data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate);
3424  }
3426  }
3427  else {
3428  const MDeformVert *dvert = NULL;
3429  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
3430  {
3431  data->vbo_data[ml_index] = evaluate_vertex_weight(dvert, data->wstate);
3432  }
3434  }
3435 }
3436 
3438  struct MeshBatchCache *UNUSED(cache),
3439  void *UNUSED(buf),
3440  void *data)
3441 {
3442  MEM_freeN(data);
3443 }
3444 
3447  .iter_poly_bm = extract_weights_iter_poly_bm,
3448  .iter_poly_mesh = extract_weights_iter_poly_mesh,
3449  .finish = extract_weights_finish,
3450  .data_flag = 0,
3451  .use_threading = true,
3452 };
3453 
3456 /* ---------------------------------------------------------------------- */
3460 typedef struct EditLoopData {
3466 
3468  BMFace *efa,
3469  const int cd_ofs,
3470  EditLoopData *eattr)
3471 {
3472  if (efa == mr->efa_act) {
3473  eattr->v_flag |= VFLAG_FACE_ACTIVE;
3474  }
3475  if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
3476  eattr->v_flag |= VFLAG_FACE_SELECTED;
3477  }
3478 
3479  if (efa == mr->efa_act_uv) {
3480  eattr->v_flag |= VFLAG_FACE_UV_ACTIVE;
3481  }
3482  if ((cd_ofs != -1) && uvedit_face_select_test_ex(mr->toolsettings, (BMFace *)efa, cd_ofs)) {
3483  eattr->v_flag |= VFLAG_FACE_UV_SELECT;
3484  }
3485 
3486 #ifdef WITH_FREESTYLE
3487  if (mr->freestyle_face_ofs != -1) {
3489  if (ffa->flag & FREESTYLE_FACE_MARK) {
3490  eattr->v_flag |= VFLAG_FACE_FREESTYLE;
3491  }
3492  }
3493 #endif
3494 }
3495 
3496 static void mesh_render_data_edge_flag(const MeshRenderData *mr, BMEdge *eed, EditLoopData *eattr)
3497 {
3498  const ToolSettings *ts = mr->toolsettings;
3499  const bool is_vertex_select_mode = (ts != NULL) && (ts->selectmode & SCE_SELECT_VERTEX) != 0;
3500  const bool is_face_only_select_mode = (ts != NULL) && (ts->selectmode == SCE_SELECT_FACE);
3501 
3502  if (eed == mr->eed_act) {
3503  eattr->e_flag |= VFLAG_EDGE_ACTIVE;
3504  }
3505  if (!is_vertex_select_mode && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
3506  eattr->e_flag |= VFLAG_EDGE_SELECTED;
3507  }
3508  if (is_vertex_select_mode && BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) &&
3510  eattr->e_flag |= VFLAG_EDGE_SELECTED;
3511  eattr->e_flag |= VFLAG_VERT_SELECTED;
3512  }
3513  if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
3514  eattr->e_flag |= VFLAG_EDGE_SEAM;
3515  }
3516  if (!BM_elem_flag_test(eed, BM_ELEM_SMOOTH)) {
3517  eattr->e_flag |= VFLAG_EDGE_SHARP;
3518  }
3519 
3520  /* Use active edge color for active face edges because
3521  * specular highlights make it hard to see T55456#510873.
3522  *
3523  * This isn't ideal since it can't be used when mixing edge/face modes
3524  * but it's still better than not being able to see the active face. */
3525  if (is_face_only_select_mode) {
3526  if (mr->efa_act != NULL) {
3527  if (BM_edge_in_face(eed, mr->efa_act)) {
3528  eattr->e_flag |= VFLAG_EDGE_ACTIVE;
3529  }
3530  }
3531  }
3532 
3533  /* Use a byte for value range */
3534  if (mr->crease_ofs != -1) {
3535  float crease = BM_ELEM_CD_GET_FLOAT(eed, mr->crease_ofs);
3536  if (crease > 0) {
3537  eattr->crease = (uchar)(crease * 255.0f);
3538  }
3539  }
3540  /* Use a byte for value range */
3541  if (mr->bweight_ofs != -1) {
3542  float bweight = BM_ELEM_CD_GET_FLOAT(eed, mr->bweight_ofs);
3543  if (bweight > 0) {
3544  eattr->bweight = (uchar)(bweight * 255.0f);
3545  }
3546  }
3547 #ifdef WITH_FREESTYLE
3548  if (mr->freestyle_edge_ofs != -1) {
3550  if (fed->flag & FREESTYLE_EDGE_MARK) {
3551  eattr->e_flag |= VFLAG_EDGE_FREESTYLE;
3552  }
3553  }
3554 #endif
3555 }
3556 
3558  BMLoop *l,
3559  const int cd_ofs,
3560  EditLoopData *eattr)
3561 {
3562  if (cd_ofs == -1) {
3563  return;
3564  }
3565  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_ofs);
3566  if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) {
3567  eattr->v_flag |= VFLAG_VERT_UV_PINNED;
3568  }
3569  if (uvedit_uv_select_test_ex(mr->toolsettings, l, cd_ofs)) {
3570  eattr->v_flag |= VFLAG_VERT_UV_SELECT;
3571  }
3572 }
3573 
3575  BMLoop *l,
3576  const int cd_ofs,
3577  EditLoopData *eattr)
3578 {
3579  if (cd_ofs == -1) {
3580  return;
3581  }
3582  if (uvedit_edge_select_test_ex(mr->toolsettings, l, cd_ofs)) {
3583  eattr->v_flag |= VFLAG_EDGE_UV_SELECT;
3584  eattr->v_flag |= VFLAG_VERT_UV_SELECT;
3585  }
3586 }
3587 
3588 static void mesh_render_data_vert_flag(const MeshRenderData *mr, BMVert *eve, EditLoopData *eattr)
3589 {
3590  if (eve == mr->eve_act) {
3591  eattr->e_flag |= VFLAG_VERT_ACTIVE;
3592  }
3593  if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
3594  eattr->e_flag |= VFLAG_VERT_SELECTED;
3595  }
3596 }
3597 
3599  struct MeshBatchCache *UNUSED(cache),
3600  void *buf)
3601 {
3602  static GPUVertFormat format = {0};
3603  if (format.attr_len == 0) {
3604  /* WARNING: Adjust #EditLoopData struct accordingly. */
3606  GPU_vertformat_alias_add(&format, "flag");
3607  }
3608  GPUVertBuf *vbo = buf;
3611  return GPU_vertbuf_get_data(vbo);
3612 }
3613 
3616  void *_data)
3617 {
3618 
3620  {
3621  EditLoopData *data = (EditLoopData *)_data + l_index;
3622  memset(data, 0x0, sizeof(*data));
3623  mesh_render_data_face_flag(mr, l->f, -1, data);
3626  }
3628 }
3629 
3632  void *_data)
3633 {
3634  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
3635  {
3636  EditLoopData *data = (EditLoopData *)_data + ml_index;
3637  memset(data, 0x0, sizeof(*data));
3638  BMFace *efa = bm_original_face_get(mr, mp_index);
3639  BMEdge *eed = bm_original_edge_get(mr, ml->e);
3640  BMVert *eve = bm_original_vert_get(mr, ml->v);
3641  if (efa) {
3642  mesh_render_data_face_flag(mr, efa, -1, data);
3643  }
3644  if (eed) {
3645  mesh_render_data_edge_flag(mr, eed, data);
3646  }
3647  if (eve) {
3648  mesh_render_data_vert_flag(mr, eve, data);
3649  }
3650  }
3652 }
3653 
3656  void *_data)
3657 {
3658  EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
3659  {
3660  EditLoopData *data = (EditLoopData *)_data + mr->loop_len + (ledge_index * 2);
3661  memset(data, 0x0, sizeof(*data) * 2);
3662  mesh_render_data_edge_flag(mr, eed, &data[0]);
3663  data[1] = data[0];
3664  mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
3665  mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
3666  }
3668 }
3669 
3672  void *_data)
3673 {
3674  EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
3675  {
3676  EditLoopData *data = (EditLoopData *)_data + mr->loop_len + ledge_index * 2;
3677  memset(data, 0x0, sizeof(*data) * 2);
3678  const int e_index = mr->ledges[ledge_index];
3679  BMEdge *eed = bm_original_edge_get(mr, e_index);
3680  BMVert *eve1 = bm_original_vert_get(mr, med->v1);
3681  BMVert *eve2 = bm_original_vert_get(mr, med->v2);
3682  if (eed) {
3683  mesh_render_data_edge_flag(mr, eed, &data[0]);
3684  data[1] = data[0];
3685  }
3686  if (eve1) {
3687  mesh_render_data_vert_flag(mr, eve1, &data[0]);
3688  }
3689  if (eve2) {
3690  mesh_render_data_vert_flag(mr, eve2, &data[1]);
3691  }
3692  }
3694 }
3695 
3698  void *_data)
3699 {
3700  const int offset = mr->loop_len + (mr->edge_loose_len * 2);
3701  EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
3702  {
3703  EditLoopData *data = (EditLoopData *)_data + offset + lvert_index;
3704  memset(data, 0x0, sizeof(*data));
3705  mesh_render_data_vert_flag(mr, eve, data);
3706  }
3708 }
3709 
3712  void *_data)
3713 {
3714  const int offset = mr->loop_len + (mr->edge_loose_len * 2);
3715  EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
3716  {
3717  EditLoopData *data = (EditLoopData *)_data + offset + lvert_index;
3718  memset(data, 0x0, sizeof(*data));
3719  const int v_index = mr->lverts[lvert_index];
3720  BMVert *eve = bm_original_vert_get(mr, v_index);
3721  if (eve) {
3722  mesh_render_data_vert_flag(mr, eve, data);
3723  }
3724  }
3726 }
3727 
3730  .iter_poly_bm = extract_edit_data_iter_poly_bm,
3731  .iter_poly_mesh = extract_edit_data_iter_poly_mesh,
3732  .iter_ledge_bm = extract_edit_data_iter_ledge_bm,
3733  .iter_ledge_mesh = extract_edit_data_iter_ledge_mesh,
3734  .iter_lvert_bm = extract_edit_data_iter_lvert_bm,
3735  .iter_lvert_mesh = extract_edit_data_iter_lvert_mesh,
3736  .data_flag = 0,
3737  .use_threading = true,
3738 };
3739 
3742 /* ---------------------------------------------------------------------- */
3748  int cd_ofs;
3750 
3752  struct MeshBatchCache *UNUSED(cache),
3753  void *buf)
3754 {
3755  static GPUVertFormat format = {0};
3756  if (format.attr_len == 0) {
3757  /* WARNING: Adjust #EditLoopData struct accordingly. */
3759  GPU_vertformat_alias_add(&format, "flag");
3760  }
3761 
3762  GPUVertBuf *vbo = buf;
3764  GPU_vertbuf_data_alloc(vbo, mr->loop_len);
3765 
3766  CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
3767 
3768  MeshExtract_EditUVData_Data *data = MEM_callocN(sizeof(*data), __func__);
3769  data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
3770  data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV);
3771  return data;
3772 }
3773 
3776  void *_data)
3777 {
3779  {
3781  EditLoopData *eldata = &data->vbo_data[l_index];
3782  memset(eldata, 0x0, sizeof(*eldata));
3783  mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata);
3784  mesh_render_data_face_flag(mr, l->f, data->cd_ofs, eldata);
3785  mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata);
3786  }
3788 }
3789 
3792  void *_data)
3793 {
3795  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
3796  {
3797  EditLoopData *eldata = &data->vbo_data[ml_index];
3798  memset(eldata, 0x0, sizeof(*eldata));
3799  BMFace *efa = bm_original_face_get(mr, mp_index);
3800  if (efa) {
3801  BMEdge *eed = bm_original_edge_get(mr, ml->e);
3802  BMVert *eve = bm_original_vert_get(mr, ml->v);
3803  if (eed && eve) {
3804  /* Loop on an edge endpoint. */
3805  BMLoop *l = BM_face_edge_share_loop(efa, eed);
3806  mesh_render_data_loop_flag(mr, l, data->cd_ofs, eldata);
3807  mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata);
3808  }
3809  else {
3810  if (eed == NULL) {
3811  /* Find if the loop's vert is not part of an edit edge.
3812  * For this, we check if the previous loop was on an edge. */
3813  const int ml_index_last = mp->loopstart + mp->totloop - 1;
3814  const int l_prev = (ml_index == mp->loopstart) ? ml_index_last : (ml_index - 1);
3815  const MLoop *ml_prev = &mr->mloop[l_prev];
3816  eed = bm_original_edge_get(mr, ml_prev->e);
3817  }
3818  if (eed) {
3819  /* Mapped points on an edge between two edit verts. */
3820  BMLoop *l = BM_face_edge_share_loop(efa, eed);
3821  mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, eldata);
3822  }
3823  }
3824  }
3825  }
3827 }
3828 
3830  struct MeshBatchCache *UNUSED(cache),
3831  void *UNUSED(buf),
3832  void *data)
3833 {
3834  MEM_freeN(data);
3835 }
3836 
3839  .iter_poly_bm = extract_edituv_data_iter_poly_bm,
3840  .iter_poly_mesh = extract_edituv_data_iter_poly_mesh,
3841  .finish = extract_edituv_data_finish,
3842  .data_flag = 0,
3843  .use_threading = true,
3844 };
3845 
3848 /* ---------------------------------------------------------------------- */
3853  struct MeshBatchCache *UNUSED(cache),
3854  void *buf)
3855 {
3856  static GPUVertFormat format = {0};
3857  if (format.attr_len == 0) {
3859  }
3860 
3861  GPUVertBuf *vbo = buf;
3863  GPU_vertbuf_data_alloc(vbo, mr->loop_len);
3864 
3865  return NULL;
3866 }
3867 
3868 BLI_INLINE float area_ratio_get(float area, float uvarea)
3869 {
3870  if (area >= FLT_EPSILON && uvarea >= FLT_EPSILON) {
3871  /* Tag inversion by using the sign. */
3872  return (area > uvarea) ? (uvarea / area) : -(area / uvarea);
3873  }
3874  return 0.0f;
3875 }
3876 
3877 BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio)
3878 {
3879  ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio;
3880  return (ratio > 1.0f) ? (1.0f / ratio) : ratio;
3881 }
3882 
3884  struct MeshBatchCache *cache,
3885  void *buf,
3886  void *UNUSED(data))
3887 {
3888  float tot_area = 0.0f, tot_uv_area = 0.0f;
3889  float *area_ratio = MEM_mallocN(sizeof(float) * mr->poly_len, __func__);
3890 
3891  if (mr->extract_type == MR_EXTRACT_BMESH) {
3892  CustomData *cd_ldata = &mr->bm->ldata;
3893  int uv_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV);
3894 
3895  BMFace *efa;
3896  BMIter f_iter;
3897  int f;
3898  BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) {
3899  float area = BM_face_calc_area(efa);
3900  float uvarea = BM_face_calc_area_uv(efa, uv_ofs);
3901  tot_area += area;
3902  tot_uv_area += uvarea;
3903  area_ratio[f] = area_ratio_get(area, uvarea);
3904  }
3905  }
3906  else {
3908  const MLoopUV *uv_data = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
3909  const MPoly *mp = mr->mpoly;
3910  for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
3911  float area = BKE_mesh_calc_poly_area(mp, &mr->mloop[mp->loopstart], mr->mvert);
3912  float uvarea = BKE_mesh_calc_poly_uv_area(mp, uv_data);
3913  tot_area += area;
3914  tot_uv_area += uvarea;
3915  area_ratio[mp_index] = area_ratio_get(area, uvarea);
3916  }
3917  }
3918 
3919  cache->tot_area = tot_area;
3920  cache->tot_uv_area = tot_uv_area;
3921 
3922  /* Convert in place to avoid an extra allocation */
3923  uint16_t *poly_stretch = (uint16_t *)area_ratio;
3924  for (int mp_index = 0; mp_index < mr->poly_len; mp_index++) {
3925  poly_stretch[mp_index] = area_ratio[mp_index] * SHRT_MAX;
3926  }
3927 
3928  /* Copy face data for each loop. */
3929  GPUVertBuf *vbo = buf;
3930  uint16_t *loop_stretch = (uint16_t *)GPU_vertbuf_get_data(vbo);
3931 
3932  if (mr->extract_type == MR_EXTRACT_BMESH) {
3933  BMFace *efa;
3934  BMIter f_iter;
3935  int f, l_index = 0;
3936  BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, f) {
3937  for (int i = 0; i < efa->len; i++, l_index++) {
3938  loop_stretch[l_index] = poly_stretch[f];
3939  }
3940  }
3941  }
3942  else {
3944  const MPoly *mp = mr->mpoly;
3945  for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
3946  for (int i = 0; i < mp->totloop; i++, l_index++) {
3947  loop_stretch[l_index] = poly_stretch[mp_index];
3948  }
3949  }
3950  }
3951 
3952  MEM_freeN(area_ratio);
3953 }
3954 
3958  .data_flag = 0,
3959  .use_threading = false,
3960 };
3961 
3964 /* ---------------------------------------------------------------------- */
3968 typedef struct UVStretchAngle {
3972 
3976  float auv[2][2], last_auv[2];
3977  float av[2][3], last_av[3];
3978  int cd_ofs;
3980 
3981 static void compute_normalize_edge_vectors(float auv[2][2],
3982  float av[2][3],
3983  const float uv[2],
3984  const float uv_prev[2],
3985  const float co[3],
3986  const float co_prev[3])
3987 {
3988  /* Move previous edge. */
3989  copy_v2_v2(auv[0], auv[1]);
3990  copy_v3_v3(av[0], av[1]);
3991  /* 2d edge */
3992  sub_v2_v2v2(auv[1], uv_prev, uv);
3993  normalize_v2(auv[1]);
3994  /* 3d edge */
3995  sub_v3_v3v3(av[1], co_prev, co);
3996  normalize_v3(av[1]);
3997 }
3998 
3999 static short v2_to_short_angle(const float v[2])
4000 {
4001  return atan2f(v[1], v[0]) * (float)M_1_PI * SHRT_MAX;
4002 }
4003 
4004 static void edituv_get_edituv_stretch_angle(float auv[2][2],
4005  const float av[2][3],
4006  UVStretchAngle *r_stretch)
4007 {
4008  /* Send UV's to the shader and let it compute the aspect corrected angle. */
4009  r_stretch->uv_angles[0] = v2_to_short_angle(auv[0]);
4010  r_stretch->uv_angles[1] = v2_to_short_angle(auv[1]);
4011  /* Compute 3D angle here. */
4012  r_stretch->angle = angle_normalized_v3v3(av[0], av[1]) * (float)M_1_PI * SHRT_MAX;
4013 
4014 #if 0 /* here for reference, this is done in shader now. */
4015  float uvang = angle_normalized_v2v2(auv0, auv1);
4016  float ang = angle_normalized_v3v3(av0, av1);
4017  float stretch = fabsf(uvang - ang) / (float)M_PI;
4018  return 1.0f - pow2f(1.0f - stretch);
4019 #endif
4020 }
4021 
4023  struct MeshBatchCache *UNUSED(cache),
4024  void *buf)
4025 {
4026  static GPUVertFormat format = {0};
4027  if (format.attr_len == 0) {
4028  /* Waning: adjust #UVStretchAngle struct accordingly. */
4031  }
4032 
4033  GPUVertBuf *vbo = buf;
4035  GPU_vertbuf_data_alloc(vbo, mr->loop_len);
4036 
4037  MeshExtract_StretchAngle_Data *data = MEM_callocN(sizeof(*data), __func__);
4038  data->vbo_data = (UVStretchAngle *)GPU_vertbuf_get_data(vbo);
4039 
4040  /* Special iterator needed to save about half of the computing cost. */
4041  if (mr->extract_type == MR_EXTRACT_BMESH) {
4042  data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
4043  }
4044  else {
4046  data->luv = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
4047  }
4048  return data;
4049 }
4050 
4053  void *_data)
4054 {
4056  float(*auv)[2] = data->auv, *last_auv = data->last_auv;
4057  float(*av)[3] = data->av, *last_av = data->last_av;
4059  {
4060  const MLoopUV *luv, *luv_next;
4061  BMLoop *l_next = l->next;
4062  BMFace *efa = l->f;
4063  if (l == BM_FACE_FIRST_LOOP(efa)) {
4064  /* First loop in face. */
4065  BMLoop *l_tmp = l->prev;
4066  BMLoop *l_next_tmp = l;
4067  luv = BM_ELEM_CD_GET_VOID_P(l_tmp, data->cd_ofs);
4068  luv_next = BM_ELEM_CD_GET_VOID_P(l_next_tmp, data->cd_ofs);
4070  av,
4071  luv->uv,
4072  luv_next->uv,
4073  bm_vert_co_get(mr, l_tmp->v),
4074  bm_vert_co_get(mr, l_next_tmp->v));
4075  /* Save last edge. */
4076  copy_v2_v2(last_auv, auv[1]);
4077  copy_v3_v3(last_av, av[1]);
4078  }
4079  if (l_next == BM_FACE_FIRST_LOOP(efa)) {
4080  /* Move previous edge. */
4081  copy_v2_v2(auv[0], auv[1]);
4082  copy_v3_v3(av[0], av[1]);
4083  /* Copy already calculated last edge. */
4084  copy_v2_v2(auv[1], last_auv);
4085  copy_v3_v3(av[1], last_av);
4086  }
4087  else {
4088  luv = BM_ELEM_CD_GET_VOID_P(l, data->cd_ofs);
4089  luv_next = BM_ELEM_CD_GET_VOID_P(l_next, data->cd_ofs);
4091  auv, av, luv->uv, luv_next->uv, bm_vert_co_get(mr, l->v), bm_vert_co_get(mr, l_next->v));
4092  }
4093  edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[l_index]);
4094  }
4096 }
4097 
4100  void *_data)
4101 {
4103 
4104  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
4105  {
4106  float(*auv)[2] = data->auv, *last_auv = data->last_auv;
4107  float(*av)[3] = data->av, *last_av = data->last_av;
4108  int l_next = ml_index + 1, ml_index_end = mp->loopstart + mp->totloop;
4109  const MVert *v, *v_next;
4110  if (ml_index == mp->loopstart) {
4111  /* First loop in face. */
4112  const int ml_index_last = ml_index_end - 1;
4113  const int l_next_tmp = mp->loopstart;
4114  v = &mr->mvert[mr->mloop[ml_index_last].v];
4115  v_next = &mr->mvert[mr->mloop[l_next_tmp].v];
4117  auv, av, data->luv[ml_index_last].uv, data->luv[l_next_tmp].uv, v->co, v_next->co);
4118  /* Save last edge. */
4119  copy_v2_v2(last_auv, auv[1]);
4120  copy_v3_v3(last_av, av[1]);
4121  }
4122  if (l_next == ml_index_end) {
4123  l_next = mp->loopstart;
4124  /* Move previous edge. */
4125  copy_v2_v2(auv[0], auv[1]);
4126  copy_v3_v3(av[0], av[1]);
4127  /* Copy already calculated last edge. */
4128  copy_v2_v2(auv[1], last_auv);
4129  copy_v3_v3(av[1], last_av);
4130  }
4131  else {
4132  v = &mr->mvert[mr->mloop[ml_index].v];
4133  v_next = &mr->mvert[mr->mloop[l_next].v];
4135  auv, av, data->luv[ml_index].uv, data->luv[l_next].uv, v->co, v_next->co);
4136  }
4137  edituv_get_edituv_stretch_angle(auv, av, &data->vbo_data[ml_index]);
4138  }
4140 }
4141 
4143  struct MeshBatchCache *UNUSED(cache),
4144  void *UNUSED(buf),
4145  void *data)
4146 {
4147  MEM_freeN(data);
4148 }
4149 
4155  .data_flag = 0,
4156  .use_threading = false,
4157 };
4158 
4161 /* ---------------------------------------------------------------------- */
4166  struct MeshBatchCache *UNUSED(cache),
4167  void *buf)
4168 {
4169  static GPUVertFormat format = {0};
4170  if (format.attr_len == 0) {
4172  }
4173 
4174  GPUVertBuf *vbo = buf;
4176  GPU_vertbuf_data_alloc(vbo, mr->loop_len);
4177 
4178  return NULL;
4179 }
4180 
4181 static void axis_from_enum_v3(float v[3], const char axis)
4182 {
4183  zero_v3(v);
4184  if (axis < 3) {
4185  v[axis] = 1.0f;
4186  }
4187  else {
4188  v[axis - 3] = -1.0f;
4189  }
4190 }
4191 
4192 BLI_INLINE float overhang_remap(float fac, float min, float max, float minmax_irange)
4193 {
4194  if (fac < min) {
4195  fac = 1.0f;
4196  }
4197  else if (fac > max) {
4198  fac = -1.0f;
4199  }
4200  else {
4201  fac = (fac - min) * minmax_irange;
4202  fac = 1.0f - fac;
4203  CLAMP(fac, 0.0f, 1.0f);
4204  }
4205  return fac;
4206 }
4207 
4208 static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang)
4209 {
4210  const MeshStatVis *statvis = &mr->toolsettings->statvis;
4211  const float min = statvis->overhang_min / (float)M_PI;
4212  const float max = statvis->overhang_max / (float)M_PI;
4213  const char axis = statvis->overhang_axis;
4214  BMEditMesh *em = mr->edit_bmesh;
4215  BMIter iter;
4216  BMesh *bm = em->bm;
4217  BMFace *f;
4218  float dir[3];
4219  const float minmax_irange = 1.0f / (max - min);
4220 
4221  BLI_assert(min <= max);
4222 
4223  axis_from_enum_v3(dir, axis);
4224 
4225  /* now convert into global space */
4226  mul_transposed_mat3_m4_v3(mr->obmat, dir);
4227  normalize_v3(dir);
4228 
4229  if (mr->extract_type == MR_EXTRACT_BMESH) {
4230  int l_index = 0;
4231  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
4232  float fac = angle_normalized_v3v3(bm_face_no_get(mr, f), dir) / (float)M_PI;
4233  fac = overhang_remap(fac, min, max, minmax_irange);
4234  for (int i = 0; i < f->len; i++, l_index++) {
4235  r_overhang[l_index] = fac;
4236  }
4237  }
4238  }
4239  else {
4240  const MPoly *mp = mr->mpoly;
4241  for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
4242  float fac = angle_normalized_v3v3(mr->poly_normals[mp_index], dir) / (float)M_PI;
4243  fac = overhang_remap(fac, min, max, minmax_irange);
4244  for (int i = 0; i < mp->totloop; i++, l_index++) {
4245  r_overhang[l_index] = fac;
4246  }
4247  }
4248  }
4249 }
4250 
4254 static void uv_from_jitter_v2(float uv[2])
4255 {
4256  uv[0] += 0.5f;
4257  uv[1] += 0.5f;
4258  if (uv[0] + uv[1] > 1.0f) {
4259  uv[0] = 1.0f - uv[0];
4260  uv[1] = 1.0f - uv[1];
4261  }
4262 
4263  clamp_v2(uv, 0.0f, 1.0f);
4264 }
4265 
4266 BLI_INLINE float thickness_remap(float fac, float min, float max, float minmax_irange)
4267 {
4268  /* important not '<=' */
4269  if (fac < max) {
4270  fac = (fac - min) * minmax_irange;
4271  fac = 1.0f - fac;
4272  CLAMP(fac, 0.0f, 1.0f);
4273  }
4274  else {
4275  fac = -1.0f;
4276  }
4277  return fac;
4278 }
4279 
4280 static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness)
4281 {
4282  const float eps_offset = 0.00002f; /* values <= 0.00001 give errors */
4283  /* cheating to avoid another allocation */
4284  float *face_dists = r_thickness + (mr->loop_len - mr->poly_len);
4285  BMEditMesh *em = mr->edit_bmesh;
4286  const float scale = 1.0f / mat4_to_scale(mr->obmat);
4287  const MeshStatVis *statvis = &mr->toolsettings->statvis;
4288  const float min = statvis->thickness_min * scale;
4289  const float max = statvis->thickness_max * scale;
4290  const float minmax_irange = 1.0f / (max - min);
4291  const int samples = statvis->thickness_samples;
4292  float jit_ofs[32][2];
4293  BLI_assert(samples <= 32);
4294  BLI_assert(min <= max);
4295 
4296  copy_vn_fl(face_dists, mr->poly_len, max);
4297 
4298  BLI_jitter_init(jit_ofs, samples);
4299  for (int j = 0; j < samples; j++) {
4300  uv_from_jitter_v2(jit_ofs[j]);
4301  }
4302 
4303  if (mr->extract_type == MR_EXTRACT_BMESH) {
4304  BMesh *bm = em->bm;
4306 
4307  struct BMBVHTree *bmtree = BKE_bmbvh_new_from_editmesh(em, 0, NULL, false);
4308  struct BMLoop *(*looptris)[3] = em->looptris;
4309  for (int i = 0; i < mr->tri_len; i++) {
4310  BMLoop **ltri = looptris[i];
4311  const int index = BM_elem_index_get(ltri[0]->f);
4312  const float *cos[3] = {
4313  bm_vert_co_get(mr, ltri[0]->v),
4314  bm_vert_co_get(mr, ltri[1]->v),
4315  bm_vert_co_get(mr, ltri[2]->v),
4316  };
4317  float ray_co[3];
4318  float ray_no[3];
4319 
4320  normal_tri_v3(ray_no, cos[2], cos[1], cos[0]);
4321 
4322  for (int j = 0; j < samples; j++) {
4323  float dist = face_dists[index];
4324  interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]);
4325  madd_v3_v3fl(ray_co, ray_no, eps_offset);
4326 
4327  BMFace *f_hit = BKE_bmbvh_ray_cast(bmtree, ray_co, ray_no, 0.0f, &dist, NULL, NULL);
4328  if (f_hit && dist < face_dists[index]) {
4329  float angle_fac = fabsf(
4330  dot_v3v3(bm_face_no_get(mr, ltri[0]->f), bm_face_no_get(mr, f_hit)));
4331  angle_fac = 1.0f - angle_fac;
4332  angle_fac = angle_fac * angle_fac * angle_fac;
4333  angle_fac = 1.0f - angle_fac;
4334  dist /= angle_fac;
4335  if (dist < face_dists[index]) {
4336  face_dists[index] = dist;
4337  }
4338  }
4339  }
4340  }
4341  BKE_bmbvh_free(bmtree);
4342 
4343  BMIter iter;
4344  BMFace *f;
4345  int l_index = 0;
4346  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
4347  float fac = face_dists[BM_elem_index_get(f)];
4348  fac = thickness_remap(fac, min, max, minmax_irange);
4349  for (int i = 0; i < f->len; i++, l_index++) {
4350  r_thickness[l_index] = fac;
4351  }
4352  }
4353  }
4354  else {
4355  BVHTreeFromMesh treeData = {NULL};
4356 
4358  const MLoopTri *mlooptri = mr->mlooptri;
4359  for (int i = 0; i < mr->tri_len; i++, mlooptri++) {
4360  const int index = mlooptri->poly;
4361  const float *cos[3] = {mr->mvert[mr->mloop[mlooptri->tri[0]].v].co,
4362  mr->mvert[mr->mloop[mlooptri->tri[1]].v].co,
4363  mr->mvert[mr->mloop[mlooptri->tri[2]].v].co};
4364  float ray_co[3];
4365  float ray_no[3];
4366 
4367  normal_tri_v3(ray_no, cos[2], cos[1], cos[0]);
4368 
4369  for (int j = 0; j < samples; j++) {
4370  interp_v3_v3v3v3_uv(ray_co, cos[0], cos[1], cos[2], jit_ofs[j]);
4371  madd_v3_v3fl(ray_co, ray_no, eps_offset);
4372 
4373  BVHTreeRayHit hit;
4374  hit.index = -1;
4375  hit.dist = face_dists[index];
4376  if ((BLI_bvhtree_ray_cast(
4377  tree, ray_co, ray_no, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) &&
4378  hit.dist < face_dists[index]) {
4379  float angle_fac = fabsf(dot_v3v3(mr->poly_normals[index], hit.no));
4380  angle_fac = 1.0f - angle_fac;
4381  angle_fac = angle_fac * angle_fac * angle_fac;
4382  angle_fac = 1.0f - angle_fac;
4383  hit.dist /= angle_fac;
4384  if (hit.dist < face_dists[index]) {
4385  face_dists[index] = hit.dist;
4386  }
4387  }
4388  }
4389  }
4390 
4391  const MPoly *mp = mr->mpoly;
4392  for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
4393  float fac = face_dists[mp_index];
4394  fac = thickness_remap(fac, min, max, minmax_irange);
4395  for (int i = 0; i < mp->totloop; i++, l_index++) {
4396  r_thickness[l_index] = fac;
4397  }
4398  }
4399  }
4400 }
4401 
4403  const Mesh *me;
4405  float epsilon;
4406 };
4407 
4408 static bool bvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
4409 {
4410  struct BVHTree_OverlapData *data = userdata;
4411  const Mesh *me = data->me;
4412 
4413  const MLoopTri *tri_a = &data->mlooptri[index_a];
4414  const MLoopTri *tri_b = &data->mlooptri[index_b];
4415 
4416  if (UNLIKELY(tri_a->poly == tri_b->poly)) {
4417  return false;
4418  }
4419 
4420  const float *tri_a_co[3] = {me->mvert[me->mloop[tri_a->tri[0]].v].co,
4421  me->mvert[me->mloop[tri_a->tri[1]].v].co,
4422  me->mvert[me->mloop[tri_a->tri[2]].v].co};
4423  const float *tri_b_co[3] = {me->mvert[me->mloop[tri_b->tri[0]].v].co,
4424  me->mvert[me->mloop[tri_b->tri[1]].v].co,
4425  me->mvert[me->mloop[tri_b->tri[2]].v].co};
4426  float ix_pair[2][3];
4427  int verts_shared = 0;
4428 
4429  verts_shared = (ELEM(tri_a_co[0], UNPACK3(tri_b_co)) + ELEM(tri_a_co[1], UNPACK3(tri_b_co)) +
4430  ELEM(tri_a_co[2], UNPACK3(tri_b_co)));
4431 
4432  /* if 2 points are shared, bail out */
4433  if (verts_shared >= 2) {
4434  return false;
4435  }
4436 
4437  return (isect_tri_tri_v3(UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1]) &&
4438  /* if we share a vertex, check the intersection isn't a 'point' */
4439  ((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
4440 }
4441 
4442 static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect)
4443 {
4444  BMEditMesh *em = mr->edit_bmesh;
4445 
4446  for (int l_index = 0; l_index < mr->loop_len; l_index++) {
4447  r_intersect[l_index] = -1.0f;
4448  }
4449 
4450  if (mr->extract_type == MR_EXTRACT_BMESH) {
4451  uint overlap_len;
4452  BMesh *bm = em->bm;
4453 
4455 
4456  struct BMBVHTree *bmtree = BKE_bmbvh_new_from_editmesh(em, 0, NULL, false);
4457  BVHTreeOverlap *overlap = BKE_bmbvh_overlap_self(bmtree, &overlap_len);
4458 
4459  if (overlap) {
4460  for (int i = 0; i < overlap_len; i++) {
4461  BMFace *f_hit_pair[2] = {
4462  em->looptris[overlap[i].indexA][0]->f,
4463  em->looptris[overlap[i].indexB][0]->f,
4464  };
4465  for (int j = 0; j < 2; j++) {
4466  BMFace *f_hit = f_hit_pair[j];
4467  BMLoop *l_first = BM_FACE_FIRST_LOOP(f_hit);
4468  int l_index = BM_elem_index_get(l_first);
4469  for (int k = 0; k < f_hit->len; k++, l_index++) {
4470  r_intersect[l_index] = 1.0f;
4471  }
4472  }
4473  }
4474  MEM_freeN(overlap);
4475  }
4476 
4477  BKE_bmbvh_free(bmtree);
4478  }
4479  else {
4480  uint overlap_len;
4481  BVHTreeFromMesh treeData = {NULL};
4482 
4484 
4485  struct BVHTree_OverlapData data = {
4486  .me = mr->me, .mlooptri = mr->mlooptri, .epsilon = BLI_bvhtree_get_epsilon(tree)};
4487 
4488  BVHTreeOverlap *overlap = BLI_bvhtree_overlap(tree, tree, &overlap_len, bvh_overlap_cb, &data);
4489  if (overlap) {
4490  for (int i = 0; i < overlap_len; i++) {
4491  const MPoly *f_hit_pair[2] = {
4492  &mr->mpoly[mr->mlooptri[overlap[i].indexA].poly],
4493  &mr->mpoly[mr->mlooptri[overlap[i].indexB].poly],
4494  };
4495  for (int j = 0; j < 2; j++) {
4496  const MPoly *f_hit = f_hit_pair[j];
4497  int l_index = f_hit->loopstart;
4498  for (int k = 0; k < f_hit->totloop; k++, l_index++) {
4499  r_intersect[l_index] = 1.0f;
4500  }
4501  }
4502  }
4503  MEM_freeN(overlap);
4504  }
4505  }
4506 }
4507 
4508 BLI_INLINE float distort_remap(float fac, float min, float UNUSED(max), float minmax_irange)
4509 {
4510  if (fac >= min) {
4511  fac = (fac - min) * minmax_irange;
4512  CLAMP(fac, 0.0f, 1.0f);
4513  }
4514  else {
4515  /* fallback */
4516  fac = -1.0f;
4517  }
4518  return fac;
4519 }
4520 
4521 static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort)
4522 {
4523  BMEditMesh *em = mr->edit_bmesh;
4524  const MeshStatVis *statvis = &mr->toolsettings->statvis;
4525  const float min = statvis->distort_min;
4526  const float max = statvis->distort_max;
4527  const float minmax_irange = 1.0f / (max - min);
4528 
4529  if (mr->extract_type == MR_EXTRACT_BMESH) {
4530  BMIter iter;
4531  BMesh *bm = em->bm;
4532  BMFace *f;
4533 
4534  if (mr->bm_vert_coords != NULL) {
4536 
4537  /* Most likely this is already valid, ensure just in case.
4538  * Needed for #BM_loop_calc_face_normal_safe_vcos. */
4540  }
4541 
4542  int l_index = 0;
4543  int f_index = 0;
4544  BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, f_index) {
4545  float fac = -1.0f;
4546 
4547  if (f->len > 3) {
4548  BMLoop *l_iter, *l_first;
4549 
4550  fac = 0.0f;
4551  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
4552  do {
4553  const float *no_face;
4554  float no_corner[3];
4555  if (mr->bm_vert_coords != NULL) {
4556  no_face = mr->bm_poly_normals[f_index];
4557  BM_loop_calc_face_normal_safe_vcos(l_iter, no_face, mr->bm_vert_coords, no_corner);
4558  }
4559  else {
4560  no_face = f->no;
4561  BM_loop_calc_face_normal_safe(l_iter, no_corner);
4562  }
4563 
4564  /* simple way to detect (what is most likely) concave */
4565  if (dot_v3v3(no_face, no_corner) < 0.0f) {
4566  negate_v3(no_corner);
4567  }
4568  fac = max_ff(fac, angle_normalized_v3v3(no_face, no_corner));
4569 
4570  } while ((l_iter = l_iter->next) != l_first);
4571  fac *= 2.0f;
4572  }
4573 
4574  fac = distort_remap(fac, min, max, minmax_irange);
4575  for (int i = 0; i < f->len; i++, l_index++) {
4576  r_distort[l_index] = fac;
4577  }
4578  }
4579  }
4580  else {
4581  const MPoly *mp = mr->mpoly;
4582  for (int mp_index = 0, l_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
4583  float fac = -1.0f;
4584 
4585  if (mp->totloop > 3) {
4586  float *f_no = mr->poly_normals[mp_index];
4587  fac = 0.0f;
4588 
4589  for (int i = 1; i <= mp->totloop; i++) {
4590  const MLoop *l_prev = &mr->mloop[mp->loopstart + (i - 1) % mp->totloop];
4591  const MLoop *l_curr = &mr->mloop[mp->loopstart + (i + 0) % mp->totloop];
4592  const MLoop *l_next = &mr->mloop[mp->loopstart + (i + 1) % mp->totloop];
4593  float no_corner[3];
4594  normal_tri_v3(no_corner,
4595  mr->mvert[l_prev->v].co,
4596  mr->mvert[l_curr->v].co,
4597  mr->mvert[l_next->v].co);
4598  /* simple way to detect (what is most likely) concave */
4599  if (dot_v3v3(f_no, no_corner) < 0.0f) {
4600  negate_v3(no_corner);
4601  }
4602  fac = max_ff(fac, angle_normalized_v3v3(f_no, no_corner));
4603  }
4604  fac *= 2.0f;
4605  }
4606 
4607  fac = distort_remap(fac, min, max, minmax_irange);
4608  for (int i = 0; i < mp->totloop; i++, l_index++) {
4609  r_distort[l_index] = fac;
4610  }
4611  }
4612  }
4613 }
4614 
4615 BLI_INLINE float sharp_remap(float fac, float min, float UNUSED(max), float minmax_irange)
4616 {
4617  /* important not '>=' */
4618  if (fac > min) {
4619  fac = (fac - min) * minmax_irange;
4620  CLAMP(fac, 0.0f, 1.0f);
4621  }
4622  else {
4623  /* fallback */
4624  fac = -1.0f;
4625  }
4626  return fac;
4627 }
4628 
4629 static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp)
4630 {
4631  BMEditMesh *em = mr->edit_bmesh;
4632  const MeshStatVis *statvis = &mr->toolsettings->statvis;
4633  const float min = statvis->sharp_min;
4634  const float max = statvis->sharp_max;
4635  const float minmax_irange = 1.0f / (max - min);
4636 
4637  /* Can we avoid this extra allocation? */
4638  float *vert_angles = MEM_mallocN(sizeof(float) * mr->vert_len, __func__);
4639  copy_vn_fl(vert_angles, mr->vert_len, -M_PI);
4640 
4641  if (mr->extract_type == MR_EXTRACT_BMESH) {
4642  BMIter iter;
4643  BMesh *bm = em->bm;
4644  BMFace *efa;
4645  BMEdge *e;
4646  /* first assign float values to verts */
4647  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
4649  float *col1 = &vert_angles[BM_elem_index_get(e->v1)];
4650  float *col2 = &vert_angles[BM_elem_index_get(e->v2)];
4651  *col1 = max_ff(*col1, angle);
4652  *col2 = max_ff(*col2, angle);
4653  }
4654  /* Copy vert value to loops. */
4655  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
4656  BMLoop *l_iter, *l_first;
4657  l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
4658  do {
4659  int l_index = BM_elem_index_get(l_iter);
4660  int v_index = BM_elem_index_get(l_iter->v);
4661  r_sharp[l_index] = sharp_remap(vert_angles[v_index], min, max, minmax_irange);
4662  } while ((l_iter = l_iter->next) != l_first);
4663  }
4664  }
4665  else {
4666  /* first assign float values to verts */
4667  const MPoly *mp = mr->mpoly;
4668 
4669  EdgeHash *eh = BLI_edgehash_new_ex(__func__, mr->edge_len);
4670 
4671  for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) {
4672  for (int i = 0; i < mp->totloop; i++) {
4673  const MLoop *l_curr = &mr->mloop[mp->loopstart + (i + 0) % mp->totloop];
4674  const MLoop *l_next = &mr->mloop[mp->loopstart + (i + 1) % mp->totloop];
4675  const MVert *v_curr = &mr->mvert[l_curr->v];
4676  const MVert *v_next = &mr->mvert[l_next->v];
4677  float angle;
4678  void **pval;
4679  bool value_is_init = BLI_edgehash_ensure_p(eh, l_curr->v, l_next->v, &pval);
4680  if (!value_is_init) {
4681  *pval = mr->poly_normals[mp_index];
4682  /* non-manifold edge, yet... */
4683  continue;
4684  }
4685  if (*pval != NULL) {
4686  const float *f1_no = mr->poly_normals[mp_index];
4687  const float *f2_no = *pval;
4688  angle = angle_normalized_v3v3(f1_no, f2_no);
4689  angle = is_edge_convex_v3(v_curr->co, v_next->co, f1_no, f2_no) ? angle : -angle;
4690  /* Tag as manifold. */
4691  *pval = NULL;
4692  }
4693  else {
4694  /* non-manifold edge */
4695  angle = DEG2RADF(90.0f);
4696  }
4697  float *col1 = &vert_angles[l_curr->v];
4698  float *col2 = &vert_angles[l_next->v];
4699  *col1 = max_ff(*col1, angle);
4700  *col2 = max_ff(*col2, angle);
4701  }
4702  }
4703  /* Remaining non manifold edges. */
4706  if (BLI_edgehashIterator_getValue(ehi) != NULL) {
4707  uint v1, v2;
4708  const float angle = DEG2RADF(90.0f);
4710  float *col1 = &vert_angles[v1];
4711  float *col2 = &vert_angles[v2];
4712  *col1 = max_ff(*col1, angle);
4713  *col2 = max_ff(*col2, angle);
4714  }
4715  }
4717  BLI_edgehash_free(eh, NULL);
4718 
4719  const MLoop *ml = mr->mloop;
4720  for (int l_index = 0; l_index < mr->loop_len; l_index++, ml++) {
4721  r_sharp[l_index] = sharp_remap(vert_angles[ml->v], min, max, minmax_irange);
4722  }
4723  }
4724 
4725  MEM_freeN(vert_angles);
4726 }
4727 
4729  struct MeshBatchCache *UNUSED(cache),
4730  void *buf,
4731  void *UNUSED(data))
4732 {
4733  BLI_assert(mr->edit_bmesh);
4734 
4735  GPUVertBuf *vbo = buf;
4736  float *l_weight = (float *)GPU_vertbuf_get_data(vbo);
4737 
4738  switch (mr->toolsettings->statvis.type) {
4739  case SCE_STATVIS_OVERHANG:
4740  statvis_calc_overhang(mr, l_weight);
4741  break;
4742  case SCE_STATVIS_THICKNESS:
4743  statvis_calc_thickness(mr, l_weight);
4744  break;
4745  case SCE_STATVIS_INTERSECT:
4746  statvis_calc_intersect(mr, l_weight);
4747  break;
4748  case SCE_STATVIS_DISTORT:
4749  statvis_calc_distort(mr, l_weight);
4750  break;
4751  case SCE_STATVIS_SHARP:
4752  statvis_calc_sharp(mr, l_weight);
4753  break;
4754  }
4755 }
4756 
4759  .finish = extract_mesh_analysis_finish,
4760  /* This is not needed for all visualization types.
4761  * * Maybe split into different extract. */
4762  .data_flag = MR_DATA_POLY_NOR | MR_DATA_LOOPTRI,
4763  .use_threading = false,
4764 };
4765 
4768 /* ---------------------------------------------------------------------- */
4773  struct MeshBatchCache *UNUSED(cache),
4774  void *buf)
4775 {
4776  static GPUVertFormat format = {0};
4777  if (format.attr_len == 0) {
4779  }
4780  GPUVertBuf *vbo = buf;
4782  GPU_vertbuf_data_alloc(vbo, mr->poly_len);
4783  return GPU_vertbuf_get_data(vbo);
4784 }
4785 
4788  void *data)
4789 {
4790  float(*center)[3] = data;
4791 
4792  EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
4793  {
4794  float *co = center[f_index];
4795  zero_v3(co);
4796 
4797  BMLoop *l_iter, *l_first;
4798  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
4799  do {
4800  add_v3_v3(co, bm_vert_co_get(mr, l_iter->v));
4801  } while ((l_iter = l_iter->next) != l_first);
4802  mul_v3_fl(co, 1.0f / (float)f->len);
4803  }
4805 }
4806 
4809  void *data)
4810 {
4811  float(*center)[3] = (float(*)[3])data;
4812  const MVert *mvert = mr->mvert;
4813  const MLoop *mloop = mr->mloop;
4814 
4815  if (mr->use_subsurf_fdots) {
4816  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
4817  {
4818  const MVert *mv = &mr->mvert[ml->v];
4819  if (mv->flag & ME_VERT_FACEDOT) {
4820  copy_v3_v3(center[mp_index], mv->co);
4821  }
4822  }
4824  }
4825  else {
4826  EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
4827  {
4828  float *co = center[mp_index];
4829  zero_v3(co);
4830 
4831  const MLoop *ml = &mloop[mp->loopstart];
4832  for (int i = 0; i < mp->totloop; i++, ml++) {
4833  const MVert *mv = &mvert[ml->v];
4834  add_v3_v3(center[mp_index], mv->co);
4835  }
4836  mul_v3_fl(co, 1.0f / (float)mp->totloop);
4837  }
4839  }
4840 }
4841 
4844  .iter_poly_bm = extract_fdots_pos_iter_poly_bm,
4845  .iter_poly_mesh = extract_fdots_pos_iter_poly_mesh,
4846  .data_flag = 0,
4847  .use_threading = true,
4848 };
4849 
4852 /* ---------------------------------------------------------------------- */
4855 #define NOR_AND_FLAG_DEFAULT 0
4856 #define NOR_AND_FLAG_SELECT 1
4857 #define NOR_AND_FLAG_ACTIVE -1
4858 #define NOR_AND_FLAG_HIDDEN -2
4859 
4861  struct MeshBatchCache *UNUSED(cache),
4862  void *buf)
4863 {
4864  static GPUVertFormat format = {0};
4865  if (format.attr_len == 0) {
4867  }
4868  GPUVertBuf *vbo = buf;
4870  GPU_vertbuf_data_alloc(vbo, mr->poly_len);
4871 
4872  return NULL;
4873 }
4874 
4876  struct MeshBatchCache *UNUSED(cache),
4877  void *buf,
4878  void *UNUSED(data))
4879 {
4880  static float invalid_normal[3] = {0.0f, 0.0f, 0.0f};
4881  GPUVertBuf *vbo = buf;
4883  BMFace *efa;
4884 
4885  /* Quicker than doing it for each loop. */
4886  if (mr->extract_type == MR_EXTRACT_BMESH) {
4887  for (int f = 0; f < mr->poly_len; f++) {
4888  efa = BM_face_at_index(mr->bm, f);
4889  const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
4890  if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
4891  mr->p_origindex[f] == ORIGINDEX_NONE)) {
4892  nor[f] = GPU_normal_convert_i10_v3(invalid_normal);
4893  nor[f].w = NOR_AND_FLAG_HIDDEN;
4894  }
4895  else {
4897  /* Select / Active Flag. */
4898  nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
4899  ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
4901  }
4902  }
4903  }
4904  else {
4905  for (int f = 0; f < mr->poly_len; f++) {
4906  efa = bm_original_face_get(mr, f);
4907  const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
4908  if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
4909  mr->p_origindex[f] == ORIGINDEX_NONE)) {
4910  nor[f] = GPU_normal_convert_i10_v3(invalid_normal);
4911  nor[f].w = NOR_AND_FLAG_HIDDEN;
4912  }
4913  else {
4915  /* Select / Active Flag. */
4916  nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
4917  ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
4919  }
4920  }
4921  }
4922 }
4923 
4926  .finish = extract_fdots_nor_finish,
4927  .data_flag = MR_DATA_POLY_NOR,
4928  .use_threading = false,
4929 };
4930 
4933 /* ---------------------------------------------------------------------- */
4937  struct MeshBatchCache *UNUSED(cache),
4938  void *buf)
4939 {
4940  static GPUVertFormat format = {0};
4941  if (format.attr_len == 0) {
4943  }
4944  GPUVertBuf *vbo = buf;
4946  GPU_vertbuf_data_alloc(vbo, mr->poly_len);
4947 
4948  return NULL;
4949 }
4950 
4952  struct MeshBatchCache *UNUSED(cache),
4953  void *buf,
4954  void *UNUSED(data))
4955 {
4956  static float invalid_normal[3] = {0.0f, 0.0f, 0.0f};
4957  GPUVertBuf *vbo = buf;
4958  short *nor = (short *)GPU_vertbuf_get_data(vbo);
4959  BMFace *efa;
4960 
4961  /* Quicker than doing it for each loop. */
4962  if (mr->extract_type == MR_EXTRACT_BMESH) {
4963  for (int f = 0; f < mr->poly_len; f++) {
4964  efa = BM_face_at_index(mr->bm, f);
4965  const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
4966  if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
4967  mr->p_origindex[f] == ORIGINDEX_NONE)) {
4968  normal_float_to_short_v3(&nor[f * 4], invalid_normal);
4969  nor[f * 4 + 3] = NOR_AND_FLAG_HIDDEN;
4970  }
4971  else {
4972  normal_float_to_short_v3(&nor[f * 4], bm_face_no_get(mr, efa));
4973  /* Select / Active Flag. */
4974  nor[f * 4 + 3] = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
4975  ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
4977  }
4978  }
4979  }
4980  else {
4981  for (int f = 0; f < mr->poly_len; f++) {
4982  efa = bm_original_face_get(mr, f);
4983  const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
4984  if (is_face_hidden || (mr->extract_type == MR_EXTRACT_MAPPED && mr->p_origindex &&
4985  mr->p_origindex[f] == ORIGINDEX_NONE)) {
4986  normal_float_to_short_v3(&nor[f * 4], invalid_normal);
4987  nor[f * 4 + 3] = NOR_AND_FLAG_HIDDEN;
4988  }
4989  else {
4990  normal_float_to_short_v3(&nor[f * 4], bm_face_no_get(mr, efa));
4991  /* Select / Active Flag. */
4992  nor[f * 4 + 3] = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
4993  ((efa == mr->efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
4995  }
4996  }
4997  }
4998 }
4999 
5002  .finish = extract_fdots_nor_hq_finish,
5003  .data_flag = MR_DATA_POLY_NOR,
5004  .use_threading = false,
5005 };
5006 
5009 /* ---------------------------------------------------------------------- */
5013 typedef struct MeshExtract_FdotUV_Data {
5016  int cd_ofs;
5018 
5019 static void *extract_fdots_uv_init(const MeshRenderData *mr,
5020  struct MeshBatchCache *UNUSED(cache),
5021  void *buf)
5022 {
5023  static GPUVertFormat format = {0};
5024  if (format.attr_len == 0) {
5028  }
5029  GPUVertBuf *vbo = buf;
5031  GPU_vertbuf_data_alloc(vbo, mr->poly_len);
5032 
5033  if (!mr->use_subsurf_fdots) {
5034  /* Clear so we can accumulate on it. */
5035  memset(GPU_vertbuf_get_data(vbo), 0x0, mr->poly_len * GPU_vertbuf_get_format(vbo)->stride);
5036  }
5037 
5038  MeshExtract_FdotUV_Data *data = MEM_callocN(sizeof(*data), __func__);
5039  data->vbo_data = (float(*)[2])GPU_vertbuf_get_data(vbo);
5040 
5041  if (mr->extract_type == MR_EXTRACT_BMESH) {
5042  data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
5043  }
5044  else {
5045  data->uv_data = CustomData_get_layer(&mr->me->ldata, CD_MLOOPUV);
5046  }
5047  return data;
5048 }
5049 
5052  void *_data)
5053 {
5054  MeshExtract_FdotUV_Data *data = _data;
5056  {
5057  float w = 1.0f / (float)l->f->len;
5058  const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, data->cd_ofs);
5059  madd_v2_v2fl(data->vbo_data[BM_elem_index_get(l->f)], luv->uv, w);
5060  }
5062 }
5063 
5066  void *_data)
5067 {
5068  MeshExtract_FdotUV_Data *data = _data;
5069  if (mr->use_subsurf_fdots) {
5070  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
5071  {
5072  const MVert *mv = &mr->mvert[ml->v];
5073  if (mv->flag & ME_VERT_FACEDOT) {
5074  copy_v2_v2(data->vbo_data[mp_index], data->uv_data[ml_index].uv);
5075  }
5076  }
5078  }
5079  else {
5080  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
5081  {
5082  float w = 1.0f / (float)mp->totloop;
5083  madd_v2_v2fl(data->vbo_data[mp_index], data->uv_data[ml_index].uv, w);
5084  }
5086  }
5087 }
5088 
5090  struct MeshBatchCache *UNUSED(cache),
5091  void *UNUSED(buf),
5092  void *data)
5093 {
5094  MEM_freeN(data);
5095 }
5096 
5099  .iter_poly_bm = extract_fdots_uv_iter_poly_bm,
5100  .iter_poly_mesh = extract_fdots_uv_iter_poly_mesh,
5101  .finish = extract_fdots_uv_finish,
5102  .data_flag = 0,
5103  .use_threading = true,
5104 };
5107 /* ---------------------------------------------------------------------- */
5113  int cd_ofs;
5115 
5117  struct MeshBatchCache *UNUSED(cache),
5118  void *buf)
5119 {
5120  static GPUVertFormat format = {0};
5121  if (format.attr_len == 0) {
5123  }
5124  GPUVertBuf *vbo = buf;
5126  GPU_vertbuf_data_alloc(vbo, mr->poly_len);
5127 
5128  MeshExtract_EditUVFdotData_Data *data = MEM_callocN(sizeof(*data), __func__);
5129  data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
5130  data->cd_ofs = CustomData_get_offset(&mr->bm->ldata, CD_MLOOPUV);
5131  return data;
5132 }
5133 
5136  void *_data)
5137 {
5139  EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
5140  {
5141  EditLoopData *eldata = &data->vbo_data[BM_elem_index_get(f)];
5142  memset(eldata, 0x0, sizeof(*eldata));
5143  mesh_render_data_face_flag(mr, f, data->cd_ofs, eldata);
5144  }
5146 }
5147 
5150  void *_data)
5151 {
5153  EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
5154  {
5155  EditLoopData *eldata = &data->vbo_data[mp_index];
5156  memset(eldata, 0x0, sizeof(*eldata));
5157  BMFace *efa = bm_original_face_get(mr, mp_index);
5158  if (efa) {
5159  mesh_render_data_face_flag(mr, efa, data->cd_ofs, eldata);
5160  }
5161  }
5163 }
5164 
5166  struct MeshBatchCache *UNUSED(cache),
5167  void *UNUSED(buf),
5168  void *data)
5169 {
5170  MEM_freeN(data);
5171 }
5172 
5176  .iter_poly_mesh = extract_fdots_edituv_data_iter_poly_mesh,
5178  .data_flag = 0,
5179  .use_threading = true,
5180 };
5183 /* ---------------------------------------------------------------------- */
5187 typedef struct SkinRootData {
5188  float size;
5189  float local_pos[3];
5191 
5193  struct MeshBatchCache *UNUSED(cache),
5194  void *buf)
5195 {
5196  /* Exclusively for edit mode. */
5197  BLI_assert(mr->bm);
5198 
5199  static GPUVertFormat format = {0};
5200  if (format.attr_len == 0) {
5203  }
5204  GPUVertBuf *vbo = buf;
5206  GPU_vertbuf_data_alloc(vbo, mr->bm->totvert);
5207 
5208  SkinRootData *vbo_data = (SkinRootData *)GPU_vertbuf_get_data(vbo);
5209 
5210  int root_len = 0;
5211  int cd_ofs = CustomData_get_offset(&mr->bm->vdata, CD_MVERT_SKIN);
5212 
5213  BMIter iter;
5214  BMVert *eve;
5215  BM_ITER_MESH (eve, &iter, mr->bm, BM_VERTS_OF_MESH) {
5216  const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_ofs);
5217  if (vs->flag & MVERT_SKIN_ROOT) {
5218  vbo_data->size = (vs->radius[0] + vs->radius[1]) * 0.5f;
5219  copy_v3_v3(vbo_data->local_pos, bm_vert_co_get(mr, eve));
5220  vbo_data++;
5221  root_len++;
5222  }
5223  }
5224 
5225  /* It's really unlikely that all verts will be roots. Resize to avoid losing VRAM. */
5226  GPU_vertbuf_data_len_set(vbo, root_len);
5227 
5228  return NULL;
5229 }
5230 
5233  .data_flag = 0,
5234  .use_threading = false,
5235 };
5236 
5239 /* ---------------------------------------------------------------------- */
5244  struct MeshBatchCache *UNUSED(cache),
5245  void *buf)
5246 {
5247  static GPUVertFormat format = {0};
5248  if (format.attr_len == 0) {
5249  /* TODO rename "color" to something more descriptive. */
5251  }
5252  GPUVertBuf *vbo = buf;
5255  return GPU_vertbuf_get_data(vbo);
5256 }
5257 
5258 /* TODO Use #glVertexID to get loop index and use the data structure on the CPU to retrieve the
5259  * select element associated with this loop ID. This would remove the need for this separate
5260  * index VBO's. We could upload the p/e/v_origindex as a buffer texture and sample it inside the
5261  * shader to output original index. */
5262 
5265  void *data)
5266 {
5268  {
5269  ((uint32_t *)data)[l_index] = BM_elem_index_get(l->f);
5270  }
5272 }
5273 
5276  void *data)
5277 {
5279  {
5280  ((uint32_t *)data)[l_index] = BM_elem_index_get(l->e);
5281  }
5283 }
5284 
5287  void *data)
5288 {
5290  {
5291  ((uint32_t *)data)[l_index] = BM_elem_index_get(l->v);
5292  }
5294 }
5295 
5298  void *data)
5299 {
5300  EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
5301  {
5302  ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed);
5303  ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed);
5304  }
5306 }
5307 
5310  void *data)
5311 {
5312  EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
5313  {
5314  ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = BM_elem_index_get(eed->v1);
5315  ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = BM_elem_index_get(eed->v2);
5316  }
5318 }
5319 
5322  void *data)
5323 {
5324  const int offset = mr->loop_len + (mr->edge_loose_len * 2);
5325  EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
5326  {
5327  ((uint32_t *)data)[offset + lvert_index] = BM_elem_index_get(eve);
5328  }
5330 }
5331 
5334  void *data)
5335 {
5336  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
5337  {
5338  ((uint32_t *)data)[ml_index] = (mr->p_origindex) ? mr->p_origindex[mp_index] : mp_index;
5339  }
5341 }
5342 
5345  void *data)
5346 {
5347  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
5348  {
5349  ((uint32_t *)data)[ml_index] = (mr->e_origindex) ? mr->e_origindex[ml->e] : ml->e;
5350  }
5352 }
5353 
5356  void *data)
5357 {
5358  EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(mp, mp_index, ml, ml_index, params, mr)
5359  {
5360  ((uint32_t *)data)[ml_index] = (mr->v_origindex) ? mr->v_origindex[ml->v] : ml->v;
5361  }
5363 }
5364 
5367  void *data)
5368 {
5369  EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
5370  {
5371  const int e_index = mr->ledges[ledge_index];
5372  const int e_orig = (mr->e_origindex) ? mr->e_origindex[e_index] : e_index;
5373  ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = e_orig;
5374  ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = e_orig;
5375  }
5377 }
5378 
5381  void *data)
5382 {
5383  EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
5384  {
5385  int v1_orig = (mr->v_origindex) ? mr->v_origindex[med->v1] : med->v1;
5386  int v2_orig = (mr->v_origindex) ? mr->v_origindex[med->v2] : med->v2;
5387  ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 0] = v1_orig;
5388  ((uint32_t *)data)[mr->loop_len + ledge_index * 2 + 1] = v2_orig;
5389  }
5391 }
5392 
5395  void *data)
5396 {
5397  const int offset = mr->loop_len + (mr->edge_loose_len * 2);
5398  EXTRACT_LVERT_FOREACH_MESH_BEGIN(med, lvert_index, params, mr)
5399  {
5400  const int v_index = mr->lverts[lvert_index];
5401  const int v_orig = (mr->v_origindex) ? mr->v_origindex[v_index] : v_index;
5402  ((uint32_t *)data)[offset + lvert_index] = v_orig;
5403  }
5405 }
5406 
5409  .iter_poly_bm = extract_poly_idx_iter_poly_bm,
5410  .iter_poly_mesh = extract_poly_idx_iter_poly_mesh,
5411  .data_flag = 0,
5412  .use_threading = true,
5413 };
5414 
5417  .iter_poly_bm = extract_edge_idx_iter_poly_bm,
5418  .iter_poly_mesh = extract_edge_idx_iter_poly_mesh,
5419  .iter_ledge_bm = extract_edge_idx_iter_ledge_bm,
5420  .iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh,
5421  .data_flag = 0,
5422  .use_threading = true,
5423 };
5424 
5427  .iter_poly_bm = extract_vert_idx_iter_poly_bm,
5428  .iter_poly_mesh = extract_vert_idx_iter_poly_mesh,
5429  .iter_ledge_bm = extract_vert_idx_iter_ledge_bm,
5430  .iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh,
5431  .iter_lvert_bm = extract_vert_idx_iter_lvert_bm,
5432  .iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh,
5433  .data_flag = 0,
5434  .use_threading = true,
5435 };
5436 
5438  struct MeshBatchCache *UNUSED(cache),
5439  void *buf)
5440 {
5441  static GPUVertFormat format = {0};
5442  if (format.attr_len == 0) {
5443  /* TODO rename "color" to something more descriptive. */
5445  }
5446  GPUVertBuf *vbo = buf;
5448  GPU_vertbuf_data_alloc(vbo, mr->poly_len);
5449  return GPU_vertbuf_get_data(vbo);
5450 }
5451 
5454  void *data)
5455 {
5456  EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
5457  {
5458  ((uint32_t *)data)[f_index] = f_index;
5459  }
5461 }
5462 
5465  void *data)
5466 {
5467  if (mr->p_origindex != NULL) {
5468  EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
5469  {
5470  ((uint32_t *)data)[mp_index] = mr->p_origindex[mp_index];
5471  }
5473  }
5474  else {
5475  EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
5476  {
5477  ((uint32_t *)data)[mp_index] = mp_index;
5478  }
5480  }
5481 }
5482 
5485  .iter_poly_bm = extract_fdot_idx_iter_poly_bm,
5486  .iter_poly_mesh = extract_fdot_idx_iter_poly_mesh,
5487  .data_flag = 0,
5488  .use_threading = true,
5489 };
5490 
5493 /* ---------------------------------------------------------------------- */
5496 typedef struct ExtractUserData {
5497  void *user_data;
5499 
5500 typedef enum ExtractTaskDataType {
5504 
5505 typedef struct ExtractTaskData {
5506  void *next, *prev;
5512  int start, end;
5515  void *buf;
5518 
5520  struct MeshBatchCache *cache,
5521  const MeshExtract *extract,
5522  void *buf,
5523  int32_t *task_counter)
5524 {
5525  ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), __func__);
5526  taskdata->next = NULL;
5527  taskdata->prev = NULL;
5528  taskdata->tasktype = EXTRACT_MESH_EXTRACT;
5529  taskdata->mr = mr;
5530  taskdata->cache = cache;
5531  taskdata->extract = extract;
5532  taskdata->buf = buf;
5533 
5534  /* #ExtractUserData is shared between the iterations as it holds counters to detect if the
5535  * extraction is finished. To make sure the duplication of the user_data does not create a new
5536  * instance of the counters we allocate the user_data in its own container.
5537  *
5538  * This structure makes sure that when extract_init is called, that the user data of all
5539  * iterations are updated. */
5540  taskdata->user_data = MEM_callocN(sizeof(ExtractUserData), __func__);
5542  taskdata->task_counter = task_counter;
5543  taskdata->start = 0;
5544  taskdata->end = INT_MAX;
5545  return taskdata;
5546 }
5547 
5549  struct MeshBatchCache *cache)
5550 {
5551  ExtractTaskData *taskdata = MEM_callocN(sizeof(*taskdata), __func__);
5552  taskdata->tasktype = EXTRACT_LINES_LOOSE;
5553  taskdata->mr = mr;
5554  taskdata->cache = cache;
5555  return taskdata;
5556 }
5557 
5558 static void extract_task_data_free(void *data)
5559 {
5560  ExtractTaskData *task_data = data;
5561  MEM_SAFE_FREE(task_data->user_data);
5562  MEM_freeN(task_data);
5563 }
5564 
5566  const eMRIterType iter_type,
5567  int start,
5568  int end,
5569  const MeshExtract *extract,
5570  void *user_data)
5571 {
5572  switch (mr->extract_type) {
5573  case MR_EXTRACT_BMESH:
5574  if (iter_type & MR_ITER_LOOPTRI) {
5575  extract->iter_looptri_bm(mr,
5576  &(const ExtractTriBMesh_Params){
5577  .looptris = mr->edit_bmesh->looptris,
5578  .tri_range = {start, min_ii(mr->tri_len, end)},
5579  },
5580  user_data);
5581  }
5582  if (iter_type & MR_ITER_POLY) {
5583  extract->iter_poly_bm(mr,
5584  &(const ExtractPolyBMesh_Params){
5585  .poly_range = {start, min_ii(mr->poly_len, end)},
5586  },
5587  user_data);
5588  }
5589  if (iter_type & MR_ITER_LEDGE) {
5590  extract->iter_ledge_bm(mr,
5591  &(const ExtractLEdgeBMesh_Params){
5592  .ledge = mr->ledges,
5593  .ledge_range = {start, min_ii(mr->edge_loose_len, end)},
5594  },
5595  user_data);
5596  }
5597  if (iter_type & MR_ITER_LVERT) {
5598  extract->iter_lvert_bm(mr,
5599  &(const ExtractLVertBMesh_Params){
5600  .lvert = mr->lverts,
5601  .lvert_range = {start, min_ii(mr->vert_loose_len, end)},
5602  },
5603  user_data);
5604  }
5605  break;
5606  case MR_EXTRACT_MAPPED:
5607  case MR_EXTRACT_MESH:
5608  if (iter_type & MR_ITER_LOOPTRI) {
5609  extract->iter_looptri_mesh(mr,
5610  &(const ExtractTriMesh_Params){
5611  .mlooptri = mr->mlooptri,
5612  .tri_range = {start, min_ii(mr->tri_len, end)},
5613  },
5614  user_data);
5615  }
5616  if (iter_type & MR_ITER_POLY) {
5617  extract->iter_poly_mesh(mr,
5618  &(const ExtractPolyMesh_Params){
5619  .poly_range = {start, min_ii(mr->poly_len, end)},
5620  },
5621  user_data);
5622  }
5623  if (iter_type & MR_ITER_LEDGE) {
5624  extract->iter_ledge_mesh(mr,
5625  &(const ExtractLEdgeMesh_Params){
5626  .ledge = mr->ledges,
5627  .ledge_range = {start, min_ii(mr->edge_loose_len, end)},
5628  },
5629  user_data);
5630  }
5631  if (iter_type & MR_ITER_LVERT) {
5632  extract->iter_lvert_mesh(mr,
5633  &(const ExtractLVertMesh_Params){
5634  .lvert = mr->lverts,
5635  .lvert_range = {start, min_ii(mr->vert_loose_len, end)},
5636  },
5637  user_data);
5638  }
5639  break;
5640  }
5641 }
5642 
5644 {
5645  if (data->tasktype == EXTRACT_MESH_EXTRACT) {
5646  data->user_data->user_data = data->extract->init(data->mr, data->cache, data->buf);
5647  }
5648 }
5649 
5650 static void extract_run(void *__restrict taskdata)
5651 {
5652  ExtractTaskData *data = (ExtractTaskData *)taskdata;
5653  if (data->tasktype == EXTRACT_MESH_EXTRACT) {
5654  mesh_extract_iter(data->mr,
5655  data->iter_type,
5656  data->start,
5657  data->end,
5658  data->extract,
5659  data->user_data->user_data);
5660 
5661  /* If this is the last task, we do the finish function. */
5662  int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1);
5663  if (remainin_tasks == 0 && data->extract->finish != NULL) {
5664  data->extract->finish(data->mr, data->cache, data->buf, data->user_data->user_data);
5665  }
5666  }
5667  else if (data->tasktype == EXTRACT_LINES_LOOSE) {
5669  }
5670 }
5671 
5672 static void extract_init_and_run(void *__restrict taskdata)
5673 {
5674  extract_init((ExtractTaskData *)taskdata);
5675  extract_run(taskdata);
5676 }
5677 
5680 /* ---------------------------------------------------------------------- */
5688 
5690 {
5691  BLI_assert(taskdata);
5692  MeshRenderData *mr = taskdata->mr;
5694  MEM_freeN(taskdata);
5695 }
5696 
5697 static void mesh_extract_render_data_node_exec(void *__restrict task_data)
5698 {
5699  MeshRenderDataUpdateTaskData *update_task_data = task_data;
5700  MeshRenderData *mr = update_task_data->mr;
5701  const eMRIterType iter_type = update_task_data->iter_type;
5702  const eMRDataType data_flag = update_task_data->data_flag;
5703 
5704  mesh_render_data_update_normals(mr, iter_type, data_flag);
5705  mesh_render_data_update_looptris(mr, iter_type, data_flag);
5706 }
5707 
5708 static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph,
5709  MeshRenderData *mr,
5710  const eMRIterType iter_type,
5711  const eMRDataType data_flag)
5712 {
5714  __func__);
5715  task_data->mr = mr;
5716  task_data->iter_type = iter_type;
5717  task_data->data_flag = data_flag;
5718 
5719  struct TaskNode *task_node = BLI_task_graph_node_create(
5720  task_graph,
5722  task_data,
5724  return task_node;
5725 }
5726 
5729 /* ---------------------------------------------------------------------- */
5735 
5737 {
5738  BLI_assert(taskdata);
5741  }
5742  BLI_listbase_clear(&taskdata->task_datas);
5743  MEM_freeN(taskdata);
5744 }
5745 
5746 static void extract_single_threaded_task_node_exec(void *__restrict task_data)
5747 {
5748  ExtractSingleThreadedTaskData *extract_task_data = task_data;
5749  LISTBASE_FOREACH (ExtractTaskData *, td, &extract_task_data->task_datas) {
5751  }
5752 }
5753 
5755  struct TaskGraph *task_graph, ExtractSingleThreadedTaskData *task_data)
5756 {
5757  struct TaskNode *task_node = BLI_task_graph_node_create(
5758  task_graph,
5760  task_data,
5762  return task_node;
5763 }
5764 
5767 /* ---------------------------------------------------------------------- */
5770 typedef struct UserDataInitTaskData {
5773 
5775 
5777 {
5778  BLI_assert(taskdata);
5781  }
5782  BLI_listbase_clear(&taskdata->task_datas);
5783  MEM_SAFE_FREE(taskdata->task_counters);
5784  MEM_freeN(taskdata);
5785 }
5786 
5787 static void user_data_init_task_data_exec(void *__restrict task_data)
5788 {
5789  UserDataInitTaskData *extract_task_data = task_data;
5790  LISTBASE_FOREACH (ExtractTaskData *, td, &extract_task_data->task_datas) {
5791  extract_init(td);
5792  }
5793 }
5794 
5795 static struct TaskNode *user_data_init_task_node_create(struct TaskGraph *task_graph,
5797 {
5798  struct TaskNode *task_node = BLI_task_graph_node_create(
5799  task_graph,
5801  task_data,
5803  return task_node;
5804 }
5805 
5807 /* ---------------------------------------------------------------------- */
5811 static void extract_range_task_create(struct TaskGraph *task_graph,
5812  struct TaskNode *task_node_user_data_init,
5813  ExtractTaskData *taskdata,
5814  const eMRIterType type,
5815  int start,
5816  int length)
5817 {
5818  taskdata = MEM_dupallocN(taskdata);
5820  taskdata->iter_type = type;
5821  taskdata->start = start;
5822  taskdata->end = start + length;
5823  struct TaskNode *task_node = BLI_task_graph_node_create(
5824  task_graph, extract_run, taskdata, MEM_freeN);
5825  BLI_task_graph_edge_create(task_node_user_data_init, task_node);
5826 }
5827 
5828 static void extract_task_create(struct TaskGraph *task_graph,
5829  struct TaskNode *task_node_mesh_render_data,
5830  struct TaskNode *task_node_user_data_init,
5831  ListBase *single_threaded_task_datas,
5832  ListBase *user_data_init_task_datas,
5833  const Scene *scene,
5834  const MeshRenderData *mr,
5835  MeshBatchCache *cache,
5836  const MeshExtract *extract,
5837  void *buf,
5838  int32_t *task_counter)
5839 {
5840  BLI_assert(scene != NULL);
5841  const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
5843  if (do_hq_normals) {
5844  if (extract == &extract_lnor) {
5846  }
5847  else if (extract == &extract_pos_nor) {
5849  }
5850  else if (extract == &extract_tan) {
5852  }
5853  else if (extract == &extract_fdots_nor) {
5855  }
5856  }
5857 
5858  /* Divide extraction of the VBO/IBO into sensible chunks of works. */
5860  mr, cache, extract, buf, task_counter);
5861 
5862  /* Simple heuristic. */
5863  const int chunk_size = 8192;
5864  const bool use_thread = (mr->loop_len + mr->loop_loose_len) > chunk_size;
5865  if (use_thread && extract->use_threading) {
5866 
5867  /* Divide task into sensible chunks. */
5868  if (taskdata->iter_type & MR_ITER_LOOPTRI) {
5869  for (int i = 0; i < mr->tri_len; i += chunk_size) {
5871  task_graph, task_node_user_data_init, taskdata, MR_ITER_LOOPTRI, i, chunk_size);
5872  }
5873  }
5874  if (taskdata->iter_type & MR_ITER_POLY) {
5875  for (int i = 0; i < mr->poly_len; i += chunk_size) {
5877  task_graph, task_node_user_data_init, taskdata, MR_ITER_POLY, i, chunk_size);
5878  }
5879  }
5880  if (taskdata->iter_type & MR_ITER_LEDGE) {
5881  for (int i = 0; i < mr->edge_loose_len; i += chunk_size) {
5883  task_graph, task_node_user_data_init, taskdata, MR_ITER_LEDGE, i, chunk_size);
5884  }
5885  }
5886  if (taskdata->iter_type & MR_ITER_LVERT) {
5887  for (int i = 0; i < mr->vert_loose_len; i += chunk_size) {
5889  task_graph, task_node_user_data_init, taskdata, MR_ITER_LVERT, i, chunk_size);
5890  }
5891  }
5892  BLI_addtail(user_data_init_task_datas, taskdata);
5893  }
5894  else if (use_thread) {
5895  /* One task for the whole VBO. */
5896  (*task_counter)++;
5897  struct TaskNode *one_task = BLI_task_graph_node_create(
5898  task_graph, extract_init_and_run, taskdata, extract_task_data_free);
5899  BLI_task_graph_edge_create(task_node_mesh_render_data, one_task);
5900  }
5901  else {
5902  /* Single threaded extraction. */
5903  (*task_counter)++;
5904  BLI_addtail(single_threaded_task_datas, taskdata);
5905  }
5906 }
5907 
5909  MeshBatchCache *cache,
5910  MeshBufferCache mbc,
5911  Mesh *me,
5912 
5913  const bool is_editmode,
5914  const bool is_paint_mode,
5915  const bool is_mode_active,
5916  const float obmat[4][4],
5917  const bool do_final,
5918  const bool do_uvedit,
5919  const bool use_subsurf_fdots,
5920  const DRW_MeshCDMask *cd_layer_used,
5921  const Scene *scene,
5922  const ToolSettings *ts,
5923  const bool use_hide)
5924 {
5925  /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph.
5926  * This sub-graph starts with an extract_render_data_node. This fills/converts the required data
5927  * from Mesh.
5928  *
5929  * Small extractions and extractions that can't be multi-threaded are grouped in a single
5930  * `extract_single_threaded_task_node`.
5931  *
5932  * Other extractions will create a node for each loop exceeding 8192 items. these nodes are
5933  * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the
5934  * user_data needed for the extraction based on the data extracted from the mesh.
5935  * counters are used to check if the finalize of a task has to be called.
5936  *
5937  * Mesh extraction sub graph
5938  *
5939  * +----------------------+
5940  * +-----> | extract_task1_loop_1 |
5941  * | +----------------------+
5942  * +------------------+ +----------------------+ +----------------------+
5943  * | mesh_render_data | --> | | --> | extract_task1_loop_2 |
5944  * +------------------+ | | +----------------------+
5945  * | | | +----------------------+
5946  * | | user_data_init | --> | extract_task2_loop_1 |
5947  * v | | +----------------------+
5948  * +------------------+ | | +----------------------+
5949  * | single_threaded | | | --> | extract_task2_loop_2 |
5950  * +------------------+ +----------------------+ +----------------------+
5951  * | +----------------------+
5952  * +-----> | extract_task2_loop_3 |
5953  * +----------------------+
5954  */
5955  eMRIterType iter_flag = 0;
5956  eMRDataType data_flag = 0;
5957 
5958  const bool do_lines_loose_subbuffer = mbc.ibo.lines_loose != NULL;
5959 
5960 #define TEST_ASSIGN(type, type_lowercase, name) \
5961  do { \
5962  if (DRW_TEST_ASSIGN_##type(mbc.type_lowercase.name)) { \
5963  iter_flag |= mesh_extract_iter_type(&extract_##name); \
5964  data_flag |= extract_##name.data_flag; \
5965  } \
5966  } while (0)
5967 
5968  TEST_ASSIGN(VBO, vbo, pos_nor);
5969  TEST_ASSIGN(VBO, vbo, lnor);
5970  TEST_ASSIGN(VBO, vbo, uv);
5971  TEST_ASSIGN(VBO, vbo, tan);
5972  TEST_ASSIGN(VBO, vbo, vcol);
5973  TEST_ASSIGN(VBO, vbo, sculpt_data);
5974  TEST_ASSIGN(VBO, vbo, orco);
5975  TEST_ASSIGN(VBO, vbo, edge_fac);
5976  TEST_ASSIGN(VBO, vbo, weights);
5977  TEST_ASSIGN(VBO, vbo, edit_data);
5978  TEST_ASSIGN(VBO, vbo, edituv_data);
5979  TEST_ASSIGN(VBO, vbo, edituv_stretch_area);
5980  TEST_ASSIGN(VBO, vbo, edituv_stretch_angle);
5981  TEST_ASSIGN(VBO, vbo, mesh_analysis);
5982  TEST_ASSIGN(VBO, vbo, fdots_pos);
5983  TEST_ASSIGN(VBO, vbo, fdots_nor);
5984  TEST_ASSIGN(VBO, vbo, fdots_uv);
5985  TEST_ASSIGN(VBO, vbo, fdots_edituv_data);
5986  TEST_ASSIGN(VBO, vbo, poly_idx);
5987  TEST_ASSIGN(VBO, vbo, edge_idx);
5988  TEST_ASSIGN(VBO, vbo, vert_idx);
5989  TEST_ASSIGN(VBO, vbo, fdot_idx);
5990  TEST_ASSIGN(VBO, vbo, skin_roots);
5991 
5992  TEST_ASSIGN(IBO, ibo, tris);
5993  TEST_ASSIGN(IBO, ibo, lines);
5994  TEST_ASSIGN(IBO, ibo, points);
5995  TEST_ASSIGN(IBO, ibo, fdots);
5996  TEST_ASSIGN(IBO, ibo, lines_paint_mask);
5997  TEST_ASSIGN(IBO, ibo, lines_adjacency);
5998  TEST_ASSIGN(IBO, ibo, edituv_tris);
5999  TEST_ASSIGN(IBO, ibo, edituv_lines);
6000  TEST_ASSIGN(IBO, ibo, edituv_points);
6001  TEST_ASSIGN(IBO, ibo, edituv_fdots);
6002 
6003  if (do_lines_loose_subbuffer) {
6004  iter_flag |= MR_ITER_LEDGE;
6005  }
6006 
6007 #undef TEST_ASSIGN
6008 
6009 #ifdef DEBUG_TIME
6010  double rdata_start = PIL_check_seconds_timer();
6011 #endif
6012 
6014  is_editmode,
6015  is_paint_mode,
6016  is_mode_active,
6017  obmat,
6018  do_final,
6019  do_uvedit,
6020  cd_layer_used,
6021  ts,
6022  iter_flag,
6023  data_flag);
6024  mr->use_hide = use_hide;
6025  mr->use_subsurf_fdots = use_subsurf_fdots;
6026  mr->use_final_mesh = do_final;
6027 
6028 #ifdef DEBUG_TIME
6029  double rdata_end = PIL_check_seconds_timer();
6030 #endif
6031 
6032  size_t counters_size = (sizeof(mbc) / sizeof(void *)) * sizeof(int32_t);
6033  int32_t *task_counters = MEM_callocN(counters_size, __func__);
6034  int counter_used = 0;
6035 
6036  struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create(
6037  task_graph, mr, iter_flag, data_flag);
6038  ExtractSingleThreadedTaskData *single_threaded_task_data = MEM_callocN(
6039  sizeof(ExtractSingleThreadedTaskData), __func__);
6040  UserDataInitTaskData *user_data_init_task_data = MEM_callocN(sizeof(UserDataInitTaskData),
6041  __func__);
6042  user_data_init_task_data->task_counters = task_counters;
6043  struct TaskNode *task_node_user_data_init = user_data_init_task_node_create(
6044  task_graph, user_data_init_task_data);
6045 
6046 #define EXTRACT(buf, name) \
6047  if (mbc.buf.name) { \
6048  extract_task_create(task_graph, \
6049  task_node_mesh_render_data, \
6050  task_node_user_data_init, \
6051  &single_threaded_task_data->task_datas, \
6052  &user_data_init_task_data->task_datas, \
6053  scene, \
6054  mr, \
6055  cache, \
6056  &extract_##name, \
6057  mbc.buf.name, \
6058  &task_counters[counter_used++]); \
6059  } \
6060  ((void)0)
6061 
6062  EXTRACT(vbo, pos_nor);
6063  EXTRACT(vbo, lnor);
6064  EXTRACT(vbo, uv);
6065  EXTRACT(vbo, tan);
6066  EXTRACT(vbo, vcol);
6067  EXTRACT(vbo, sculpt_data);
6068  EXTRACT(vbo, orco);
6069  EXTRACT(vbo, edge_fac);
6070  EXTRACT(vbo, weights);
6071  EXTRACT(vbo, edit_data);
6072  EXTRACT(vbo, edituv_data);
6073  EXTRACT(vbo, edituv_stretch_area);
6074  EXTRACT(vbo, edituv_stretch_angle);
6075  EXTRACT(vbo, mesh_analysis);
6076  EXTRACT(vbo, fdots_pos);
6077  EXTRACT(vbo, fdots_nor);
6078  EXTRACT(vbo, fdots_uv);
6079  EXTRACT(vbo, fdots_edituv_data);
6080  EXTRACT(vbo, poly_idx);
6081  EXTRACT(vbo, edge_idx);
6082  EXTRACT(vbo, vert_idx);
6083  EXTRACT(vbo, fdot_idx);
6084  EXTRACT(vbo, skin_roots);
6085 
6086  EXTRACT(ibo, tris);
6087  if (mbc.ibo.lines) {
6088  /* When `lines` and `lines_loose` are requested, schedule lines extraction that also creates
6089  * the `lines_loose` sub-buffer. */
6090  const MeshExtract *lines_extractor = do_lines_loose_subbuffer ?
6092  &extract_lines;
6093  extract_task_create(task_graph,
6094  task_node_mesh_render_data,
6095  task_node_user_data_init,
6096  &single_threaded_task_data->task_datas,
6097  &user_data_init_task_data->task_datas,
6098  scene,
6099  mr,
6100  cache,
6101  lines_extractor,
6102  mbc.ibo.lines,
6103  &task_counters[counter_used++]);
6104  }
6105  else {
6106  if (do_lines_loose_subbuffer) {
6108  BLI_addtail(&single_threaded_task_data->task_datas, taskdata);
6109  }
6110  }
6111  EXTRACT(ibo, points);
6112  EXTRACT(ibo, fdots);
6113  EXTRACT(ibo, lines_paint_mask);
6114  EXTRACT(ibo, lines_adjacency);
6115  EXTRACT(ibo, edituv_tris);
6116  EXTRACT(ibo, edituv_lines);
6117  EXTRACT(ibo, edituv_points);
6118  EXTRACT(ibo, edituv_fdots);
6119 
6120  /* Only create the edge when there is user data that needs to be initialized.
6121  * The task is still part of the graph so the task_data will be freed when the graph is freed.
6122  */
6123  if (!BLI_listbase_is_empty(&user_data_init_task_data->task_datas)) {
6124  BLI_task_graph_edge_create(task_node_mesh_render_data, task_node_user_data_init);
6125  }
6126 
6127  if (!BLI_listbase_is_empty(&single_threaded_task_data->task_datas)) {
6129  task_graph, single_threaded_task_data);
6130  BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
6131  }
6132  else {
6133  extract_single_threaded_task_data_free(single_threaded_task_data);
6134  }
6135 
6136  /* Trigger the sub-graph for this mesh. */
6137  BLI_task_graph_node_push_work(task_node_mesh_render_data);
6138 
6139 #undef EXTRACT
6140 
6141 #ifdef DEBUG_TIME
6142  BLI_task_graph_work_and_wait(task_graph);
6143  double end = PIL_check_seconds_timer();
6144 
6145  static double avg = 0;
6146  static double avg_fps = 0;
6147  static double avg_rdata = 0;
6148  static double end_prev = 0;
6149 
6150  if (end_prev == 0) {
6151  end_prev = end;
6152  }
6153 
6154  avg = avg * 0.95 + (end - rdata_end) * 0.05;
6155  avg_fps = avg_fps * 0.95 + (end - end_prev) * 0.05;
6156  avg_rdata = avg_rdata * 0.95 + (rdata_end - rdata_start) * 0.05;
6157 
6158  printf(
6159  "rdata %.0fms iter %.0fms (frame %.0fms)\n", avg_rdata * 1000, avg * 1000, avg_fps * 1000);
6160 
6161  end_prev = end;
6162 #endif
6163 }
6164 
typedef float(TangentPoint)[2]
BVHTree * BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, struct Mesh *mesh, const BVHCacheType bvh_cache_type, const int tree_type)
Definition: bvhutils.c:1413
@ BVHTREE_FROM_LOOPTRI
Definition: BKE_bvhutils.h:93
CustomData interface, see also DNA_customdata_types.h.
void CustomData_free(struct CustomData *data, int totelem)
Definition: customdata.c:2239
const char * CustomData_get_layer_name(const struct CustomData *data, int type, int n)
int CustomData_get_named_layer_index(const struct CustomData *data, int type, const char *name)
int CustomData_get_active_layer(const struct CustomData *data, int type)
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
Definition: customdata.c:3217
int CustomData_get_stencil_layer(const struct CustomData *data, int type)
#define ORIGINDEX_NONE
void * CustomData_get_layer_n(const struct CustomData *data, int type, int n)
void * CustomData_get_layer(const struct CustomData *data, int type)
int CustomData_get_n_offset(const struct CustomData *data, int type, int n)
int CustomData_get_offset(const struct CustomData *data, int type)
void CustomData_reset(struct CustomData *data)
Definition: customdata.c:2233
int CustomData_get_render_layer(const struct CustomData *data, int type)
support for deformation groups and hooks.
float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
Definition: deform.c:632
bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgroup_tot)
Definition: deform.c:818
float BKE_defvert_lock_relative_weight(float weight, const struct MDeformVert *dv, int defbase_tot, const bool *defbase_locked, const bool *defbase_unlocked)
Definition: deform.c:920
float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv, int defbase_tot, const bool *defbase_sel, int defbase_tot_sel, bool is_normalized)
Definition: deform.c:865
struct BMFace * BKE_bmbvh_ray_cast(BMBVHTree *tree, const float co[3], const float dir[3], const float radius, float *r_dist, float r_hitout[3], float r_cagehit[3])
Definition: editmesh_bvh.c:306
void BKE_bmbvh_free(BMBVHTree *tree)
Definition: editmesh_bvh.c:186
BMBVHTree * BKE_bmbvh_new_from_editmesh(struct BMEditMesh *em, int flag, const float(*cos_cage)[3], const bool cos_cage_free)
Definition: editmesh_bvh.c:47
struct BVHTreeOverlap * BKE_bmbvh_overlap_self(const BMBVHTree *bmtree, unsigned int *r_overlap_tot)
Definition: editmesh_bvh.c:597
void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, struct EditMeshData *emd)
void BKE_editmesh_cache_ensure_poly_normals(struct BMEditMesh *em, struct EditMeshData *emd)
void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, bool calc_active_tangent, const char(*tangent_names)[MAX_NAME], int tangent_names_len, const float(*poly_normals)[3], const float(*loop_normals)[3], const float(*vert_orco)[3], CustomData *dm_loopdata_out, const uint dm_loopdata_out_len, short *tangent_mask_curr_p)
void BKE_mesh_recalc_looptri(const struct MLoop *mloop, const struct MPoly *mpoly, const struct MVert *mvert, int totloop, int totpoly, struct MLoopTri *mlooptri)
void BKE_mesh_orco_verts_transform(struct Mesh *me, float(*orco)[3], int totvert, int invert)
Definition: mesh.c:1179
void BKE_mesh_normals_loop_split(const struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges, struct MLoop *mloops, float(*r_loopnors)[3], const int numLoops, struct MPoly *mpolys, const float(*polynors)[3], const int numPolys, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr, short(*clnors_data)[2], int *r_loop_to_poly)
float BKE_mesh_calc_poly_uv_area(const struct MPoly *mpoly, const struct MLoopUV *uv_array)
float BKE_mesh_calc_poly_area(const struct MPoly *mpoly, const struct MLoop *loopstart, const struct MVert *mvarray)
void BKE_mesh_calc_normals_poly(struct MVert *mverts, float(*r_vertnors)[3], int numVerts, const struct MLoop *mloop, const struct MPoly *mpolys, int numLoops, int numPolys, float(*r_polyNors)[3], const bool only_face_normals)
void BKE_mesh_calc_loop_tangent_ex(const struct MVert *mvert, const struct MPoly *mpoly, const uint mpoly_len, const struct MLoop *mloop, const struct MLoopTri *looptri, const uint looptri_len, struct CustomData *loopdata, bool calc_active_tangent, const char(*tangent_names)[64], int tangent_names_len, const float(*poly_normals)[3], const float(*loop_normals)[3], const float(*vert_orco)[3], struct CustomData *loopdata_out, const uint loopdata_out_len, short *tangent_mask_curr_p)
Functions for dealing with objects and deform verts, used by painting and tools.
void BKE_paint_face_set_overlay_color_get(const int face_set, const int seed, uchar r_color[4])
Definition: paint.c:2249
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:63
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:78
#define BLI_BITMAP_SIZE(_tot)
Definition: BLI_bitmap.h:47
#define BLI_BITMAP_NEW(_tot, _alloc_string)
Definition: BLI_bitmap.h:50
#define BLI_BITMAP_TEST_AND_SET_ATOMIC(_bitmap, _index)
Definition: BLI_bitmap.h:67
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:32
#define BLI_INLINE
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value)
Definition: edgehash.c:244
BLI_INLINE void BLI_edgehashIterator_getKey(EdgeHashIterator *ehi, unsigned int *r_v0, unsigned int *r_v1)
Definition: BLI_edgehash.h:93
BLI_INLINE bool BLI_edgehashIterator_isDone(EdgeHashIterator *ehi)
Definition: BLI_edgehash.h:89
EdgeHash * BLI_edgehash_new_ex(const char *info, const unsigned int nentries_reserve)
Definition: edgehash.c:226
EdgeHashIterator * BLI_edgehashIterator_new(EdgeHash *eh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: edgehash.c:471
bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: edgehash.c:355
BLI_INLINE void BLI_edgehashIterator_step(EdgeHashIterator *ehi)
Definition: BLI_edgehash.h:85
void BLI_edgehashIterator_free(EdgeHashIterator *ehi)
Definition: edgehash.c:496
BLI_INLINE void * BLI_edgehashIterator_getValue(EdgeHashIterator *ehi)
Definition: BLI_edgehash.h:101
void BLI_jitter_init(float(*jitarr)[2], int num)
Definition: jitter_2d.c:142
BVHTreeOverlap * BLI_bvhtree_overlap(const BVHTree *tree1, const BVHTree *tree2, unsigned int *r_overlap_tot, BVHTree_OverlapCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1401
float BLI_bvhtree_get_epsilon(const BVHTree *tree)
Definition: BLI_kdopbvh.c:1074
int BLI_bvhtree_ray_cast(BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1984
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
#define M_1_PI
Definition: BLI_math_base.h:59
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float pow2f(float x)
#define M_PI
Definition: BLI_math_base.h:38
MINLINE int poly_to_tri_count(const int poly_count, const int corner_count)
bool is_edge_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition: math_geom.c:6064
bool isect_tri_tri_v3(const float t_a0[3], const float t_a1[3], const float t_a2[3], const float t_b0[3], const float t_b1[3], const float t_b2[3], float r_i1[3], float r_i2[3])
Definition: math_geom.c:2521
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:51
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:950
float mat4_to_scale(const float M[4][4])
Definition: math_matrix.c:2196
#define DEG2RADF(_deg)
void copy_vn_fl(float *array_tar, const int size, const float val)
Definition: math_vector.c:1410
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:521
MINLINE void madd_v2_v2fl(float r[2], const float a[2], float f)
MINLINE void normal_float_to_short_v3(short r[3], const float n[3])
MINLINE float normalize_v3(float r[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void normal_short_to_float_v3(float r[3], const short n[3])
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void clamp_v2(float vec[2], const float min, const float max)
MINLINE void copy_v3_v3_short(short r[3], const short a[3])
MINLINE void negate_v3(float r[3])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v3(float r[3])
MINLINE float normalize_v2(float r[2])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:505
MINLINE void add_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3v3_uv(float p[3], const float v1[3], const float v2[3], const float v3[3], const float uv[2])
Definition: math_vector.c:235
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
unsigned char uchar
Definition: BLI_sys_types.h:86
unsigned int uint
Definition: BLI_sys_types.h:83
unsigned short ushort
Definition: BLI_sys_types.h:84
void(* TaskGraphNodeFreeFunction)(void *task_data)
Definition: BLI_task.h:307
void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node)
Definition: task_graph.cc:153
bool BLI_task_graph_node_push_work(struct TaskNode *task_node)
Definition: task_graph.cc:141
struct TaskNode * BLI_task_graph_node_create(struct TaskGraph *task_graph, TaskGraphNodeRunFunction run, void *user_data, TaskGraphNodeFreeFunction free_func)
Definition: task_graph.cc:131
void BLI_task_graph_work_and_wait(struct TaskGraph *task_graph)
Definition: task_graph.cc:122
#define UNUSED_VARS(...)
#define SWAP(type, a, b)
#define POINTER_FROM_INT(i)
#define SHIFT3(type, a, b, c)
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define POINTER_AS_INT(i)
#define UNPACK3(a)
#define UNLIKELY(x)
#define ELEM(...)
#define MAX_CUSTOMDATA_LAYER_NAME
#define MAX_MCOL
@ CD_PAINT_MASK
@ CD_MVERT_SKIN
@ CD_CUSTOMLOOPNORMAL
@ CD_MDEFORMVERT
@ CD_ORIGINDEX
@ CD_PROP_COLOR
@ CD_MLOOPCOL
@ CD_SCULPT_FACE_SETS
@ CD_FREESTYLE_EDGE
@ CD_FREESTYLE_FACE
@ CD_MVERT
@ CD_BWEIGHT
@ CD_MLOOPUV
@ CD_TANGENT
#define MAX_MTFACE
@ ME_WRAPPER_TYPE_MDATA
@ ME_AUTOSMOOTH
@ FREESTYLE_EDGE_MARK
@ ME_HIDE
@ ME_VERT_FACEDOT
@ ME_EDGERENDER
@ ME_LOOSEEDGE
@ MLOOPUV_PINNED
@ FREESTYLE_FACE_MARK
@ MVERT_SKIN_ROOT
@ ME_SMOOTH
@ ME_FACE_SEL
Object is a sort of wrapper for general info.
@ SCE_PERF_HQ_NORMALS
#define SCE_STATVIS_INTERSECT
#define SCE_STATVIS_THICKNESS
#define SCE_STATVIS_SHARP
#define SCE_STATVIS_DISTORT
#define SCE_SELECT_FACE
@ OB_DRAW_GROUPUSER_ACTIVE
@ OB_DRAW_GROUPUSER_NONE
@ OB_DRAW_GROUPUSER_ALL
#define SCE_STATVIS_OVERHANG
#define UV_SYNC_SELECTION
#define SCE_SELECT_VERTEX
struct BMFace * EDBM_uv_active_face_get(struct BMEditMesh *em, const bool sloppy, const bool selected)
bool uvedit_edge_select_test_ex(const struct ToolSettings *ts, struct BMLoop *l, const int cd_loop_uv_offset)
bool uvedit_uv_select_test_ex(const struct ToolSettings *ts, struct BMLoop *l, const int cd_loop_uv_offset)
bool uvedit_face_select_test_ex(const struct ToolSettings *ts, struct BMFace *efa, const int cd_loop_uv_offset)
NSNotificationCenter * center
bool GPU_use_hq_normals_workaround(void)
bool GPU_crappy_amd_driver(void)
void GPU_indexbuf_set_point_vert(GPUIndexBufBuilder *builder, uint elem, uint v1)
void GPU_indexbuf_set_point_restart(GPUIndexBufBuilder *builder, uint elem)
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
void GPU_indexbuf_add_point_vert(GPUIndexBufBuilder *, uint v)
void GPU_indexbuf_add_line_verts(GPUIndexBufBuilder *, uint v1, uint v2)
void GPU_indexbuf_set_line_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2)
void GPU_indexbuf_set_tri_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2, uint v3)
void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem)
void GPU_indexbuf_add_line_adj_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3, uint v4)
GPUIndexBuf * GPU_indexbuf_calloc(void)
void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem, GPUIndexBuf *elem_src, uint start, uint length)
void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, GPUIndexBuf *)
void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei stride
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:36
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:35
@ GPU_PRIM_LINES_ADJ
Definition: GPU_primitive.h:43
@ GPU_PRIM_TRIS
Definition: GPU_primitive.h:37
const GPUVertFormat * GPU_vertbuf_get_format(const GPUVertBuf *verts)
void * GPU_vertbuf_steal_data(GPUVertBuf *verts)
struct GPUVertBuf GPUVertBuf
void GPU_vertbuf_clear(GPUVertBuf *verts)
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len)
#define GPU_vertbuf_init_with_format(verts, format)
void * GPU_vertbuf_get_data(const GPUVertBuf *verts)
void GPU_vertbuf_data_len_set(GPUVertBuf *, uint v_len)
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len)
GPUVertFetchMode
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
@ GPU_FETCH_INT
BLI_INLINE GPUPackedNormal GPU_normal_convert_i10_s3(const short data[3])
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
#define GPU_MAX_SAFE_ATTR_NAME
struct GPUNormal GPUNormal
BLI_INLINE GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3])
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias)
void GPU_vertformat_deinterleave(GPUVertFormat *format)
GPUVertCompType
@ GPU_COMP_U16
@ GPU_COMP_I10
@ GPU_COMP_F32
@ GPU_COMP_U32
@ GPU_COMP_I16
@ GPU_COMP_U8
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
Group RGB to Bright Vector Camera CLAMP
Utility defines for timing/benchmarks.
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE int32_t atomic_add_and_fetch_int32(int32_t *p, int32_t x)
ATOMIC_INLINE int32_t atomic_sub_and_fetch_int32(int32_t *p, int32_t x)
#define BM_ELEM_CD_GET_FLOAT(ele, offset)
Definition: bmesh_class.h:542
#define BM_ELEM_CD_GET_INT(ele, offset)
Definition: bmesh_class.h:518
@ BM_LOOP
Definition: bmesh_class.h:385
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SEAM
Definition: bmesh_class.h:473
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_SMOOTH
Definition: bmesh_class.h:477
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:530
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
ATTR_WARN_UNUSED_RESULT BMesh * bm
BMEdge * BM_mesh_active_edge_get(BMesh *bm)
BMVert * BM_mesh_active_vert_get(BMesh *bm)
BMFace * BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
void BM_loops_calc_normal_vcos(BMesh *bm, const float(*vcos)[3], const float(*vnos)[3], const float(*fnos)[3], const bool use_split_normals, const float split_angle, float(*r_lnos)[3], MLoopNorSpaceArray *r_lnors_spacearr, short(*clnors_data)[2], const int cd_loop_clnors_offset, const bool do_rebuild)
BMesh Compute Loop Normals from/to external data.
Definition: bmesh_mesh.c:1346
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2276
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:110
BLI_INLINE BMEdge * BM_edge_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:104
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:98
float BM_face_calc_area_uv(const BMFace *f, int cd_loop_uv_offset)
float BM_face_calc_area(const BMFace *f)
float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3])
Definition: bmesh_query.c:1612
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
Definition: bmesh_query.c:555
float BM_loop_calc_face_normal_safe_vcos(const BMLoop *l, const float normal_fallback[3], float const (*vertexCos)[3], float r_normal[3])
Definition: bmesh_query.c:1617
float BM_edge_calc_face_angle_signed(const BMEdge *e)
Definition: bmesh_query.c:1785
BMLoop * BM_face_edge_share_loop(BMFace *f, BMEdge *e)
Return the Loop Shared by Face and Edge.
Definition: bmesh_query.c:1426
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
unsigned int U
Definition: btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
__forceinline float extract(const int4 &b)
Definition: bvh_binning.cpp:45
#define SELECT
Scene scene
void * user_data
@ DRW_MESH_WEIGHT_STATE_MULTIPAINT
@ DRW_MESH_WEIGHT_STATE_AUTO_NORMALIZE
@ DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE
BLI_INLINE int mesh_render_mat_len_get(Mesh *me)
eMRExtractType
@ MR_EXTRACT_BMESH
@ MR_EXTRACT_MESH
@ MR_EXTRACT_MAPPED
eMRIterType
eMRDataType
@ MR_DATA_LOOP_NOR
@ MR_DATA_TAN_LOOP_NOR
@ MR_DATA_POLY_NOR
@ MR_DATA_LOOPTRI
static const MeshExtract extract_fdots_pos
static void statvis_calc_intersect(const MeshRenderData *mr, float *r_intersect)
BLI_INLINE float overhang_remap(float fac, float min, float max, float minmax_irange)
static void * extract_edituv_fdots_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(ibo))
void() ExtractTriMeshFn(const MeshRenderData *mr, const ExtractTriMesh_Params *params, void *data)
static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata)
static void extract_pos_nor_hq_iter_lvert_mesh(const MeshRenderData *mr, const ExtractLVertMesh_Params *params, void *_data)
static void mesh_extract_render_data_node_exec(void *__restrict task_data)
static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *data)
static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *UNUSED(vbo), void *data)
static void extract_points_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *ibo, void *elb)
static void extract_edituv_points_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *data)
static const MeshExtract extract_uv
static void * extract_vcol_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
static void extract_edge_idx_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *data)
#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN(elem_poly, index_poly, elem_loop, index_loop, params, mr)
static const MeshExtract extract_fdots_nor
struct MeshExtract_LinePaintMask_Data MeshExtract_LinePaintMask_Data
BLI_INLINE const float * bm_face_no_get(const MeshRenderData *mr, const BMFace *efa)
struct ExtractUserData ExtractUserData
#define NOR_AND_FLAG_ACTIVE
static void extract_vert_idx_iter_ledge_bm(const MeshRenderData *mr, const ExtractLEdgeBMesh_Params *params, void *data)
static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *ibo, void *_data)
#define EXTRACT_POLY_FOREACH_BM_BEGIN(elem_poly, index_poly, params, mr)
static const MeshExtract extract_lines_with_lines_loose
static void extract_points_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *elb)
static const MeshExtract extract_edge_fac
static void extract_single_threaded_task_node_exec(void *__restrict task_data)
static void extract_edit_data_iter_lvert_bm(const MeshRenderData *mr, const ExtractLVertBMesh_Params *params, void *_data)
#define EXTRACT_LEDGE_FOREACH_MESH_END
static void extract_edit_data_iter_ledge_mesh(const MeshRenderData *mr, const ExtractLEdgeMesh_Params *params, void *_data)
static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *cache, void *ibo, void *_data)
static void extract_fdots_nor_finish(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(data))
static void * extract_edit_data_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
static void * extract_lines_paint_mask_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf))
static void * extract_tan_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
static void extract_tris_finish(const MeshRenderData *mr, struct MeshBatchCache *cache, void *ibo, void *_data)
static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *data)
static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *_data)
static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *data)
BLI_INLINE void edituv_tri_add(MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, int v1, int v2, int v3)
static void extract_poly_idx_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *data)
static const MeshExtract extract_edituv_stretch_area
static void extract_pos_nor_hq_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *_data)
static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr, struct MeshBatchCache *cache, void *ibo, void *elb)
BLI_INLINE const float * bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve)
static const MeshExtract extract_weights
struct MeshExtract MeshExtract
BLI_INLINE BMFace * bm_original_face_get(const MeshRenderData *mr, int idx)
static void * extract_mesh_analysis_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
static const MeshExtract extract_vert_idx
struct ExtractLVertMesh_Params ExtractLVertMesh_Params
static void * extract_fdots_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf))
static void extract_lines_iter_ledge_bm(const MeshRenderData *mr, const ExtractLEdgeBMesh_Params *params, void *elb)
struct ExtractTriMesh_Params ExtractTriMesh_Params
#define NO_EDGE
static void extract_orco_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *data)
static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *elb)
static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *ibo, void *_data)
static void extract_fdots_uv_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *_data)
static void axis_from_enum_v3(float v[3], const char axis)
static float loop_edge_factor_get(const float f_no[3], const float v_co[3], const float v_no[3], const float v_next_co[3])
#define NOR_AND_FLAG_DEFAULT
BLI_INLINE BMEdge * bm_original_edge_get(const MeshRenderData *mr, int idx)
static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *data)
static void extract_pos_nor_hq_iter_lvert_bm(const MeshRenderData *mr, const ExtractLVertBMesh_Params *params, void *_data)
static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *_data)
static void extract_edituv_data_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *data)
#define EXTRACT_POLY_FOREACH_MESH_BEGIN(elem_poly, index_poly, params, mr)
static bool bvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
static void mesh_render_data_update_normals(MeshRenderData *mr, const eMRIterType UNUSED(iter_type), const eMRDataType data_flag)
static void edituv_get_edituv_stretch_angle(float auv[2][2], const float av[2][3], UVStretchAngle *r_stretch)
#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END
#define EXTRACT_LVERT_FOREACH_BM_END
static const MeshExtract extract_fdots
static void extract_pos_nor_hq_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *UNUSED(vbo), void *data)
static void extract_fdots_pos_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *data)
static void extract_edituv_stretch_angle_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *data)
struct MeshRenderData MeshRenderData
#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(elem_loop)
static void * extract_fdots_nor_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr, const ExtractLVertMesh_Params *params, void *data)
static void * extract_fdots_edituv_data_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
static const MeshExtract extract_lnor
static void extract_pos_nor_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *_data)
struct ExtractTriBMesh_Params ExtractTriBMesh_Params
#define EXTRACT_LEDGE_FOREACH_BM_BEGIN(elem_edge, index_ledge, params)
struct MeshExtract_Tri_Data MeshExtract_Tri_Data
BLI_INLINE float area_ratio_get(float area, float uvarea)
static void * extract_lines_adjacency_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf))
static void extract_vert_idx_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *data)
static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *_data)
struct MeshExtract_StretchAngle_Data MeshExtract_StretchAngle_Data
static void extract_edit_data_iter_ledge_bm(const MeshRenderData *mr, const ExtractLEdgeBMesh_Params *params, void *_data)
static void extract_weights_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *data)
static const MeshExtract extract_fdots_nor_hq
static void extract_edge_fac_iter_ledge_bm(const MeshRenderData *mr, const ExtractLEdgeBMesh_Params *params, void *_data)
static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *_data)
static void * extract_tan_hq_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
static void extract_points_iter_ledge_bm(const MeshRenderData *mr, const ExtractLEdgeBMesh_Params *params, void *elb)
static void extract_fdots_edituv_data_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *_data)
static void * extract_lnor_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
struct PosNorHQLoop PosNorHQLoop
struct ExtractTaskData ExtractTaskData
static void extract_task_create(struct TaskGraph *task_graph, struct TaskNode *task_node_mesh_render_data, struct TaskNode *task_node_user_data_init, ListBase *single_threaded_task_datas, ListBase *user_data_init_task_datas, const Scene *scene, const MeshRenderData *mr, MeshBatchCache *cache, const MeshExtract *extract, void *buf, int32_t *task_counter)
static void * extract_select_idx_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END
static void extract_vert_idx_iter_lvert_bm(const MeshRenderData *mr, const ExtractLVertBMesh_Params *params, void *data)
#define EXTRACT_LEDGE_FOREACH_MESH_BEGIN(elem_edge, index_ledge, params, mr)
#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elem_tri, index_tri, params)
static const MeshExtract extract_fdots_edituv_data
static void extract_mesh_analysis_finish(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(data))
static void * extract_uv_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
BLI_INLINE BMVert * bm_original_vert_get(const MeshRenderData *mr, int idx)
static void extract_lines_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *ibo, void *elb)
static const MeshExtract extract_orco
static short v2_to_short_angle(const float v[2])
struct ExtractPolyBMesh_Params ExtractPolyBMesh_Params
struct MeshExtract_EdgeFac_Data MeshExtract_EdgeFac_Data
struct MeshRenderDataUpdateTaskData MeshRenderDataUpdateTaskData
@ EXTRACT_MESH_EXTRACT
@ EXTRACT_LINES_LOOSE
static void extract_init_and_run(void *__restrict taskdata)
static const MeshExtract extract_edituv_fdots
BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb, const MeshRenderData *mr, const int v_index, const int l_index)
static void extract_orco_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *data)
static const MeshExtract extract_fdot_idx
static void extract_pos_nor_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *_data)
struct MeshExtract_EditUvElem_Data MeshExtract_EditUvElem_Data
static void extract_pos_nor_iter_ledge_mesh(const MeshRenderData *mr, const ExtractLEdgeMesh_Params *params, void *_data)
static void extract_fdots_uv_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *_data)
static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr, const ExtractLEdgeMesh_Params *params, void *_data)
static void extract_tris_iter_looptri_bm(const MeshRenderData *mr, const struct ExtractTriBMesh_Params *params, void *_data)
static void extract_init(ExtractTaskData *data)
static void extract_pos_nor_hq_iter_ledge_bm(const MeshRenderData *mr, const ExtractLEdgeBMesh_Params *params, void *_data)
static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData *mr, const struct ExtractTriMesh_Params *params, void *data)
static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *ibo, void *data)
static const MeshExtract extract_lines
static void extract_tan_ex(const MeshRenderData *mr, struct MeshBatchCache *cache, GPUVertBuf *vbo, const bool do_hq)
static const MeshExtract extract_edituv_points
static void statvis_calc_thickness(const MeshRenderData *mr, float *r_thickness)
static void extract_lines_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *elb)
BLI_INLINE eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
static void extract_single_threaded_task_data_free(ExtractSingleThreadedTaskData *taskdata)
static void extract_lines_iter_ledge_mesh(const MeshRenderData *mr, const ExtractLEdgeMesh_Params *params, void *elb)
static const MeshExtract extract_edituv_tris
static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *ibo, void *data)
void() ExtractLVertBMeshFn(const MeshRenderData *mr, const ExtractLVertBMesh_Params *params, void *data)
static void mesh_render_data_update_looptris(MeshRenderData *mr, const eMRIterType iter_type, const eMRDataType data_flag)
BLI_INLINE void vert_set_bm(GPUIndexBufBuilder *elb, BMVert *eve, int l_index)
static const MeshExtract extract_sculpt_data
static void extract_weights_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *_data)
static MeshRenderData * mesh_render_data_create(Mesh *me, const bool is_editmode, const bool is_paint_mode, const bool is_mode_active, const float obmat[4][4], const bool do_final, const bool do_uvedit, const DRW_MeshCDMask *UNUSED(cd_used), const ToolSettings *ts, const eMRIterType iter_type, const eMRDataType data_flag)
static void mesh_render_data_edge_flag(const MeshRenderData *mr, BMEdge *eed, EditLoopData *eattr)
static const MeshExtract extract_edge_idx
struct ExtractLEdgeBMesh_Params ExtractLEdgeBMesh_Params
#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(elem_loop, index_loop, params, mr)
static const MeshExtract extract_vcol
static void extract_points_iter_ledge_mesh(const MeshRenderData *mr, const ExtractLEdgeMesh_Params *params, void *elb)
static void extract_edge_idx_iter_ledge_mesh(const MeshRenderData *mr, const ExtractLEdgeMesh_Params *params, void *data)
static void extract_fdot_idx_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *data)
static void * extract_edituv_data_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
static void mesh_render_data_vert_flag(const MeshRenderData *mr, BMVert *eve, EditLoopData *eattr)
static const MeshExtract extract_poly_idx
static void extract_edituv_fdots_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *data)
BLI_INLINE float distort_remap(float fac, float min, float UNUSED(max), float minmax_irange)
#define EXTRACT_POLY_FOREACH_MESH_END
static struct TaskNode * mesh_extract_render_data_node_create(struct TaskGraph *task_graph, MeshRenderData *mr, const eMRIterType iter_type, const eMRDataType data_flag)
static void * extract_weights_init(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf)
static const MeshExtract extract_tris
static void extract_fdots_edituv_data_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *data)
static void * extract_tris_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(ibo))
void() ExtractTriBMeshFn(const MeshRenderData *mr, const ExtractTriBMesh_Params *params, void *data)
void *() ExtractInitFn(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buffer)
static const MeshExtract extract_edituv_data
struct ExtractPolyMesh_Params ExtractPolyMesh_Params
static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshBatchCache *cache)
void() ExtractPolyMeshFn(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *data)
static void extract_edge_fac_finish(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf, void *_data)
struct UserDataInitTaskData UserDataInitTaskData
static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr, const ExtractLVertMesh_Params *params, void *_data)
#define NOR_AND_FLAG_SELECT
struct MeshExtract_PosNor_Data MeshExtract_PosNor_Data
static const MeshExtract extract_pos_nor_hq
static void uv_from_jitter_v2(float uv[2])
static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *_data)
static void * extract_lines_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf))
static void mesh_edituv_stretch_area_finish(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, void *UNUSED(data))
static void * extract_edituv_points_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(ibo))
void() ExtractPolyBMeshFn(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *data)
static void extract_edge_idx_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *data)
static const MeshExtract extract_points
struct MeshExtract_FdotUV_Data MeshExtract_FdotUV_Data
static void extract_vert_idx_iter_ledge_mesh(const MeshRenderData *mr, const ExtractLEdgeMesh_Params *params, void *data)
static const MeshExtract extract_lnor_hq
static void * extract_select_fdot_idx_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
static void extract_edit_data_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *_data)
static void extract_points_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *elb)
static void extract_lnor_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *data)
#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END
static void * extract_skin_roots_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
BLI_INLINE const float * bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve)
static void * extract_edge_fac_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
struct ExtractSingleThreadedTaskData ExtractSingleThreadedTaskData
struct MeshExtract_Weight_Data MeshExtract_Weight_Data
#define TEST_ASSIGN(type, type_lowercase, name)
BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, int v1)
struct ExtractLVertBMesh_Params ExtractLVertBMesh_Params
struct MeshExtract_LineAdjacency_Data MeshExtract_LineAdjacency_Data
void() ExtractLEdgeBMeshFn(const MeshRenderData *mr, const ExtractLEdgeBMesh_Params *params, void *data)
static void * extract_fdots_pos_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio)
static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *data)
static void user_data_init_task_data_exec(void *__restrict task_data)
static void extract_poly_idx_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *data)
struct UVStretchAngle UVStretchAngle
static struct TaskNode * extract_single_threaded_task_node_create(struct TaskGraph *task_graph, ExtractSingleThreadedTaskData *task_data)
static void extract_orco_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *data)
static void extract_lines_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *elb)
static void * extract_fdots_uv_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
#define EXTRACT_LEDGE_FOREACH_BM_END
static void extract_fdots_edituv_data_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *_data)
static void extract_run(void *__restrict taskdata)
static const MeshExtract extract_fdots_uv
static void * extract_points_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf))
static void extract_edit_data_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *_data)
#define EXTRACT_POLY_FOREACH_BM_END
static const MeshExtract extract_edituv_stretch_angle
static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *_data)
static void extract_range_task_create(struct TaskGraph *task_graph, struct TaskNode *task_node_user_data_init, ExtractTaskData *taskdata, const eMRIterType type, int start, int length)
#define EXTRACT_LVERT_FOREACH_MESH_BEGIN(elem, index_lvert, params, mr)
static ExtractTaskData * extract_task_data_create_lines_loose(const MeshRenderData *mr, struct MeshBatchCache *cache)
static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData *mr, const struct ExtractTriMesh_Params *params, void *data)
static void mesh_render_data_face_flag(const MeshRenderData *mr, BMFace *efa, const int cd_ofs, EditLoopData *eattr)
static const MeshExtract extract_mesh_analysis
BLI_INLINE float thickness_remap(float fac, float min, float max, float minmax_irange)
static const MeshExtract extract_pos_nor
static const MeshExtract extract_edit_data
#define EXTRACT_LVERT_FOREACH_BM_BEGIN(elem_vert, index_lvert, params)
struct MeshExtract_PosNorHQ_Data MeshExtract_PosNorHQ_Data
static void extract_fdots_uv_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf), void *data)
struct MeshExtract_EditUVFdotData_Data MeshExtract_EditUVFdotData_Data
static void * extract_sculpt_data_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
static void extract_fdots_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *ibo, void *elb)
struct PosNorLoop PosNorLoop
static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *data)
struct ExtractLEdgeMesh_Params ExtractLEdgeMesh_Params
BLI_INLINE float sharp_remap(float fac, float min, float UNUSED(max), float minmax_irange)
static const MeshExtract extract_skin_roots
static void * extract_edituv_stretch_angle_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
void() ExtractFinishFn(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buffer, void *data)
static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeightState *wstate)
static void extract_pos_nor_iter_ledge_bm(const MeshRenderData *mr, const ExtractLEdgeBMesh_Params *params, void *_data)
static const MeshExtract extract_lines_paint_mask
static void mesh_render_data_update_loose_geom(MeshRenderData *mr, const eMRIterType iter_type, const eMRDataType UNUSED(data_flag))
static void extract_pos_nor_hq_iter_ledge_mesh(const MeshRenderData *mr, const ExtractLEdgeMesh_Params *params, void *_data)
static void extract_fdots_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *elb)
static void * extract_edituv_tris_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(ibo))
static void extract_fdot_idx_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *data)
static void mesh_render_data_free(MeshRenderData *mr)
static void extract_points_iter_lvert_bm(const MeshRenderData *mr, const ExtractLVertBMesh_Params *params, void *elb)
#define EXTRACT(buf, name)
BLI_INLINE void edituv_edge_add(MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, int v1, int v2)
static void extract_edge_idx_iter_ledge_bm(const MeshRenderData *mr, const ExtractLEdgeBMesh_Params *params, void *data)
static void * extract_lnor_hq_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
static void extract_lines_adjacency_iter_looptri_bm(const MeshRenderData *UNUSED(mr), const struct ExtractTriBMesh_Params *params, void *data)
static const MeshExtract extract_tan_hq
static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *data)
static void extract_edituv_stretch_angle_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *_data)
static const MeshExtract extract_tan
static void statvis_calc_overhang(const MeshRenderData *mr, float *r_overhang)
static void extract_pos_nor_hq_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, void *_data)
struct gpuHQNor gpuHQNor
static void * extract_edituv_lines_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(ibo))
static ExtractTaskData * extract_task_data_create_mesh_extract(const MeshRenderData *mr, struct MeshBatchCache *cache, const MeshExtract *extract, void *buf, int32_t *task_counter)
static void * extract_orco_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp)
BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, const eMRIterType iter_type, int start, int end, const MeshExtract *extract, void *user_data)
static void user_data_init_task_data_free(UserDataInitTaskData *taskdata)
static void extract_points_iter_lvert_mesh(const MeshRenderData *mr, const ExtractLVertMesh_Params *params, void *elb)
BLI_INLINE void lines_adjacency_triangle(uint v1, uint v2, uint v3, uint l1, uint l2, uint l3, MeshExtract_LineAdjacency_Data *data)
static void * extract_pos_nor_hq_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
static void extract_pos_nor_iter_lvert_bm(const MeshRenderData *mr, const ExtractLVertBMesh_Params *params, void *_data)
static void extract_weights_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *_data)
static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort)
static void compute_normalize_edge_vectors(float auv[2][2], float av[2][3], const float uv[2], const float uv_prev[2], const float co[3], const float co_prev[3])
struct MeshExtract_EditUVData_Data MeshExtract_EditUVData_Data
static const MeshExtract extract_edituv_lines
static const MeshExtract extract_lines_adjacency
struct SkinRootData SkinRootData
void() ExtractLEdgeMeshFn(const MeshRenderData *mr, const ExtractLEdgeMesh_Params *params, void *data)
static void extract_tris_iter_looptri_mesh(const MeshRenderData *mr, const struct ExtractTriMesh_Params *params, void *_data)
static void * extract_pos_nor_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data, bool hidden, bool selected, int face_index)
#define NOR_AND_FLAG_HIDDEN
static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *ibo, void *data)
static void extract_vert_idx_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *data)
static void extract_edituv_tris_iter_looptri_bm(const MeshRenderData *UNUSED(mr), const struct ExtractTriBMesh_Params *params, void *data)
static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr, const ExtractLVertMesh_Params *params, void *_data)
#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(elem_tri, index_tri, params)
void() ExtractLVertMeshFn(const MeshRenderData *mr, const ExtractLVertMesh_Params *params, void *data)
static struct TaskNode * user_data_init_task_node_create(struct TaskGraph *task_graph, UserDataInitTaskData *task_data)
static void extract_fdots_nor_hq_finish(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(data))
void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, MeshBatchCache *cache, MeshBufferCache mbc, Mesh *me, const bool is_editmode, const bool is_paint_mode, const bool is_mode_active, const float obmat[4][4], const bool do_final, const bool do_uvedit, const bool use_subsurf_fdots, const DRW_MeshCDMask *cd_layer_used, const Scene *scene, const ToolSettings *ts, const bool use_hide)
static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, void *data)
#define EXTRACT_LVERT_FOREACH_MESH_END
struct EditLoopData EditLoopData
static void mesh_render_data_loop_flag(const MeshRenderData *mr, BMLoop *l, const int cd_ofs, EditLoopData *eattr)
static void extract_task_data_free(void *data)
static void * extract_fdots_nor_hq_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
static void mesh_render_data_loop_edge_flag(const MeshRenderData *mr, BMLoop *l, const int cd_ofs, EditLoopData *eattr)
static void * extract_edituv_stretch_area_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf)
struct MeshExtract_Orco_Data MeshExtract_Orco_Data
@ VFLAG_EDGE_SEAM
@ VFLAG_EDGE_FREESTYLE
@ VFLAG_EDGE_ACTIVE
@ VFLAG_EDGE_SHARP
@ VFLAG_EDGE_SELECTED
@ VFLAG_VERT_SELECTED
@ VFLAG_VERT_ACTIVE
@ VFLAG_FACE_UV_ACTIVE
@ VFLAG_FACE_ACTIVE
@ VFLAG_VERT_UV_PINNED
@ VFLAG_FACE_UV_SELECT
@ VFLAG_FACE_SELECTED
@ VFLAG_VERT_UV_SELECT
@ VFLAG_FACE_FREESTYLE
@ VFLAG_EDGE_UV_SELECT
void * tree
uint pos
uint nor
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define atan2f(x, y)
#define fabsf(x)
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
format
Definition: logImageCore.h:47
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
MINLINE unsigned short unit_float_to_ushort_clamp(float val)
float BLI_color_from_srgb_table[256]
Definition: math_color.c:556
static unsigned a[3]
Definition: RandGen.cpp:92
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
INLINE Rall1d< T, V, S > tan(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:327
static void area(int d1, int d2, int e1, int e2, float weights[2])
#define min(a, b)
Definition: sort.c:51
signed short int16_t
Definition: stdint.h:79
unsigned short uint16_t
Definition: stdint.h:82
unsigned int uint32_t
Definition: stdint.h:83
signed int int32_t
Definition: stdint.h:80
unsigned char uint8_t
Definition: stdint.h:81
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
struct BMLoop * l
Definition: bmesh_class.h:140
struct Mesh * mesh_eval_final
Definition: BKE_editmesh.h:63
struct Mesh * mesh_eval_cage
Definition: BKE_editmesh.h:63
struct BMLoop *(* looptris)[3]
Definition: BKE_editmesh.h:60
struct BMesh * bm
Definition: BKE_editmesh.h:52
short mat_nr
Definition: bmesh_class.h:281
int len
Definition: bmesh_class.h:279
float no[3]
Definition: bmesh_class.h:280
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109
float no[3]
Definition: bmesh_class.h:100
int totvert
Definition: bmesh_class.h:297
CustomData vdata
Definition: bmesh_class.h:337
int totedge
Definition: bmesh_class.h:297
CustomData edata
Definition: bmesh_class.h:337
int totloop
Definition: bmesh_class.h:297
CustomData pdata
Definition: bmesh_class.h:337
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
BVHTree_RayCastCallback raycast_callback
Definition: BKE_bvhutils.h:70
float no[3]
Definition: BLI_kdopbvh.h:86
float const (* polyNos)[3]
const float(* polyCos)[3]
float const (* vertexNos)[3]
const float(* vertexCos)[3]
ExtractTaskDataType tasktype
struct MeshBatchCache * cache
const MeshExtract * extract
const MeshRenderData * mr
ExtractUserData * user_data
unsigned int v1
unsigned int v2
unsigned char a
unsigned char b
unsigned char r
unsigned char g
unsigned int poly
unsigned int tri[3]
unsigned int e
unsigned int v
short mat_nr
float color[4]
float co[3]
short no[3]
DRW_MeshCDMask cd_used
struct DRW_MeshWeightState weight_state
MeshBufferCache final
struct MeshBufferCache::@261 ibo
GPUIndexBuf ** tris_per_mat
GPUIndexBuf * lines
GPUIndexBuf * lines_loose
const DRW_MeshWeightState * wstate
ExtractFinishFn * finish
ExtractLVertBMeshFn * iter_lvert_bm
ExtractLVertMeshFn * iter_lvert_mesh
ExtractLEdgeBMeshFn * iter_ledge_bm
ExtractTriBMeshFn * iter_looptri_bm
const eMRDataType data_flag
ExtractPolyBMeshFn * iter_poly_bm
ExtractLEdgeMeshFn * iter_ledge_mesh
ExtractPolyMeshFn * iter_poly_mesh
ExtractTriMeshFn * iter_looptri_mesh
ExtractInitFn * init
eMRExtractType extract_type
const float(* bm_vert_normals)[3]
const float(* bm_poly_centers)[3]
const float(* bm_poly_normals)[3]
EditMeshData * edit_data
const float(* bm_vert_coords)[3]
const ToolSettings * toolsettings
struct EditMeshData * edit_data
struct MEdge * medge
struct BMEditMesh * edit_mesh
float smoothresh
struct CustomData pdata ldata
struct MVert * mvert
int totedge
int totvert
short flag
struct MLoop * mloop
Mesh_Runtime runtime
int totpoly
int face_sets_color_seed
int face_sets_color_default
int totloop
struct MPoly * mpoly
GPUPackedNormal nor
struct RenderData r
void * task_data
Definition: task_graph.cc:57
struct MeshStatVis statvis
double PIL_check_seconds_timer(void)
Definition: time.c:80
float max
__forceinline ssef high(const avxf &a)
Definition: util_avxf.h:281
__forceinline const avxi abs(const avxi &a)
Definition: util_avxi.h:186
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
uint len