Blender V4.3
bmesh_mesh_tessellate.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
14#include "MEM_guardedalloc.h"
15
16#include "BLI_heap.h"
17#include "BLI_math_geom.h"
18#include "BLI_math_matrix.h"
19#include "BLI_memarena.h"
20#include "BLI_polyfill_2d.h"
22#include "BLI_task.h"
23
24#include "bmesh.hh"
25
27
35#define BM_FACE_TESSELLATE_THREADED_LIMIT 1024
36
37/* -------------------------------------------------------------------- */
44BLI_INLINE void bmesh_calc_tessellation_for_face_impl(std::array<BMLoop *, 3> *looptris,
45 BMFace *efa,
46 MemArena **pf_arena_p,
47 const bool face_normal)
48{
49#ifndef NDEBUG
50 /* The face normal is used for projecting faces into 2D space for tessellation.
51 * Invalid normals may result in invalid tessellation.
52 * Either `face_normal` should be true or normals should be updated first. */
53 BLI_assert(face_normal || BM_face_is_normal_valid(efa));
54#endif
55
56 switch (efa->len) {
57 case 3: {
58 /* `0 1 2` -> `0 1 2` */
59 BMLoop *l;
60 BMLoop **l_ptr = looptris[0].data();
61 l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa);
62 l_ptr[1] = l = l->next;
63 l_ptr[2] = l->next;
64 if (face_normal) {
65 normal_tri_v3(efa->no, l_ptr[0]->v->co, l_ptr[1]->v->co, l_ptr[2]->v->co);
66 }
67 break;
68 }
69 case 4: {
70 /* `0 1 2 3` -> (`0 1 2`, `0 2 3`) */
71 BMLoop *l;
72 BMLoop **l_ptr_a = looptris[0].data();
73 BMLoop **l_ptr_b = looptris[1].data();
74 (l_ptr_a[0] = l_ptr_b[0] = l = BM_FACE_FIRST_LOOP(efa));
75 (l_ptr_a[1] = l = l->next);
76 (l_ptr_a[2] = l_ptr_b[1] = l = l->next);
77 (l_ptr_b[2] = l->next);
78
79 if (face_normal) {
81 efa->no, l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co);
82 }
83
85 l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co)))
86 {
87 /* Flip out of degenerate 0-2 state. */
88 l_ptr_a[2] = l_ptr_b[2];
89 l_ptr_b[0] = l_ptr_a[1];
90 }
91 break;
92 }
93 default: {
94 if (face_normal) {
95 BM_face_calc_normal(efa, efa->no);
96 }
97
98 BMLoop *l_iter, *l_first;
99 BMLoop **l_arr;
100
101 float axis_mat[3][3];
102 float(*projverts)[2];
103 uint(*tris)[3];
104
105 const int tris_len = efa->len - 2;
106
107 MemArena *pf_arena = *pf_arena_p;
108 if (UNLIKELY(pf_arena == nullptr)) {
109 pf_arena = *pf_arena_p = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
110 }
111
112 tris = static_cast<uint(*)[3]>(BLI_memarena_alloc(pf_arena, sizeof(*tris) * tris_len));
113 l_arr = static_cast<BMLoop **>(BLI_memarena_alloc(pf_arena, sizeof(*l_arr) * efa->len));
114 projverts = static_cast<float(*)[2]>(
115 BLI_memarena_alloc(pf_arena, sizeof(*projverts) * efa->len));
116
117 axis_dominant_v3_to_m3_negate(axis_mat, efa->no);
118
119 int i = 0;
120 l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
121 do {
122 l_arr[i] = l_iter;
123 mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
124 i++;
125 } while ((l_iter = l_iter->next) != l_first);
126
127 BLI_polyfill_calc_arena(projverts, efa->len, 1, tris, pf_arena);
128
129 for (i = 0; i < tris_len; i++) {
130 BMLoop **l_ptr = looptris[i].data();
131 uint *tri = tris[i];
132
133 l_ptr[0] = l_arr[tri[0]];
134 l_ptr[1] = l_arr[tri[1]];
135 l_ptr[2] = l_arr[tri[2]];
136 }
137
138 BLI_memarena_clear(pf_arena);
139 break;
140 }
141 }
142}
143
144static void bmesh_calc_tessellation_for_face(std::array<BMLoop *, 3> *looptris,
145 BMFace *efa,
146 MemArena **pf_arena_p)
147{
148 bmesh_calc_tessellation_for_face_impl(looptris, efa, pf_arena_p, false);
149}
150
151static void bmesh_calc_tessellation_for_face_with_normal(std::array<BMLoop *, 3> *looptris,
152 BMFace *efa,
153 MemArena **pf_arena_p)
154{
155 bmesh_calc_tessellation_for_face_impl(looptris, efa, pf_arena_p, true);
156}
157
165 BMesh *bm, MutableSpan<std::array<BMLoop *, 3>> looptris, const char face_normals)
166{
167#ifndef NDEBUG
168 const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
169#endif
170
171 BMIter iter;
172 BMFace *efa;
173 int i = 0;
174
175 MemArena *pf_arena = nullptr;
176
177 if (face_normals) {
178 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
179 BLI_assert(efa->len >= 3);
180 BM_face_calc_normal(efa, efa->no);
181 bmesh_calc_tessellation_for_face_with_normal(looptris.data() + i, efa, &pf_arena);
182 i += efa->len - 2;
183 }
184 }
185 else {
186 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
187 BLI_assert(efa->len >= 3);
188 bmesh_calc_tessellation_for_face(looptris.data() + i, efa, &pf_arena);
189 i += efa->len - 2;
190 }
191 }
192
193 if (pf_arena) {
194 BLI_memarena_free(pf_arena);
195 pf_arena = nullptr;
196 }
197
198 BLI_assert(i <= looptris_tot);
199}
200
204
205static void bmesh_calc_tessellation_for_face_fn(void *__restrict userdata,
206 MempoolIterData *mp_f,
207 const TaskParallelTLS *__restrict tls)
208{
209 TessellationUserTLS *tls_data = static_cast<TessellationUserTLS *>(tls->userdata_chunk);
210 std::array<BMLoop *, 3> *looptris = static_cast<std::array<BMLoop *, 3> *>(userdata);
211 BMFace *f = (BMFace *)mp_f;
213 const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
214 bmesh_calc_tessellation_for_face(looptris + offset, f, &tls_data->pf_arena);
215}
216
217static void bmesh_calc_tessellation_for_face_with_normals_fn(void *__restrict userdata,
218 MempoolIterData *mp_f,
219 const TaskParallelTLS *__restrict tls)
220{
221 TessellationUserTLS *tls_data = static_cast<TessellationUserTLS *>(tls->userdata_chunk);
222 std::array<BMLoop *, 3> *looptris = static_cast<std::array<BMLoop *, 3> *>(userdata);
223 BMFace *f = (BMFace *)mp_f;
225 const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
226 bmesh_calc_tessellation_for_face_with_normal(looptris + offset, f, &tls_data->pf_arena);
227}
228
229static void bmesh_calc_tessellation_for_face_free_fn(const void *__restrict /*userdata*/,
230 void *__restrict tls_v)
231{
232 TessellationUserTLS *tls_data = static_cast<TessellationUserTLS *>(tls_v);
233 if (tls_data->pf_arena) {
234 BLI_memarena_free(tls_data->pf_arena);
235 }
236}
237
239 BMesh *bm, MutableSpan<std::array<BMLoop *, 3>> looptris, const char face_normals)
240{
242
243 TaskParallelSettings settings;
244 TessellationUserTLS tls_dummy = {nullptr};
246 settings.userdata_chunk = &tls_dummy;
247 settings.userdata_chunk_size = sizeof(tls_dummy);
248 settings.func_free = bmesh_calc_tessellation_for_face_free_fn;
249 BM_iter_parallel(bm,
253 looptris.data(),
254 &settings);
255}
256
258 MutableSpan<std::array<BMLoop *, 3>> looptris,
260{
262 bm_mesh_calc_tessellation__single_threaded(bm, looptris, params->face_normals);
263 }
264 else {
265 bm_mesh_calc_tessellation__multi_threaded(bm, looptris, params->face_normals);
266 }
267}
268
269void BM_mesh_calc_tessellation(BMesh *bm, MutableSpan<std::array<BMLoop *, 3>> looptris)
270{
272 params.face_normals = false;
274}
275
278/* -------------------------------------------------------------------- */
286
290
291static void bmesh_calc_tessellation_for_face_partial_fn(void *__restrict userdata,
292 const int index,
293 const TaskParallelTLS *__restrict tls)
294{
296 tls->userdata_chunk);
297 PartialTessellationUserData *data = static_cast<PartialTessellationUserData *>(userdata);
298 BMFace *f = data->faces[index];
300 const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
301 bmesh_calc_tessellation_for_face(data->looptris.data() + offset, f, &tls_data->pf_arena);
302}
303
305 void *__restrict userdata, const int index, const TaskParallelTLS *__restrict tls)
306{
308 tls->userdata_chunk);
309 PartialTessellationUserData *data = static_cast<PartialTessellationUserData *>(userdata);
310 BMFace *f = data->faces[index];
312 const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
314 data->looptris.data() + offset, f, &tls_data->pf_arena);
315}
316
317static void bmesh_calc_tessellation_for_face_partial_free_fn(const void *__restrict /*userdata*/,
318 void *__restrict tls_v)
319{
320 PartialTessellationUserTLS *tls_data = static_cast<PartialTessellationUserTLS *>(tls_v);
321 if (tls_data->pf_arena) {
322 BLI_memarena_free(tls_data->pf_arena);
323 }
324}
325
327 MutableSpan<std::array<BMLoop *, 3>> looptris,
328 const BMPartialUpdate *bmpinfo,
330{
331 const int faces_len = bmpinfo->faces_len;
332 BMFace **faces = bmpinfo->faces;
333
335 data.faces = faces;
336 data.looptris = looptris;
337
338 PartialTessellationUserTLS tls_dummy = {nullptr};
339 TaskParallelSettings settings;
341 settings.use_threading = true;
342 settings.userdata_chunk = &tls_dummy;
343 settings.userdata_chunk_size = sizeof(tls_dummy);
345
347 faces_len,
348 &data,
349 params->face_normals ?
352 &settings);
353}
354
356 MutableSpan<std::array<BMLoop *, 3>> looptris,
357 const BMPartialUpdate *bmpinfo,
359{
360 const int faces_len = bmpinfo->faces_len;
361 BMFace **faces = bmpinfo->faces;
362
363 MemArena *pf_arena = nullptr;
364
365 if (params->face_normals) {
366 for (int index = 0; index < faces_len; index++) {
367 BMFace *f = faces[index];
369 const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
370 bmesh_calc_tessellation_for_face_with_normal(looptris.data() + offset, f, &pf_arena);
371 }
372 }
373 else {
374 for (int index = 0; index < faces_len; index++) {
375 BMFace *f = faces[index];
377 const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
378 bmesh_calc_tessellation_for_face(looptris.data() + offset, f, &pf_arena);
379 }
380 }
381
382 if (pf_arena) {
383 BLI_memarena_free(pf_arena);
384 }
385}
386
388 MutableSpan<std::array<BMLoop *, 3>> looptris,
389 const BMPartialUpdate *bmpinfo,
391{
393 /* While harmless, exit early if there is nothing to do (avoids ensuring the index). */
394 if (UNLIKELY(bmpinfo->faces_len == 0)) {
395 return;
396 }
397
399
402 }
403 else {
405 }
406}
407
409 MutableSpan<std::array<BMLoop *, 3>> looptris,
410 const BMPartialUpdate *bmpinfo)
411{
412 BM_mesh_calc_tessellation_with_partial_ex(bm, looptris, bmpinfo, nullptr);
413}
414
417/* -------------------------------------------------------------------- */
423static int bmesh_calc_tessellation_for_face_beauty(std::array<BMLoop *, 3> *looptris,
424 BMFace *efa,
425 MemArena **pf_arena_p,
426 Heap **pf_heap_p)
427{
428 switch (efa->len) {
429 case 3: {
430 BMLoop *l;
431 BMLoop **l_ptr = looptris[0].data();
432 l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa);
433 l_ptr[1] = l = l->next;
434 l_ptr[2] = l->next;
435 return 1;
436 }
437 case 4: {
438 BMLoop *l_v1 = BM_FACE_FIRST_LOOP(efa);
439 BMLoop *l_v2 = l_v1->next;
440 BMLoop *l_v3 = l_v2->next;
441 BMLoop *l_v4 = l_v1->prev;
442
443/* #BM_verts_calc_rotate_beauty performs excessive checks we don't need!
444 * It's meant for rotating edges, it also calculates a new normal.
445 *
446 * Use #BLI_polyfill_beautify_quad_rotate_calc since we have the normal.
447 */
448#if 0
449 const bool split_13 = (BM_verts_calc_rotate_beauty(
450 l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) < 0.0f);
451#else
452 float axis_mat[3][3], v_quad[4][2];
453 axis_dominant_v3_to_m3(axis_mat, efa->no);
454 mul_v2_m3v3(v_quad[0], axis_mat, l_v1->v->co);
455 mul_v2_m3v3(v_quad[1], axis_mat, l_v2->v->co);
456 mul_v2_m3v3(v_quad[2], axis_mat, l_v3->v->co);
457 mul_v2_m3v3(v_quad[3], axis_mat, l_v4->v->co);
458
459 const bool split_13 = BLI_polyfill_beautify_quad_rotate_calc(
460 v_quad[0], v_quad[1], v_quad[2], v_quad[3]) < 0.0f;
461#endif
462
463 BMLoop **l_ptr_a = looptris[0].data();
464 BMLoop **l_ptr_b = looptris[1].data();
465 if (split_13) {
466 l_ptr_a[0] = l_v1;
467 l_ptr_a[1] = l_v2;
468 l_ptr_a[2] = l_v3;
469
470 l_ptr_b[0] = l_v1;
471 l_ptr_b[1] = l_v3;
472 l_ptr_b[2] = l_v4;
473 }
474 else {
475 l_ptr_a[0] = l_v1;
476 l_ptr_a[1] = l_v2;
477 l_ptr_a[2] = l_v4;
478
479 l_ptr_b[0] = l_v2;
480 l_ptr_b[1] = l_v3;
481 l_ptr_b[2] = l_v4;
482 }
483 return 2;
484 }
485 default: {
486 MemArena *pf_arena = *pf_arena_p;
487 Heap *pf_heap = *pf_heap_p;
488 if (UNLIKELY(pf_arena == nullptr)) {
489 pf_arena = *pf_arena_p = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
490 pf_heap = *pf_heap_p = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
491 }
492
493 BMLoop *l_iter, *l_first;
494 BMLoop **l_arr;
495
496 float axis_mat[3][3];
497 float(*projverts)[2];
498 uint(*tris)[3];
499
500 const int tris_len = efa->len - 2;
501
502 tris = static_cast<uint(*)[3]>(BLI_memarena_alloc(pf_arena, sizeof(*tris) * tris_len));
503 l_arr = static_cast<BMLoop **>(BLI_memarena_alloc(pf_arena, sizeof(*l_arr) * efa->len));
504 projverts = static_cast<float(*)[2]>(
505 BLI_memarena_alloc(pf_arena, sizeof(*projverts) * efa->len));
506
507 axis_dominant_v3_to_m3_negate(axis_mat, efa->no);
508
509 int i = 0;
510 l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
511 do {
512 l_arr[i] = l_iter;
513 mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
514 i++;
515 } while ((l_iter = l_iter->next) != l_first);
516
517 BLI_polyfill_calc_arena(projverts, efa->len, 1, tris, pf_arena);
518
519 BLI_polyfill_beautify(projverts, efa->len, tris, pf_arena, pf_heap);
520
521 for (i = 0; i < tris_len; i++) {
522 BMLoop **l_ptr = looptris[i].data();
523 uint *tri = tris[i];
524
525 l_ptr[0] = l_arr[tri[0]];
526 l_ptr[1] = l_arr[tri[1]];
527 l_ptr[2] = l_arr[tri[2]];
528 }
529
530 BLI_memarena_clear(pf_arena);
531
532 return tris_len;
533 }
534 }
535}
536
537void BM_mesh_calc_tessellation_beauty(BMesh *bm, MutableSpan<std::array<BMLoop *, 3>> looptris)
538{
539#ifndef NDEBUG
540 const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
541#endif
542
543 BMIter iter;
544 BMFace *efa;
545 int i = 0;
546
547 MemArena *pf_arena = nullptr;
548
549 /* use_beauty */
550 Heap *pf_heap = nullptr;
551
552 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
553 BLI_assert(efa->len >= 3);
554 i += bmesh_calc_tessellation_for_face_beauty(looptris.data() + i, efa, &pf_arena, &pf_heap);
555 }
556
557 if (pf_arena) {
558 BLI_memarena_free(pf_arena);
559
560 BLI_heap_free(pf_heap, nullptr);
561 }
562
563 BLI_assert(i <= looptris_tot);
564}
565
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition BLI_heap.c:192
Heap * BLI_heap_new_ex(unsigned int reserve_num) ATTR_WARN_UNUSED_RESULT
Definition BLI_heap.c:172
float normal_quad_v3(float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
Definition math_geom.cc:56
bool is_quad_flip_v3_first_third_fast(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:39
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
#define BLI_MEMARENA_STD_BUFSIZE
void void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
void BLI_polyfill_calc_arena(const float(*coords)[2], unsigned int coords_num, int coords_sign, unsigned int(*r_tris)[3], struct MemArena *arena)
#define BLI_POLYFILL_ALLOC_NGON_RESERVE
#define BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4)
void BLI_polyfill_beautify(const float(*coords)[2], unsigned int coords_num, unsigned int(*tris)[3], struct MemArena *arena, struct Heap *eheap)
unsigned int uint
struct MempoolIterData MempoolIterData
Definition BLI_task.h:209
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:230
BLI_INLINE void BLI_parallel_mempool_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:238
#define UNLIKELY(x)
Read Guarded memory(de)allocation.
float BM_verts_calc_rotate_beauty(const BMVert *v1, const BMVert *v2, const BMVert *v3, const BMVert *v4, const short flag, const short method)
@ BM_LOOP
#define BM_FACE_FIRST_LOOP(p)
#define BM_elem_index_get(ele)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
static void bm_mesh_calc_tessellation__multi_threaded(BMesh *bm, MutableSpan< std::array< BMLoop *, 3 > > looptris, const char face_normals)
void BM_mesh_calc_tessellation_with_partial_ex(BMesh *bm, MutableSpan< std::array< BMLoop *, 3 > > looptris, const BMPartialUpdate *bmpinfo, const BMeshCalcTessellation_Params *params)
static void bmesh_calc_tessellation_for_face_with_normal(std::array< BMLoop *, 3 > *looptris, BMFace *efa, MemArena **pf_arena_p)
static void bmesh_calc_tessellation_for_face_partial_with_normals_fn(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict tls)
void BM_mesh_calc_tessellation(BMesh *bm, MutableSpan< std::array< BMLoop *, 3 > > looptris)
static int bmesh_calc_tessellation_for_face_beauty(std::array< BMLoop *, 3 > *looptris, BMFace *efa, MemArena **pf_arena_p, Heap **pf_heap_p)
static void bm_mesh_calc_tessellation_with_partial__single_threaded(MutableSpan< std::array< BMLoop *, 3 > > looptris, const BMPartialUpdate *bmpinfo, const BMeshCalcTessellation_Params *params)
static void bm_mesh_calc_tessellation_with_partial__multi_threaded(MutableSpan< std::array< BMLoop *, 3 > > looptris, const BMPartialUpdate *bmpinfo, const BMeshCalcTessellation_Params *params)
static void bmesh_calc_tessellation_for_face_free_fn(const void *__restrict, void *__restrict tls_v)
#define BM_FACE_TESSELLATE_THREADED_LIMIT
static void bm_mesh_calc_tessellation__single_threaded(BMesh *bm, MutableSpan< std::array< BMLoop *, 3 > > looptris, const char face_normals)
BM_mesh_calc_tessellation get the looptris and its number from a certain bmesh.
void BM_mesh_calc_tessellation_ex(BMesh *bm, MutableSpan< std::array< BMLoop *, 3 > > looptris, const BMeshCalcTessellation_Params *params)
static void bmesh_calc_tessellation_for_face_with_normals_fn(void *__restrict userdata, MempoolIterData *mp_f, const TaskParallelTLS *__restrict tls)
void BM_mesh_calc_tessellation_beauty(BMesh *bm, MutableSpan< std::array< BMLoop *, 3 > > looptris)
static void bmesh_calc_tessellation_for_face(std::array< BMLoop *, 3 > *looptris, BMFace *efa, MemArena **pf_arena_p)
static void bmesh_calc_tessellation_for_face_partial_free_fn(const void *__restrict, void *__restrict tls_v)
void BM_mesh_calc_tessellation_with_partial(BMesh *bm, MutableSpan< std::array< BMLoop *, 3 > > looptris, const BMPartialUpdate *bmpinfo)
static void bmesh_calc_tessellation_for_face_fn(void *__restrict userdata, MempoolIterData *mp_f, const TaskParallelTLS *__restrict tls)
static void bmesh_calc_tessellation_for_face_partial_fn(void *__restrict userdata, const int index, const TaskParallelTLS *__restrict tls)
BLI_INLINE void bmesh_calc_tessellation_for_face_impl(std::array< BMLoop *, 3 > *looptris, BMFace *efa, MemArena **pf_arena_p, const bool face_normal)
#define BM_FACE
float BM_face_calc_normal(const BMFace *f, float r_no[3])
BMESH UPDATE FACE NORMAL.
bool BM_face_is_normal_valid(const BMFace *f)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
draw_view in_light_buf[] float
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static char faces[256]
float no[3]
struct BMVert * v
struct BMLoop * prev
struct BMLoop * next
BMPartialUpdate_Params params
float co[3]
int totloop
int totface
MutableSpan< std::array< BMLoop *, 3 > > looptris