Blender V5.0
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
13
14#include "BLI_heap.h"
15#include "BLI_math_geom.h"
16#include "BLI_math_matrix.h"
17#include "BLI_memarena.h"
18#include "BLI_polyfill_2d.h"
20#include "BLI_task.h"
21
22#include "bmesh.hh"
23
25
33#define BM_FACE_TESSELLATE_THREADED_LIMIT 1024
34
35/* -------------------------------------------------------------------- */
38
42BLI_INLINE void bmesh_calc_tessellation_for_face_impl(std::array<BMLoop *, 3> *looptris,
43 BMFace *efa,
44 MemArena **pf_arena_p,
45 const bool face_normal)
46{
47#ifndef NDEBUG
48 /* The face normal is used for projecting faces into 2D space for tessellation.
49 * Invalid normals may result in invalid tessellation.
50 * Either `face_normal` should be true or normals should be updated first. */
51 BLI_assert(face_normal || BM_face_is_normal_valid(efa));
52#endif
53
54 switch (efa->len) {
55 case 3: {
56 /* `0 1 2` -> `0 1 2` */
57 BMLoop *l;
58 BMLoop **l_ptr = looptris[0].data();
59 l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa);
60 l_ptr[1] = l = l->next;
61 l_ptr[2] = l->next;
62 if (face_normal) {
63 normal_tri_v3(efa->no, l_ptr[0]->v->co, l_ptr[1]->v->co, l_ptr[2]->v->co);
64 }
65 break;
66 }
67 case 4: {
68 /* `0 1 2 3` -> (`0 1 2`, `0 2 3`) */
69 BMLoop *l;
70 BMLoop **l_ptr_a = looptris[0].data();
71 BMLoop **l_ptr_b = looptris[1].data();
72 (l_ptr_a[0] = l_ptr_b[0] = l = BM_FACE_FIRST_LOOP(efa));
73 (l_ptr_a[1] = l = l->next);
74 (l_ptr_a[2] = l_ptr_b[1] = l = l->next);
75 (l_ptr_b[2] = l->next);
76
77 if (face_normal) {
79 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);
80 }
81
83 l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co)))
84 {
85 /* Flip out of degenerate 0-2 state. */
86 l_ptr_a[2] = l_ptr_b[2];
87 l_ptr_b[0] = l_ptr_a[1];
88 }
89 break;
90 }
91 default: {
92 if (face_normal) {
93 BM_face_calc_normal(efa, efa->no);
94 }
95
96 BMLoop *l_iter, *l_first;
97 BMLoop **l_arr;
98
99 float axis_mat[3][3];
100 float (*projverts)[2];
101 uint(*tris)[3];
102
103 const int tris_len = efa->len - 2;
104
105 MemArena *pf_arena = *pf_arena_p;
106 if (UNLIKELY(pf_arena == nullptr)) {
107 pf_arena = *pf_arena_p = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
108 }
109
110 tris = static_cast<uint(*)[3]>(BLI_memarena_alloc(pf_arena, sizeof(*tris) * tris_len));
111 l_arr = static_cast<BMLoop **>(BLI_memarena_alloc(pf_arena, sizeof(*l_arr) * efa->len));
112 projverts = static_cast<float (*)[2]>(
113 BLI_memarena_alloc(pf_arena, sizeof(*projverts) * efa->len));
114
115 axis_dominant_v3_to_m3_negate(axis_mat, efa->no);
116
117 int i = 0;
118 l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
119 do {
120 l_arr[i] = l_iter;
121 mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
122 i++;
123 } while ((l_iter = l_iter->next) != l_first);
124
125 BLI_polyfill_calc_arena(projverts, efa->len, 1, tris, pf_arena);
126
127 for (i = 0; i < tris_len; i++) {
128 BMLoop **l_ptr = looptris[i].data();
129 uint *tri = tris[i];
130
131 l_ptr[0] = l_arr[tri[0]];
132 l_ptr[1] = l_arr[tri[1]];
133 l_ptr[2] = l_arr[tri[2]];
134 }
135
136 BLI_memarena_clear(pf_arena);
137 break;
138 }
139 }
140}
141
142static void bmesh_calc_tessellation_for_face(std::array<BMLoop *, 3> *looptris,
143 BMFace *efa,
144 MemArena **pf_arena_p)
145{
146 bmesh_calc_tessellation_for_face_impl(looptris, efa, pf_arena_p, false);
147}
148
149static void bmesh_calc_tessellation_for_face_with_normal(std::array<BMLoop *, 3> *looptris,
150 BMFace *efa,
151 MemArena **pf_arena_p)
152{
153 bmesh_calc_tessellation_for_face_impl(looptris, efa, pf_arena_p, true);
154}
155
163 BMesh *bm, MutableSpan<std::array<BMLoop *, 3>> looptris, const char face_normals)
164{
165#ifndef NDEBUG
166 const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
167#endif
168
169 BMIter iter;
170 BMFace *efa;
171 int i = 0;
172
173 MemArena *pf_arena = nullptr;
174
175 if (face_normals) {
176 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
177 BLI_assert(efa->len >= 3);
178 BM_face_calc_normal(efa, efa->no);
179 bmesh_calc_tessellation_for_face_with_normal(looptris.data() + i, efa, &pf_arena);
180 i += efa->len - 2;
181 }
182 }
183 else {
184 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
185 BLI_assert(efa->len >= 3);
186 bmesh_calc_tessellation_for_face(looptris.data() + i, efa, &pf_arena);
187 i += efa->len - 2;
188 }
189 }
190
191 if (pf_arena) {
192 BLI_memarena_free(pf_arena);
193 pf_arena = nullptr;
194 }
195
196 BLI_assert(i <= looptris_tot);
197}
198
202
203static void bmesh_calc_tessellation_for_face_fn(void *__restrict userdata,
204 MempoolIterData *mp_f,
205 const TaskParallelTLS *__restrict tls)
206{
207 TessellationUserTLS *tls_data = static_cast<TessellationUserTLS *>(tls->userdata_chunk);
208 std::array<BMLoop *, 3> *looptris = static_cast<std::array<BMLoop *, 3> *>(userdata);
209 BMFace *f = (BMFace *)mp_f;
211 const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
212 bmesh_calc_tessellation_for_face(looptris + offset, f, &tls_data->pf_arena);
213}
214
215static void bmesh_calc_tessellation_for_face_with_normals_fn(void *__restrict userdata,
216 MempoolIterData *mp_f,
217 const TaskParallelTLS *__restrict tls)
218{
219 TessellationUserTLS *tls_data = static_cast<TessellationUserTLS *>(tls->userdata_chunk);
220 std::array<BMLoop *, 3> *looptris = static_cast<std::array<BMLoop *, 3> *>(userdata);
221 BMFace *f = (BMFace *)mp_f;
223 const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
224 bmesh_calc_tessellation_for_face_with_normal(looptris + offset, f, &tls_data->pf_arena);
225}
226
227static void bmesh_calc_tessellation_for_face_free_fn(const void *__restrict /*userdata*/,
228 void *__restrict tls_v)
229{
230 TessellationUserTLS *tls_data = static_cast<TessellationUserTLS *>(tls_v);
231 if (tls_data->pf_arena) {
232 BLI_memarena_free(tls_data->pf_arena);
233 }
234}
235
237 BMesh *bm, MutableSpan<std::array<BMLoop *, 3>> looptris, const char face_normals)
238{
240
241 TaskParallelSettings settings;
242 TessellationUserTLS tls_dummy = {nullptr};
244 settings.userdata_chunk = &tls_dummy;
245 settings.userdata_chunk_size = sizeof(tls_dummy);
247 BM_iter_parallel(bm,
251 looptris.data(),
252 &settings);
253}
254
256 MutableSpan<std::array<BMLoop *, 3>> looptris,
258{
259 if (bm->totface < BM_FACE_TESSELLATE_THREADED_LIMIT) {
260 bm_mesh_calc_tessellation__single_threaded(bm, looptris, params->face_normals);
261 }
262 else {
263 bm_mesh_calc_tessellation__multi_threaded(bm, looptris, params->face_normals);
264 }
265}
266
267void BM_mesh_calc_tessellation(BMesh *bm, MutableSpan<std::array<BMLoop *, 3>> looptris)
268{
270 params.face_normals = false;
272}
273
275
276/* -------------------------------------------------------------------- */
279
284
288
289static void bmesh_calc_tessellation_for_face_partial_fn(void *__restrict userdata,
290 const int index,
291 const TaskParallelTLS *__restrict tls)
292{
294 tls->userdata_chunk);
296 BMFace *f = data->faces[index];
298 const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
299 bmesh_calc_tessellation_for_face(data->looptris.data() + offset, f, &tls_data->pf_arena);
300}
301
303 void *__restrict userdata, const int index, const TaskParallelTLS *__restrict tls)
304{
306 tls->userdata_chunk);
308 BMFace *f = data->faces[index];
310 const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
312 data->looptris.data() + offset, f, &tls_data->pf_arena);
313}
314
315static void bmesh_calc_tessellation_for_face_partial_free_fn(const void *__restrict /*userdata*/,
316 void *__restrict tls_v)
317{
318 PartialTessellationUserTLS *tls_data = static_cast<PartialTessellationUserTLS *>(tls_v);
319 if (tls_data->pf_arena) {
320 BLI_memarena_free(tls_data->pf_arena);
321 }
322}
323
325 MutableSpan<std::array<BMLoop *, 3>> looptris,
326 const BMPartialUpdate *bmpinfo,
328{
329 const int faces_len = bmpinfo->faces.size();
330 BMFace *const *faces = bmpinfo->faces.data();
331
333 data.faces = faces;
334 data.looptris = looptris;
335
336 PartialTessellationUserTLS tls_dummy = {nullptr};
337 TaskParallelSettings settings;
339 settings.use_threading = true;
340 settings.userdata_chunk = &tls_dummy;
341 settings.userdata_chunk_size = sizeof(tls_dummy);
343
345 faces_len,
346 &data,
347 params->face_normals ?
350 &settings);
351}
352
354 MutableSpan<std::array<BMLoop *, 3>> looptris,
355 const BMPartialUpdate *bmpinfo,
357{
358 const int faces_len = bmpinfo->faces.size();
359 BMFace *const *faces = bmpinfo->faces.data();
360
361 MemArena *pf_arena = nullptr;
362
363 if (params->face_normals) {
364 for (int index = 0; index < faces_len; index++) {
365 BMFace *f = faces[index];
367 const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
368 bmesh_calc_tessellation_for_face_with_normal(looptris.data() + offset, f, &pf_arena);
369 }
370 }
371 else {
372 for (int index = 0; index < faces_len; index++) {
373 BMFace *f = faces[index];
375 const int offset = BM_elem_index_get(l) - (BM_elem_index_get(f) * 2);
376 bmesh_calc_tessellation_for_face(looptris.data() + offset, f, &pf_arena);
377 }
378 }
379
380 if (pf_arena) {
381 BLI_memarena_free(pf_arena);
382 }
383}
384
386 MutableSpan<std::array<BMLoop *, 3>> looptris,
387 const BMPartialUpdate *bmpinfo,
389{
391 /* While harmless, exit early if there is nothing to do (avoids ensuring the index). */
392 if (UNLIKELY(bmpinfo->faces.is_empty())) {
393 return;
394 }
395
397
400 }
401 else {
403 }
404}
405
407 MutableSpan<std::array<BMLoop *, 3>> looptris,
408 const BMPartialUpdate *bmpinfo)
409{
410 BM_mesh_calc_tessellation_with_partial_ex(bm, looptris, bmpinfo, nullptr);
411}
412
414
415/* -------------------------------------------------------------------- */
420
421static int bmesh_calc_tessellation_for_face_beauty(std::array<BMLoop *, 3> *looptris,
422 BMFace *efa,
423 MemArena **pf_arena_p,
424 Heap **pf_heap_p)
425{
426 switch (efa->len) {
427 case 3: {
428 BMLoop *l;
429 BMLoop **l_ptr = looptris[0].data();
430 l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa);
431 l_ptr[1] = l = l->next;
432 l_ptr[2] = l->next;
433 return 1;
434 }
435 case 4: {
436 BMLoop *l_v1 = BM_FACE_FIRST_LOOP(efa);
437 BMLoop *l_v2 = l_v1->next;
438 BMLoop *l_v3 = l_v2->next;
439 BMLoop *l_v4 = l_v1->prev;
440
441/* #BM_verts_calc_rotate_beauty performs excessive checks we don't need!
442 * It's meant for rotating edges, it also calculates a new normal.
443 *
444 * Use #BLI_polyfill_beautify_quad_rotate_calc since we have the normal.
445 */
446#if 0
447 const bool split_13 = (BM_verts_calc_rotate_beauty(
448 l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) < 0.0f);
449#else
450 float axis_mat[3][3], v_quad[4][2];
451 axis_dominant_v3_to_m3(axis_mat, efa->no);
452 mul_v2_m3v3(v_quad[0], axis_mat, l_v1->v->co);
453 mul_v2_m3v3(v_quad[1], axis_mat, l_v2->v->co);
454 mul_v2_m3v3(v_quad[2], axis_mat, l_v3->v->co);
455 mul_v2_m3v3(v_quad[3], axis_mat, l_v4->v->co);
456
457 const bool split_13 = BLI_polyfill_beautify_quad_rotate_calc(
458 v_quad[0], v_quad[1], v_quad[2], v_quad[3]) < 0.0f;
459#endif
460
461 BMLoop **l_ptr_a = looptris[0].data();
462 BMLoop **l_ptr_b = looptris[1].data();
463 if (split_13) {
464 l_ptr_a[0] = l_v1;
465 l_ptr_a[1] = l_v2;
466 l_ptr_a[2] = l_v3;
467
468 l_ptr_b[0] = l_v1;
469 l_ptr_b[1] = l_v3;
470 l_ptr_b[2] = l_v4;
471 }
472 else {
473 l_ptr_a[0] = l_v1;
474 l_ptr_a[1] = l_v2;
475 l_ptr_a[2] = l_v4;
476
477 l_ptr_b[0] = l_v2;
478 l_ptr_b[1] = l_v3;
479 l_ptr_b[2] = l_v4;
480 }
481 return 2;
482 }
483 default: {
484 MemArena *pf_arena = *pf_arena_p;
485 Heap *pf_heap = *pf_heap_p;
486 if (UNLIKELY(pf_arena == nullptr)) {
487 pf_arena = *pf_arena_p = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
488 pf_heap = *pf_heap_p = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
489 }
490
491 BMLoop *l_iter, *l_first;
492 BMLoop **l_arr;
493
494 float axis_mat[3][3];
495 float (*projverts)[2];
496 uint(*tris)[3];
497
498 const int tris_len = efa->len - 2;
499
500 tris = static_cast<uint(*)[3]>(BLI_memarena_alloc(pf_arena, sizeof(*tris) * tris_len));
501 l_arr = static_cast<BMLoop **>(BLI_memarena_alloc(pf_arena, sizeof(*l_arr) * efa->len));
502 projverts = static_cast<float (*)[2]>(
503 BLI_memarena_alloc(pf_arena, sizeof(*projverts) * efa->len));
504
505 axis_dominant_v3_to_m3_negate(axis_mat, efa->no);
506
507 int i = 0;
508 l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
509 do {
510 l_arr[i] = l_iter;
511 mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
512 i++;
513 } while ((l_iter = l_iter->next) != l_first);
514
515 BLI_polyfill_calc_arena(projverts, efa->len, 1, tris, pf_arena);
516
517 BLI_polyfill_beautify(projverts, efa->len, tris, pf_arena, pf_heap);
518
519 for (i = 0; i < tris_len; i++) {
520 BMLoop **l_ptr = looptris[i].data();
521 uint *tri = tris[i];
522
523 l_ptr[0] = l_arr[tri[0]];
524 l_ptr[1] = l_arr[tri[1]];
525 l_ptr[2] = l_arr[tri[2]];
526 }
527
528 BLI_memarena_clear(pf_arena);
529
530 return tris_len;
531 }
532 }
533}
534
535void BM_mesh_calc_tessellation_beauty(BMesh *bm, MutableSpan<std::array<BMLoop *, 3>> looptris)
536{
537#ifndef NDEBUG
538 const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
539#endif
540
541 BMIter iter;
542 BMFace *efa;
543 int i = 0;
544
545 MemArena *pf_arena = nullptr;
546
547 /* use_beauty */
548 Heap *pf_heap = nullptr;
549
550 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
551 BLI_assert(efa->len >= 3);
552 i += bmesh_calc_tessellation_for_face_beauty(looptris.data() + i, efa, &pf_arena, &pf_heap);
553 }
554
555 if (pf_arena) {
556 BLI_memarena_free(pf_arena);
557
558 BLI_heap_free(pf_heap, nullptr);
559 }
560
561 BLI_assert(i <= looptris_tot);
562}
563
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_INLINE
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition BLI_heap.cc:191
Heap * BLI_heap_new_ex(unsigned int reserve_num) ATTR_WARN_UNUSED_RESULT
Definition BLI_heap.cc:171
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:58
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:41
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
#define BLI_MEMARENA_STD_BUFSIZE
MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
void BLI_memarena_free(MemArena *ma) ATTR_NONNULL(1)
void * BLI_memarena_alloc(MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
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:200
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:221
BLI_INLINE void BLI_parallel_mempool_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:229
#define UNLIKELY(x)
float BM_verts_calc_rotate_beauty(const BMVert *v1, const BMVert *v2, const BMVert *v3, const BMVert *v4, const short flag, const short method)
#define BM_FACE_FIRST_LOOP(p)
@ BM_LOOP
#define BM_elem_index_get(ele)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
BMesh const char void * data
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
int64_t size() const
bool is_empty() const
T * data()
nullptr float
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static char faces[256]
float no[3]
struct BMVert * v
struct BMLoop * prev
struct BMLoop * next
blender::Vector< BMFace * > faces
BMPartialUpdate_Params params
float co[3]
MutableSpan< std::array< BMLoop *, 3 > > looptris
TaskParallelFreeFunc func_free
Definition BLI_task.h:178
size_t userdata_chunk_size
Definition BLI_task.h:164
i
Definition text_draw.cc:230