40#define USE_TRIANGULATE
42#define USE_VERT_NORMAL_INTERP
45#define USE_TOPOLOGY_FALLBACK
46#ifdef USE_TOPOLOGY_FALLBACK
48# define TOPOLOGY_FALLBACK_EPS 1e-12f
51#define BOUNDARY_PRESERVE_WEIGHT 100.0f
56#define OPTIMIZE_EPS 1e-8
57#define COST_INVALID FLT_MAX
95 }
while ((l_iter = l_iter->
next) != l_first);
101 float edge_vector[3];
103 double edge_plane_db[4];
142 optimize_co[0] = 0.5 * (double(
e->v1->co[0]) + double(
e->v2->co[0]));
143 optimize_co[1] = 0.5 * (double(
e->v1->co[1]) + double(
e->v2->co[1]));
144 optimize_co[2] = 0.5 * (double(
e->v1->co[2]) + double(
e->v2->co[2]));
149 double optimize_co_db[3];
160 for (
i = 0;
i < 2;
i++) {
165 if (
l->e !=
e &&
l->prev->e !=
e) {
166 const float *co_prev =
l->prev->v->co;
167 const float *co_next =
l->next->v->co;
168 float cross_exist[3];
169 float cross_optim[3];
187 if (
dot_v3v3(cross_exist, cross_optim) <=
198 if (
dot_v3v3(cross_exist, cross_optim) <= FLT_EPSILON) {
210#ifdef USE_TOPOLOGY_FALLBACK
232 const float *vweights,
233 const float vweight_factor,
247 if (
e->l->f->len == 3) {
256 if ((
e->l->f->len == 3) && (
e->l->radial_next->f->len == 3)) {
270 double optimize_co[3];
284#ifdef USE_TOPOLOGY_FALLBACK
290 if (vweights ==
nullptr) {
301 cost *= 1.0f + (e_weight * vweight_factor);
338 const float *vweights,
339 const float vweight_factor,
349 eheap_table[
i] =
nullptr;
376 float e_other_dir[3];
406 int *edge_symmetry_map;
407 const float limit_sq =
square_f(limit);
410 tree = BLI_kdtree_3d_new(
bm->totedge);
418 BLI_kdtree_3d_insert(
tree,
i, co);
420 edge_symmetry_map[
i] = -1;
423 BLI_kdtree_3d_balance(
tree);
429 if (edge_symmetry_map[
i] == -1) {
432 co[symmetry_axis] *= -1.0f;
436 sym_data.
e_v1_co[symmetry_axis] *= -1.0f;
437 sym_data.
e_v2_co[symmetry_axis] *= -1.0f;
445 edge_symmetry_map[
i] = i_other;
446 edge_symmetry_map[i_other] =
i;
452 BLI_kdtree_3d_free(
tree);
454 return edge_symmetry_map;
458#ifdef USE_TRIANGULATE
477 int *r_edges_tri_tot,
483 const int f_base_len = f_base->
len;
484 int faces_array_tot = f_base_len - 3;
485 int edges_array_tot = f_base_len - 3;
488 const int quad_method = 0, ngon_method = 0;
490 bool has_cut =
false;
507 for (
int i = 0;
i < edges_array_tot;
i++) {
509 l_iter = l_first = edges_array[
i]->
l;
513 }
while ((l_iter = l_iter->
radial_next) != l_first);
516 for (
int i = 0;
i < faces_array_tot;
i++) {
520 *r_edges_tri_tot += edges_array_tot;
529 bool has_ngon =
false;
530 bool has_cut =
false;
542 }
while ((l_iter = l_iter->
next) != l_first);
544 has_ngon |= (f->
len > 4);
579 while (faces_double) {
610 MEM_mallocN(std::min(edges_tri_tot,
bm->totedge) *
sizeof(*edges_tri), __func__));
613 STACK_INIT(edges_tri, std::min(edges_tri_tot,
bm->totedge));
620 if (l_a_index != -1) {
622 if (l_a_index == l_b_index) {
623 if (l_a->
v !=
l_b->v) {
626# define CAN_LOOP_MERGE(l) \
627 (BM_loop_is_manifold(l) && ((l)->v != (l)->radial_next->v) && \
628 (l_a_index == BM_elem_index_get(l)) && (l_a_index == BM_elem_index_get((l)->radial_next)))
641 BLI_assert(
ELEM(vquad[0], vquad[1], vquad[2], vquad[3]) ==
false);
642 BLI_assert(
ELEM(vquad[1], vquad[0], vquad[2], vquad[3]) ==
false);
643 BLI_assert(
ELEM(vquad[2], vquad[1], vquad[0], vquad[3]) ==
false);
644 BLI_assert(
ELEM(vquad[3], vquad[1], vquad[2], vquad[0]) ==
false);
646 if (!
is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) {
650# undef CAN_LOOP_MERGE
670 "Doubled face detected at " AT ". Resulting mesh may be corrupt.");
672 if (
e->l ==
nullptr) {
697 BMLoop *l_clear, *l_other;
702 if (
l->v == v_clear) {
717 for (side = 0; side < 2; side++) {
719 bool is_seam =
false;
722 BMFace *f_exit = is_manifold ?
l->radial_next->f :
nullptr;
729 l_iter = l_first = l_clear;
733 w[0] = customdata_fac;
734 w[1] = 1.0f - customdata_fac;
737 l_iter = l_first = l_other;
741 w[0] = 1.0f - customdata_fac;
742 w[1] = customdata_fac;
753 if (f_exit &&
UNLIKELY(f_exit == l_iter->
f)) {
763 for (
i = 0;
i <
bm->ldata.totlayer;
i++) {
765 const int offset =
bm->ldata.layers[
i].offset;
766 const int type =
bm->ldata.layers[
i].type;
767 const void *cd_src[2] = {
815 if (
e->l !=
e->l->radial_next) {
827 if (
e->l !=
e->l->radial_next) {
907 l_radial = e_first->
l;
915 if (l_radial != l_face) {
949 int r_e_clear_other[2],
951 int *edge_symmetry_map,
955 const float customdata_fac
969 BMEdge *e_a_other[2], *e_b_other[2];
981 e_a_other[0] = l_a->
prev->
e;
982 e_a_other[1] = l_a->
next->
e;
985 e_a_other[1] = l_a->
prev->
e;
986 e_a_other[0] = l_a->
next->
e;
990 e_b_other[0] =
l_b->prev->e;
991 e_b_other[1] =
l_b->next->e;
994 e_b_other[1] =
l_b->prev->e;
995 e_b_other[0] =
l_b->next->e;
1006 if (
ELEM(e_a_other[0], e_b_other[0], e_b_other[1]) ||
1007 ELEM(e_a_other[1], e_b_other[0], e_b_other[1]))
1018#ifdef USE_CUSTOMDATA
1046 if (edge_symmetry_map) {
1047 if (edge_symmetry_map[r_e_clear_other[0]] != -1) {
1048 edge_symmetry_map[edge_symmetry_map[r_e_clear_other[0]]] =
BM_elem_index_get(e_a_other[1]);
1050 if (edge_symmetry_map[r_e_clear_other[1]] != -1) {
1051 edge_symmetry_map[edge_symmetry_map[r_e_clear_other[1]]] =
BM_elem_index_get(e_b_other[1]);
1071 e_a_other[0] = l_a->
prev->
e;
1072 e_a_other[1] = l_a->
next->
e;
1075 e_a_other[1] = l_a->
prev->
e;
1076 e_a_other[0] = l_a->
next->
e;
1080 r_e_clear_other[1] = -1;
1082#ifdef USE_CUSTOMDATA
1105 if (edge_symmetry_map) {
1106 if (edge_symmetry_map[r_e_clear_other[0]] != -1) {
1107 edge_symmetry_map[edge_symmetry_map[r_e_clear_other[0]]] =
BM_elem_index_get(e_a_other[1]);
1128 const float vweight_factor,
1132 int *edge_symmetry_map,
1135 float optimize_co[3],
1136 bool optimize_co_calc)
1138 int e_clear_other[2];
1143 float customdata_fac;
1145#ifdef USE_VERT_NORMAL_INTERP
1146 float v_clear_no[3];
1151 if (optimize_co_calc) {
1174 if (customdata_fac < 0.0 - FLT_EPSILON || customdata_fac > 1.0f + FLT_EPSILON) {
1181 customdata_fac = 0.5f;
1198 float v_other_weight =
interpf(
1199 vweights[v_other_index], vweights[v_clear_index], customdata_fac);
1200 CLAMP(v_other_weight, 0.0f, 1.0f);
1201 vweights[v_other_index] = v_other_weight;
1210 for (
i = 0;
i < 2;
i++) {
1212 if ((e_clear_other[
i] != -1) && (eheap_table[e_clear_other[
i]] !=
nullptr)) {
1214 eheap_table[e_clear_other[
i]] =
nullptr;
1225#ifdef USE_VERT_NORMAL_INTERP
1236 e_iter = e_first = v_other->
e;
1240 e_iter, vquadrics, vweights, vweight_factor, eheap, eheap_table);
1253 if (
l->f->len == 3) {
1256 e_outer =
l->next->e;
1259 e_outer =
l->prev->e;
1265 e_outer, vquadrics, vweights, vweight_factor, eheap, eheap_table);
1284 float vweight_factor,
1285 const bool do_triangulate,
1286 const int symmetry_axis,
1287 const float symmetry_eps)
1296 int face_tot_target;
1301 bool use_symmetry = (symmetry_axis != -1);
1302 int *edge_symmetry_map;
1305#ifdef USE_TRIANGULATE
1306 int edges_tri_tot = 0;
1318 tot_edge_orig =
bm->totedge;
1325 face_tot_target =
bm->totface * factor;
1335#ifdef USE_CUSTOMDATA
1350 if (use_symmetry ==
false)
1359 float optimize_co[3];
1395 const int e_index_mirr = edge_symmetry_map[e_index];
1396 BMEdge *e_mirr =
nullptr;
1397 float optimize_co[3];
1398 char e_invalidate = 0;
1402 eheap_table[e_index] =
nullptr;
1404 if (e_index_mirr != -1) {
1405 if (e_index_mirr == e_index) {
1408 else if (eheap_table[e_index_mirr]) {
1436 e_invalidate |= (1 | (e_mirr ? 2 : 0));
1442 if (e_index_mirr == e_index) {
1443 optimize_co[symmetry_axis] = 0.0f;
1448 e_invalidate |= (1 | (e_mirr ? 2 : 0));
1465 if (e_mirr && (eheap_table[e_index_mirr])) {
1468 eheap_table[e_index_mirr] =
nullptr;
1469 optimize_co[symmetry_axis] *= -1.0f;
1484 if (e_mirr && (eheap_table[e_index_mirr])) {
1494 if (e_invalidate & 1) {
1498 if (e_invalidate & 2) {
1499 BLI_assert(eheap_table[e_index_mirr] !=
nullptr);
1501 eheap_table[e_index_mirr] =
nullptr;
1510#ifdef USE_TRIANGULATE
1511 if (do_triangulate ==
false) {
1513 if (
LIKELY(use_triangulate)) {
1529 (void)tot_edge_orig;
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_layer_has_math(const CustomData *data, int layer_n)
bool CustomData_has_interp(const CustomData *data)
void CustomData_bmesh_interp_n(CustomData *data, const void **src_blocks, const float *weights, int count, void *dst_block_ofs, int n)
bool CustomData_data_equals(eCustomDataType type, const void *data1, const void *data2)
bool CustomData_has_math(const CustomData *data)
#define BLI_array_alloca(arr, realsize)
#define BLI_assert_msg(a, msg)
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr) ATTR_NONNULL(1
Heap * BLI_heap_new_ex(unsigned int reserve_num) ATTR_WARN_UNUSED_RESULT
void void bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1)
float BLI_heap_top_value(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1)
void * BLI_heap_node_ptr(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
HeapNode * BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1)
void void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1
A KD-tree for nearest neighbor search.
MINLINE float min_ff(float a, float b)
MINLINE float square_f(float a)
MINLINE float interpf(float target, float origin, float t)
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
MINLINE double normalize_v3_db(double n[3])
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE double dot_v3db_v3fl(const double 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 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
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3fl_v3db(float r[3], const double a[3])
MINLINE void copy_v3db_v3fl(double r[3], const float a[3])
MINLINE bool compare_v3v3(const float v1[3], const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3(float n[3])
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)
#define BLI_POLYFILL_ARENA_SIZE
#define BLI_POLYFILL_ALLOC_NGON_RESERVE
void BLI_quadric_mul(Quadric *a, double scalar)
bool BLI_quadric_optimize(const Quadric *q, double v[3], double epsilon)
void BLI_quadric_from_plane(Quadric *q, const double v[4])
double BLI_quadric_evaluate(const Quadric *q, const double v[3])
void BLI_quadric_add_qu_qu(Quadric *a, const Quadric *b)
void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b)
#define ENUM_OPERATORS(_type, _max)
#define UNUSED_VARS_NDEBUG(...)
#define POINTER_OFFSET(v, ofs)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
Read Guarded memory(de)allocation.
#define BM_FACE_FIRST_LOOP(p)
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
Splice Edge.
BMFace * BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del, BMFace **r_double)
Join Connected Faces.
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
Splice Vert.
void BM_face_kill(BMesh *bm, BMFace *f)
void BM_edge_kill(BMesh *bm, BMEdge *e)
static void bm_edge_tag_enable(BMEdge *e)
static void bm_decim_invalid_edge_cost_single(BMEdge *e, Heap *eheap, HeapNode **eheap_table)
static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
static void bm_decim_build_edge_cost(BMesh *bm, const Quadric *vquadrics, const float *vweights, const float vweight_factor, Heap *eheap, HeapNode **eheap_table)
#define TOPOLOGY_FALLBACK_EPS
static void bm_edge_tag_disable(BMEdge *e)
static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_co[3])
void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, float vweight_factor, const bool do_triangulate, const int symmetry_axis, const float symmetry_eps)
BM_mesh_decimate.
static void bm_decim_triangulate_end(BMesh *bm, const int edges_tri_tot)
static void bm_decim_calc_target_co_fl(BMEdge *e, float optimize_co[3], const Quadric *vquadrics)
static bool bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e_clear_other[2], int *edge_symmetry_map, const CD_UseFlag customdata_flag, const float customdata_fac)
static bool bm_face_triangulate(BMesh *bm, BMFace *f_base, LinkNode **r_faces_double, int *r_edges_tri_tot, MemArena *pf_arena, Heap *pf_heap)
#define BOUNDARY_PRESERVE_WEIGHT
static void bm_decim_build_edge_cost_single(BMEdge *e, const Quadric *vquadrics, const float *vweights, const float vweight_factor, Heap *eheap, HeapNode **eheap_table)
#define CAN_LOOP_MERGE(l)
BLI_INLINE int bm_edge_is_manifold_or_boundary(BMLoop *l)
static float bm_decim_build_edge_cost_single__topology(BMEdge *e)
static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot)
static bool bm_edge_symmetry_check_cb(void *user_data, int index, const float[3], float)
static bool bm_decim_edge_collapse(BMesh *bm, BMEdge *e, Quadric *vquadrics, float *vweights, const float vweight_factor, Heap *eheap, HeapNode **eheap_table, int *edge_symmetry_map, const CD_UseFlag customdata_flag, float optimize_co[3], bool optimize_co_calc)
static void bm_decim_calc_target_co_db(BMEdge *e, double optimize_co[3], const Quadric *vquadrics)
static int * bm_edge_symmetry_map(BMesh *bm, uint symmetry_axis, float limit)
static float bm_decim_build_edge_cost_single_squared__topology(BMEdge *e)
static bool bm_edge_tag_test(BMEdge *e)
static void bm_edge_collapse_loop_customdata(BMesh *bm, BMLoop *l, BMVert *v_clear, BMVert *v_other, const float customdata_fac)
static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics)
#define BM_elem_index_get(ele)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
void BM_data_interp_from_edges(BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, const float fac)
Data, Interpolate From Edges.
void BM_data_interp_from_verts(BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac)
Data, Interpolate From Verts.
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
void BM_vert_normal_update(BMVert *v)
void BM_face_normal_update(BMFace *f)
void BM_face_triangulate(BMesh *bm, BMFace *f, BMFace **r_faces_new, int *r_faces_new_tot, BMEdge **r_edges_new, int *r_edges_new_tot, LinkNode **r_faces_double, const int quad_method, const int ngon_method, const bool use_tag, MemArena *pf_arena, Heap *pf_heap)
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
BMVert * BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
BMLoop * BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step)
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
BMEdge * BM_edge_find_double(BMEdge *e)
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2)
float BM_edge_calc_length(const BMEdge *e)
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
ATTR_WARN_UNUSED_RESULT const BMVert * v
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
SIMD_FORCE_INLINE void invalidate()
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
void * MEM_mallocN(size_t len, const char *str)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
static void clear(Message &msg)
struct BMLoop * radial_next