diff options
Diffstat (limited to 'source/blender/bmesh/operators')
18 files changed, 400 insertions, 120 deletions
diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 07a2e674863..213a0830e63 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -40,6 +40,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) const int seg = BMO_slot_int_get(op->slots_in, "segments"); const bool vonly = BMO_slot_bool_get(op->slots_in, "vertex_only"); const float profile = BMO_slot_float_get(op->slots_in, "profile"); + const int material = BMO_slot_int_get(op->slots_in, "material"); if (offset > 0) { BMOIter siter; @@ -60,7 +61,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) } } - BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, false, NULL, -1); + BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, false, NULL, -1, material); BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); } diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index 9e9cd0d66e2..e4417477e76 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -119,7 +119,7 @@ static void bm_bridge_best_rotation(struct BMEdgeLoopStore *el_store_a, struct B } if (el_b_best) { - BLI_rotatelist_first(lb_b, el_b_best); + BLI_listbase_rotate_first(lb_b, el_b_best); } } @@ -272,7 +272,7 @@ static void bridge_loop_pair(BMesh *bm, const int len_b = BM_edgeloop_length_get(el_store_b); ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); LinkData *el_b = BLI_rfindlink(lb_b, mod_i(twist_offset, len_b)); - BLI_rotatelist_first(lb_b, el_b); + BLI_listbase_rotate_first(lb_b, el_b); } } diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c index 4cf6e82fc8e..0213329118c 100644 --- a/source/blender/bmesh/operators/bmo_connect.c +++ b/source/blender/bmesh/operators/bmo_connect.c @@ -36,54 +36,68 @@ #include "intern/bmesh_operators_private.h" /* own include */ #define VERT_INPUT 1 + #define EDGE_OUT 1 -#define FACE_TAG 2 +/* Edge spans 2 VERT_INPUT's, its a nop, + * but include in "edges.out" */ +#define EDGE_OUT_ADJ 2 + +#define FACE_TAG 2 +#define FACE_EXCLUDE 4 static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenerate) { - BMLoop *(*loops_split)[2] = BLI_array_alloca(loops_split, f->len); + const unsigned pair_split_max = f->len / 2; + BMLoop *(*loops_split)[2] = BLI_array_alloca(loops_split, pair_split_max); STACK_DECLARE(loops_split); - BMVert *(*verts_pair)[2] = BLI_array_alloca(verts_pair, f->len); + BMVert *(*verts_pair)[2] = BLI_array_alloca(verts_pair, pair_split_max); STACK_DECLARE(verts_pair); - BMIter liter; - BMFace *f_new; - BMLoop *l; - BMLoop *l_last; + BMLoop *l_tag_prev = NULL, *l_tag_first = NULL; + BMLoop *l_iter, *l_first; unsigned int i; - STACK_INIT(loops_split, f->len); - STACK_INIT(verts_pair, f->len); + STACK_INIT(loops_split, pair_split_max); + STACK_INIT(verts_pair, pair_split_max); - l_last = NULL; - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (BMO_elem_flag_test(bm, l->v, VERT_INPUT)) { - if (!l_last) { - l_last = l; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (BMO_elem_flag_test(bm, l_iter->v, VERT_INPUT) && + /* ensure this vertex isnt part of a contiguous group */ + ((BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) || + (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0))) + { + if (!l_tag_prev) { + l_tag_prev = l_tag_first = l_iter; continue; } - if (!BM_loop_is_adjacent(l_last, l)) { + if (!BM_loop_is_adjacent(l_tag_prev, l_iter)) { BMEdge *e; - e = BM_edge_exists(l_last->v, l->v); + e = BM_edge_exists(l_tag_prev->v, l_iter->v); if (e == NULL || !BMO_elem_flag_test(bm, e, EDGE_OUT)) { BMLoop **l_pair = STACK_PUSH_RET(loops_split); - l_pair[0] = l_last; - l_pair[1] = l; + l_pair[0] = l_tag_prev; + l_pair[1] = l_iter; } } - l_last = l; + + l_tag_prev = l_iter; } - } + } while ((l_iter = l_iter->next) != l_first); if (STACK_SIZE(loops_split) == 0) { return 0; } - if (STACK_SIZE(loops_split) > 1) { + if (!BM_loop_is_adjacent(l_tag_first, l_tag_prev) && + /* ensure we don't add the same pair twice */ + (((loops_split[0][0] == l_tag_first) && + (loops_split[0][1] == l_tag_prev)) == 0)) + { BMLoop **l_pair = STACK_PUSH_RET(loops_split); - l_pair[0] = loops_split[STACK_SIZE(loops_split) - 2][1]; - l_pair[1] = loops_split[0][0]; + l_pair[0] = l_tag_first; + l_pair[1] = l_tag_prev; } if (check_degenerate) { @@ -105,6 +119,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera } for (i = 0; i < STACK_SIZE(verts_pair); i++) { + BMFace *f_new; BMLoop *l_new; BMLoop *l_a, *l_b; @@ -134,7 +149,6 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) { BMOIter siter; - BMIter iter; BMVert *v; BMFace *f; const bool check_degenerate = BMO_slot_bool_get(op->slots_in, "check_degenerate"); @@ -142,16 +156,35 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) BLI_LINKSTACK_INIT(faces); + /* tag so we won't touch ever (typically hidden faces) */ + BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces_exclude", BM_FACE, FACE_EXCLUDE); + /* add all faces connected to verts */ BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { + BMIter iter; + BMLoop *l_iter; + BMO_elem_flag_enable(bm, v, VERT_INPUT); - BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, FACE_TAG)) { - BMO_elem_flag_enable(bm, f, FACE_TAG); - if (f->len > 3) { - BLI_LINKSTACK_PUSH(faces, f); + BM_ITER_ELEM (l_iter, &iter, v, BM_LOOPS_OF_VERT) { + f = l_iter->f; + if (!BMO_elem_flag_test(bm, f, FACE_EXCLUDE)) { + if (!BMO_elem_flag_test(bm, f, FACE_TAG)) { + BMO_elem_flag_enable(bm, f, FACE_TAG); + if (f->len > 3) { + BLI_LINKSTACK_PUSH(faces, f); + } } } + + /* flag edges even if these are not newly created + * this way cut-pairs that include co-linear edges will get + * predictable output. */ + if (BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT)) { + BMO_elem_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ); + } + if (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT)) { + BMO_elem_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ); + } } } @@ -164,5 +197,5 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) BLI_LINKSTACK_FREE(faces); - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT); + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT | EDGE_OUT_ADJ); } diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c index b497ab2f693..a0acf6ed2c5 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -51,6 +51,15 @@ #define CONNECT_EPS 0.0001f #define VERT_OUT 1 +#define VERT_EXCLUDE 2 + +/* typically hidden faces */ +#define FACE_EXCLUDE 2 + +#define FACE_WALK_TEST(f) (CHECK_TYPE_INLINE(f, BMFace *), \ + BMO_elem_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0) +#define VERT_WALK_TEST(v) (CHECK_TYPE_INLINE(v, BMVert *), \ + BMO_elem_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0) // #define DEBUG_PRINT @@ -59,6 +68,9 @@ typedef struct PathContext { float matrix[3][3]; float axis_sep; + /* only to access BMO flags */ + BMesh *bm_bmoflag; + BMVert *v_a, *v_b; BLI_mempool *link_pool; @@ -134,7 +146,7 @@ static void state_calc_co_pair(const PathContext *pc, static bool state_link_find(PathLinkState *state, BMElem *ele) { PathLink *link = state->link_last; - BLI_assert(ELEM3(ele->head.htype, BM_VERT, BM_EDGE, BM_FACE)); + BLI_assert(ELEM(ele->head.htype, BM_VERT, BM_EDGE, BM_FACE)); if (link) { do { if (link->ele == ele) { @@ -204,8 +216,9 @@ static void state_link_add(PathContext *pc, PathLinkState *state, state->link_last = step_new; } -static PathLinkState *state_dupe_add(PathContext *pc, - PathLinkState *state, const PathLinkState *state_orig) +static PathLinkState *state_dupe_add( + PathContext *pc, + PathLinkState *state, const PathLinkState *state_orig) { state = MEM_mallocN(sizeof(*state), __func__); *state = *state_orig; @@ -214,16 +227,19 @@ static PathLinkState *state_dupe_add(PathContext *pc, } /* walk around the face edges */ -static PathLinkState *state_step__face_edges(PathContext *pc, - PathLinkState *state, const PathLinkState *state_orig, - BMLoop *l_iter, BMLoop *l_last) +static PathLinkState *state_step__face_edges( + PathContext *pc, + PathLinkState *state, const PathLinkState *state_orig, + BMLoop *l_iter, BMLoop *l_last) { do { if (state_isect_co_pair(pc, l_iter->v->co, l_iter->next->v->co)) { BMElem *ele_next = (BMElem *)l_iter->e; BMElem *ele_next_from = (BMElem *)l_iter->f; - if (state_link_find(state, ele_next) == false) { + if (FACE_WALK_TEST((BMFace *)ele_next_from) && + (state_link_find(state, ele_next) == false)) + { if (state_orig->link_last != state->link_last) { state = state_dupe_add(pc, state, state_orig); } @@ -235,16 +251,19 @@ static PathLinkState *state_step__face_edges(PathContext *pc, } /* walk around the face verts */ -static PathLinkState *state_step__face_verts(PathContext *pc, - PathLinkState *state, const PathLinkState *state_orig, - BMLoop *l_iter, BMLoop *l_last) +static PathLinkState *state_step__face_verts( + PathContext *pc, + PathLinkState *state, const PathLinkState *state_orig, + BMLoop *l_iter, BMLoop *l_last) { do { if (state_isect_co_exact(pc, l_iter->v->co)) { BMElem *ele_next = (BMElem *)l_iter->v; BMElem *ele_next_from = (BMElem *)l_iter->f; - if (state_link_find(state, ele_next) == false) { + if (FACE_WALK_TEST((BMFace *)ele_next_from) && + state_link_find(state, ele_next) == false) + { if (state_orig->link_last != state->link_last) { state = state_dupe_add(pc, state, state_orig); } @@ -268,7 +287,9 @@ static bool state_step(PathContext *pc, PathLinkState *state) BMLoop *l_start; BM_ITER_ELEM (l_start, &liter, e, BM_LOOPS_OF_EDGE) { - if (l_start->f != ele_from) { + if ((l_start->f != ele_from) && + FACE_WALK_TEST(l_start->f)) + { /* very similar to block below */ if (BM_vert_in_face(l_start->f, pc->v_b)) { if (state_orig.link_last != state->link_last) { @@ -295,7 +316,9 @@ static bool state_step(PathContext *pc, PathLinkState *state) BMLoop *l_start; BM_ITER_ELEM (l_start, &liter, v, BM_LOOPS_OF_VERT) { - if (l_start->f != ele_from) { + if ((l_start->f != ele_from) && + FACE_WALK_TEST(l_start->f)) + { /* very similar to block above */ if (BM_vert_in_face(l_start->f, pc->v_b)) { BMElem *ele_next = (BMElem *)pc->v_b; @@ -324,8 +347,10 @@ static bool state_step(PathContext *pc, PathLinkState *state) BMIter eiter; BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if ((BMElem *)e != ele_from) { - BMVert *v_other = BM_edge_other_vert(e, v); + BMVert *v_other = BM_edge_other_vert(e, v); + if (((BMElem *)e != ele_from) && + VERT_WALK_TEST(v_other)) + { if (v_other == pc->v_b) { BMElem *ele_next = (BMElem *)pc->v_b; BMElem *ele_next_from = (BMElem *)e; @@ -371,6 +396,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) return; } + pc.bm_bmoflag = bm; pc.v_a = ((BMVert **)op_verts_slot->data.p)[0]; pc.v_b = ((BMVert **)op_verts_slot->data.p)[1]; @@ -384,6 +410,10 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) printf("%s: v_b: %d\n", __func__, BM_elem_index_get(pc.v_b)); #endif + /* tag so we won't touch ever (typically hidden faces) */ + BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces_exclude", BM_FACE, FACE_EXCLUDE); + BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts_exclude", BM_VERT, VERT_EXCLUDE); + /* setup context */ { BLI_listbase_clear(&pc.state_lb); @@ -468,9 +498,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) BLI_remlink(&pc.state_lb, state); MEM_freeN(state); } - else { - found_all = false; - } + found_all = false; } else { /* didn't reach the end, remove it, @@ -481,6 +509,11 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) } if (found_all) { +#ifdef DEBUG + for (state = pc.state_lb.first; state; state = state->next) { + BLI_assert(state->link_last->ele == (BMElem *)pc.v_b); + } +#endif break; } } @@ -533,7 +566,8 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) * always connect even when resulting faces are degenerate [#39418] */ BMOperator op_sub; BMO_op_initf(bm, &op_sub, 0, - "connect_verts verts=%fv", VERT_OUT); + "connect_verts verts=%fv faces_exclude=%s", + VERT_OUT, op, "faces_exclude"); BMO_op_exec(bm, &op_sub); BMO_slot_copy(&op_sub, slots_out, "edges.out", op, slots_out, "edges.out"); diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index 209ca30ddc3..8cd9ee14bcb 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -29,6 +29,7 @@ #include "MEM_guardedalloc.h" #include "BLI_array.h" +#include "BLI_stack.h" #include "BLI_math.h" #include "bmesh.h" @@ -51,6 +52,7 @@ #define VERT_MARK_PAIR 4 #define VERT_TAG 2 #define VERT_ISGC 8 +#define VERT_MARK_TEAR 16 @@ -85,15 +87,20 @@ static bool UNUSED_FUNCTION(check_hole_in_region) (BMesh *bm, BMFace *f) return true; } -static void bm_face_split(BMesh *bm, const short oflag) +static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete) { + BLI_Stack *edge_delete_verts; BMIter iter; BMVert *v; - BMIter liter; + if (use_edge_delete) { + edge_delete_verts = BLI_stack_new(sizeof(BMVert *), __func__); + } + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BMO_elem_flag_test(bm, v, oflag)) { if (BM_vert_is_edge_pair(v) == false) { + BMIter liter; BMLoop *l; BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { if (l->f->len > 3) { @@ -104,8 +111,23 @@ static void bm_face_split(BMesh *bm, const short oflag) } } } + + if (use_edge_delete) { + BLI_stack_push(edge_delete_verts, &v); + } + } + } + } + + if (use_edge_delete) { + while (!BLI_stack_is_empty(edge_delete_verts)) { + /* remove surrounding edges & faces */ + BLI_stack_pop(edge_delete_verts, &v); + while (v->e) { + BM_edge_kill(bm, v->e); } } + BLI_stack_free(edge_delete_verts); } } @@ -268,7 +290,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) } } - bm_face_split(bm, VERT_TAG); + bm_face_split(bm, VERT_TAG, false); } if (use_verts) { @@ -345,13 +367,29 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) BMFace *act_face = bm->act_face; const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split"); + const bool use_boundary_tear = BMO_slot_bool_get(op->slots_in, "use_boundary_tear"); BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { BMO_elem_flag_enable(bm, v, VERT_MARK | VERT_ISGC); } if (use_face_split) { - bm_face_split(bm, VERT_MARK); + bm_face_split(bm, VERT_MARK, false); + } + + if (use_boundary_tear) { + BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { + if (!BM_vert_is_edge_pair(v)) { + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + if (BM_edge_is_boundary(e)) { + BMO_elem_flag_enable(bm, v, VERT_MARK_TEAR); + break; + } + } + } + } + + bm_face_split(bm, VERT_MARK_TEAR, true); } BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index 794c688b26b..cd5592f08c9 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -183,6 +183,7 @@ static BMFace *bmo_face_copy(BMOperator *op, */ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) { + const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history"); BMVert *v = NULL, *v2; BMEdge *e = NULL; @@ -285,6 +286,16 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) /* free pointer hashes */ BLI_ghash_free(vhash, NULL, NULL); BLI_ghash_free(ehash, NULL, NULL); + + if (use_select_history) { + BLI_assert(bm_src == bm_dst); + BMO_mesh_selected_remap( + bm_dst, + slot_vert_map_out, + slot_edge_map_out, + slot_face_map_out, + false); + } } /** diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c index 0c5de590ccf..4423123f65e 100644 --- a/source/blender/bmesh/operators/bmo_edgenet.c +++ b/source/blender/bmesh/operators/bmo_edgenet.c @@ -179,11 +179,11 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) if (!count) { edges1 = edges; - BLI_array_length_set(edges1, BLI_array_count(edges)); + BLI_array_count_set(edges1, BLI_array_count(edges)); } else { edges2 = edges; - BLI_array_length_set(edges2, BLI_array_count(edges)); + BLI_array_count_set(edges2, BLI_array_count(edges)); } BLI_array_empty(edges); diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c index 510c3ae0078..88b53b63abb 100644 --- a/source/blender/bmesh/operators/bmo_extrude.c +++ b/source/blender/bmesh/operators/bmo_extrude.c @@ -53,9 +53,16 @@ enum { void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) { + const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history"); + GHash *select_history_map = NULL; + BMOIter siter; BMFace *f_org; + if (use_select_history) { + select_history_map = BM_select_history_map_create(bm); + } + BMO_ITER (f_org, &siter, op->slots_in, "faces", BM_FACE) { BMFace *f_new; BMLoop *l_org, *l_org_first; @@ -66,6 +73,14 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) f_new = BM_face_copy(bm, bm, f_org, true, true); BMO_elem_flag_enable(bm, f_new, EXT_KEEP); + if (select_history_map) { + BMEditSelection *ese; + ese = BLI_ghash_lookup(select_history_map, f_org); + if (ese) { + ese->ele = (BMElem *)f_new; + } + } + l_org = l_org_first = BM_FACE_FIRST_LOOP(f_org); l_new = BM_FACE_FIRST_LOOP(f_new); @@ -85,10 +100,28 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter); l_side_iter = l_side_iter->next; BM_elem_attrs_copy(bm, bm, l_org, l_side_iter); l_side_iter = l_side_iter->next; BM_elem_attrs_copy(bm, bm, l_org, l_side_iter); + + if (select_history_map) { + BMEditSelection *ese; + + ese = BLI_ghash_lookup(select_history_map, l_org->v); + if (ese) { + ese->ele = (BMElem *)l_new->v; + } + ese = BLI_ghash_lookup(select_history_map, l_org->e); + if (ese) { + ese->ele = (BMElem *)l_new->e; + } + } + } while (((l_new = l_new->next), (l_org = l_org->next)) != l_org_first); } + if (select_history_map) { + BLI_ghash_free(select_history_map, NULL, NULL); + } + BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", EXT_DEL, DEL_ONLYFACES); @@ -157,7 +190,11 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op) BMO_elem_flag_enable(bm, e->v2, EXT_INPUT); } - BMO_op_initf(bm, &dupeop, op->flag, "duplicate geom=%fve", EXT_INPUT); + BMO_op_initf( + bm, &dupeop, op->flag, + "duplicate geom=%fve use_select_history=%b", + EXT_INPUT, BMO_slot_bool_get(op->slots_in, "use_select_history")); + BMO_op_exec(bm, &dupeop); /* disable root flag on all new skin nodes */ @@ -205,10 +242,16 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op) void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) { + const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history"); BMOIter siter; BMVert *v, *dupev; BMEdge *e; const bool has_vskin = CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN); + GHash *select_history_map = NULL; + + if (use_select_history) { + select_history_map = BM_select_history_map_create(bm); + } for (v = BMO_iter_new(&siter, op->slots_in, "verts", BM_VERT); v; v = BMO_iter_step(&siter)) { dupev = BM_vert_create(bm, v->co, v, BM_CREATE_NOP); @@ -217,6 +260,14 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) if (has_vskin) bm_extrude_disable_skin_root(bm, v); + if (select_history_map) { + BMEditSelection *ese; + ese = BLI_ghash_lookup(select_history_map, v); + if (ese) { + ese->ele = (BMElem *)dupev; + } + } + /* not essential, but ensures face normals from extruded edges are contiguous */ if (BM_vert_is_wire_endpoint(v)) { if (v->e->v1 == v) { @@ -228,6 +279,10 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) BMO_elem_flag_enable(bm, e, EXT_KEEP); } + if (select_history_map) { + BLI_ghash_free(select_history_map, NULL, NULL); + } + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, EXT_KEEP); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EXT_KEEP); } @@ -245,8 +300,11 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) BMOpSlot *slot_edges_exclude; /* initialize our sub-operators */ - BMO_op_init(bm, &dupeop, op->flag, "duplicate"); - + BMO_op_initf( + bm, &dupeop, op->flag, + "duplicate use_select_history=%b", + BMO_slot_bool_get(op->slots_in, "use_select_history")); + BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_EDGE | BM_FACE, EXT_INPUT); /* if one flagged face is bordered by an un-flagged face, then we delete diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c index fa77e6b509c..d9f50ac891c 100644 --- a/source/blender/bmesh/operators/bmo_fill_attribute.c +++ b/source/blender/bmesh/operators/bmo_fill_attribute.c @@ -154,7 +154,7 @@ static unsigned int bmesh_face_attribute_fill(BMesh *bm, return face_tot; } -void bmo_face_attribute_fill_exec(BMesh *bm, BMOperator *op) +void bmo_face_attribute_fill_exec(BMesh *bm, BMOperator *op) { const bool use_normals = BMO_slot_bool_get(op->slots_in, "use_normals"); const bool use_data = BMO_slot_bool_get(op->slots_in, "use_data"); diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c index 6a0fca425f8..40f6937245b 100644 --- a/source/blender/bmesh/operators/bmo_fill_grid.c +++ b/source/blender/bmesh/operators/bmo_fill_grid.c @@ -313,12 +313,12 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const unsigned int xt if (use_interp_simple == false) { float co_a[3], co_b[3]; - barycentric_transform( + transform_point_by_tri_v3( co_a, v_grid[x]->co, tri_t[0], tri_t[1], tri_t[2], tri_a[0], tri_a[1], tri_a[2]); - barycentric_transform( + transform_point_by_tri_v3( co_b, v_grid[(xtot * ytot) + (x - xtot)]->co, tri_t[0], tri_t[1], tri_t[2], diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c index 0ca4ddf8d55..f2e5ebad9c8 100644 --- a/source/blender/bmesh/operators/bmo_inset.c +++ b/source/blender/bmesh/operators/bmo_inset.c @@ -389,7 +389,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) const bool use_outset = BMO_slot_bool_get(op->slots_in, "use_outset"); const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary") && (use_outset == false); const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset"); - const bool use_even_boundry = use_even_offset; /* could make own option */ + const bool use_even_boundary = use_even_offset; /* could make own option */ const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset"); const bool use_edge_rail = BMO_slot_bool_get(op->slots_in, "use_edge_rail"); const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate"); @@ -716,7 +716,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) else if (vert_edge_tag_tot == 1) { /* 1 edge user - boundary vert, not so common */ const float *e_no_a = edge_info[vecpair[0]].no; - if (use_even_boundry) { + if (use_even_boundary) { /* This case where only one edge attached to v_split * is used - ei - the face to inset is on a boundary. @@ -984,7 +984,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) if (BM_elem_flag_test(v, BM_ELEM_TAG)) { const float fac = (depth * (use_relative_offset ? bm_edge_info_average_length(v, edge_info) : 1.0f) * - (use_even_boundry ? BM_vert_calc_shell_factor(v) : 1.0f)); + (use_even_boundary ? BM_vert_calc_shell_factor(v) : 1.0f)); madd_v3_v3v3fl(varr_co[i], v->co, v->no, fac); } } diff --git a/source/blender/bmesh/operators/bmo_poke.c b/source/blender/bmesh/operators/bmo_poke.c index 26f20656478..363e395e082 100644 --- a/source/blender/bmesh/operators/bmo_poke.c +++ b/source/blender/bmesh/operators/bmo_poke.c @@ -101,7 +101,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op) do { BMLoop *l_new; - f_new = BM_face_create_quad_tri(bm, l_iter->v, l_iter->next->v, v_center, NULL, f, false); + f_new = BM_face_create_quad_tri(bm, l_iter->v, l_iter->next->v, v_center, NULL, f, BM_CREATE_NOP); l_new = BM_FACE_FIRST_LOOP(f_new); if (i == 0) { diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index f0e31b78ca0..e69dcca6342 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -405,7 +405,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) v2 = eva[icoface[a][1]]; v3 = eva[icoface[a][2]]; - eftemp = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, false); + eftemp = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, BM_CREATE_NOP); BM_ITER_ELEM (l, &liter, eftemp, BM_LOOPS_OF_FACE) { BMO_elem_flag_enable(bm, l->e, EDGE_MARK); @@ -476,14 +476,14 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) tv[monkeyf[i][1] + i - monkeyo], tv[monkeyf[i][2] + i - monkeyo], (monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeyf[i][3] + i - monkeyo] : NULL, - NULL, false); + NULL, BM_CREATE_NOP); BM_face_create_quad_tri(bm, tv[monkeynv + monkeyf[i][2] + i - monkeyo], tv[monkeynv + monkeyf[i][1] + i - monkeyo], tv[monkeynv + monkeyf[i][0] + i - monkeyo], (monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeynv + monkeyf[i][3] + i - monkeyo] : NULL, - NULL, false); + NULL, BM_CREATE_NOP); } MEM_freeN(tv); @@ -535,7 +535,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) if (a && cap_ends) { BMFace *f; - f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, false); + f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); } @@ -553,7 +553,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) if (cap_ends) { BMFace *f; - f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, false); + f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); } @@ -622,12 +622,12 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) if (cap_ends) { BMFace *f; - f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, false); + f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); - f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, false); + f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); } - BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, false); + BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP); } else { firstv1 = v1; @@ -644,9 +644,9 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) if (cap_ends) { BMFace *f; - f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, false); + f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); - f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, false); + f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); } @@ -654,7 +654,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); } - BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, false); + BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP); BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.000001); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); @@ -726,14 +726,14 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op) BMO_elem_flag_enable(bm, v8, VERT_MARK); /* the four sides */ - BM_face_create_quad_tri(bm, v5, v6, v2, v1, NULL, false); - BM_face_create_quad_tri(bm, v6, v7, v3, v2, NULL, false); - BM_face_create_quad_tri(bm, v7, v8, v4, v3, NULL, false); - BM_face_create_quad_tri(bm, v8, v5, v1, v4, NULL, false); + BM_face_create_quad_tri(bm, v5, v6, v2, v1, NULL, BM_CREATE_NOP); + BM_face_create_quad_tri(bm, v6, v7, v3, v2, NULL, BM_CREATE_NOP); + BM_face_create_quad_tri(bm, v7, v8, v4, v3, NULL, BM_CREATE_NOP); + BM_face_create_quad_tri(bm, v8, v5, v1, v4, NULL, BM_CREATE_NOP); /* top/bottom */ - BM_face_create_quad_tri(bm, v1, v2, v3, v4, NULL, false); - BM_face_create_quad_tri(bm, v8, v7, v6, v5, NULL, false); + BM_face_create_quad_tri(bm, v1, v2, v3, v4, NULL, BM_CREATE_NOP); + BM_face_create_quad_tri(bm, v8, v7, v6, v5, NULL, BM_CREATE_NOP); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index 814649c7dbf..75f9feef413 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -528,7 +528,8 @@ static void bmesh_find_doubles_common(BMesh *bm, BMOperator *op, int i, j, keepvert = 0; const float dist = BMO_slot_float_get(op->slots_in, "dist"); - const float dist3 = dist * 3.0f; + const float dist_sq = dist * dist; + const float dist3 = (M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */ /* Test whether keep_verts arg exists and is non-empty */ if (BMO_slot_exists(op->slots_in, "keep_verts")) { @@ -576,7 +577,7 @@ static void bmesh_find_doubles_common(BMesh *bm, BMOperator *op, continue; } - if (compare_len_v3v3(v_check->co, v_other->co, dist)) { + if (compare_len_squared_v3v3(v_check->co, v_other->co, dist_sq)) { /* If one vert is marked as keep, make sure it will be the target */ if (BMO_elem_flag_test(bm, v_other, VERT_KEEP)) { diff --git a/source/blender/bmesh/operators/bmo_smooth_laplacian.c b/source/blender/bmesh/operators/bmo_smooth_laplacian.c index af5f35f2a75..a250c716c16 100644 --- a/source/blender/bmesh/operators/bmo_smooth_laplacian.c +++ b/source/blender/bmesh/operators/bmo_smooth_laplacian.c @@ -156,7 +156,7 @@ static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numFaces, in return sys; } -/* Compute weigth between vertice v_i and all your neighbors +/* Compute weight between vertice v_i and all your neighbors * weight between v_i and v_neighbor * Wij = cot(alpha) + cot(beta) / (4.0 * total area of all faces * sum all weight) * v_i * diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index e13a9df4474..c01ad10d716 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -727,8 +727,8 @@ static void bm_edgering_pair_interpolate(BMesh *bm, LoopPairStore *lpair, tri_tmp = tri_array[i]; - barycentric_transform(co_a, v_a->co, UNPACK3(tri_tmp), UNPACK3(tri_sta)); - barycentric_transform(co_b, v_b->co, UNPACK3(tri_tmp), UNPACK3(tri_end)); + transform_point_by_tri_v3(co_a, v_a->co, UNPACK3(tri_tmp), UNPACK3(tri_sta)); + transform_point_by_tri_v3(co_b, v_b->co, UNPACK3(tri_tmp), UNPACK3(tri_end)); interp_v3_v3v3(((BMVert *)v_iter->data)->co, co_a, co_b, (float)i / (float)(resolu - 1)); } @@ -920,13 +920,13 @@ static void bm_edgering_pair_order(BMesh *bm, } BLI_assert(node != NULL); - BLI_rotatelist_first(lb_b, node); + BLI_listbase_rotate_first(lb_b, node); /* now check we are winding the same way */ if (bm_edgering_pair_order_is_flipped(bm, el_store_a, el_store_b)) { BM_edgeloop_flip(bm, el_store_b); /* re-ensure the first node */ - BLI_rotatelist_first(lb_b, node); + BLI_listbase_rotate_first(lb_b, node); } /* sanity checks that we are aligned & winding now */ diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c index 8e254b2e499..986583cc21b 100644 --- a/source/blender/bmesh/operators/bmo_triangulate.c +++ b/source/blender/bmesh/operators/bmo_triangulate.c @@ -26,10 +26,12 @@ * Triangulate faces, also defines triangle fill. */ +#include "MEM_guardedalloc.h" + #include "DNA_listBase.h" #include "BLI_math.h" -#include "BLI_smallhash.h" +#include "BLI_sort_utils.h" #include "BLI_scanfill.h" #include "bmesh.h" @@ -56,6 +58,10 @@ void bmo_triangulate_exec(BMesh *bm, BMOperator *op) BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); } +struct SortNormal { + float value; /* keep first */ + float no[3]; +}; void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) { @@ -65,54 +71,153 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) BMEdge *e; ScanFillContext sf_ctx; /* ScanFillEdge *sf_edge; */ /* UNUSED */ - ScanFillVert *sf_vert_1, *sf_vert_2; ScanFillFace *sf_tri; - SmallHash hash; - float normal[3], *normal_pt; + GHash *sf_vert_map; + float normal[3]; const int scanfill_flag = BLI_SCANFILL_CALC_HOLES | BLI_SCANFILL_CALC_POLYS | BLI_SCANFILL_CALC_LOOSE; + bool calc_winding = false; - BLI_smallhash_init_ex(&hash, BMO_slot_buffer_count(op->slots_in, "edges")); + sf_vert_map = BLI_ghash_ptr_new_ex(__func__, BMO_slot_buffer_count(op->slots_in, "edges")); BMO_slot_vec_get(op->slots_in, "normal", normal); BLI_scanfill_begin(&sf_ctx); BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { + ScanFillVert *sf_verts[2]; + BMVert **e_verts = &e->v1; + unsigned int i; + BMO_elem_flag_enable(bm, e, EDGE_MARK); - - if ((sf_vert_1 = BLI_smallhash_lookup(&hash, (uintptr_t)e->v1)) == NULL) { - sf_vert_1 = BLI_scanfill_vert_add(&sf_ctx, e->v1->co); - sf_vert_1->tmp.p = e->v1; - BLI_smallhash_insert(&hash, (uintptr_t)e->v1, sf_vert_1); - } - - if ((sf_vert_2 = BLI_smallhash_lookup(&hash, (uintptr_t)e->v2)) == NULL) { - sf_vert_2 = BLI_scanfill_vert_add(&sf_ctx, e->v2->co); - sf_vert_2->tmp.p = e->v2; - BLI_smallhash_insert(&hash, (uintptr_t)e->v2, sf_vert_2); + + calc_winding = (calc_winding || BM_edge_is_boundary(e)); + + for (i = 0; i < 2; i++) { + if ((sf_verts[i] = BLI_ghash_lookup(sf_vert_map, e_verts[i])) == NULL) { + sf_verts[i] = BLI_scanfill_vert_add(&sf_ctx, e_verts[i]->co); + sf_verts[i]->tmp.p = e_verts[i]; + BLI_ghash_insert(sf_vert_map, e_verts[i], sf_verts[i]); + } } - - /* sf_edge = */ BLI_scanfill_edge_add(&sf_ctx, sf_vert_1, sf_vert_2); + /* sf_edge = */ BLI_scanfill_edge_add(&sf_ctx, UNPACK2(sf_verts)); /* sf_edge->tmp.p = e; */ /* UNUSED */ } + BLI_ghash_free(sf_vert_map, NULL, NULL); + if (is_zero_v3(normal)) { - normal_pt = NULL; + /* calculate the normal from the cross product of vert-edge pairs. + * Since we don't know winding, just accumulate */ + ScanFillVert *sf_vert; + struct SortNormal *nors; + const unsigned int nors_tot = BLI_ghash_size(sf_vert_map); + unsigned int i; + bool is_degenerate = true; + + nors = MEM_mallocN(sizeof(*nors) * nors_tot, __func__); + + for (sf_vert = sf_ctx.fillvertbase.first, i = 0; sf_vert; sf_vert = sf_vert->next, i++) { + BMVert *v = sf_vert->tmp.p; + BMIter eiter; + BMEdge *e, *e_pair[2]; + unsigned int e_index = 0; + + nors[i].value = -1.0f; + + /* only use if 'is_degenerate' stays true */ + add_v3_v3(normal, v->no); + + BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { + if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (e_index == 2) { + e_index = 0; + break; + } + e_pair[e_index++] = e; + } + } + + if (e_index == 2) { + float dir_a[3], dir_b[3]; + + is_degenerate = false; + + sub_v3_v3v3(dir_a, v->co, BM_edge_other_vert(e_pair[0], v)->co); + sub_v3_v3v3(dir_b, v->co, BM_edge_other_vert(e_pair[1], v)->co); + + cross_v3_v3v3(nors[i].no, dir_a, dir_b); + nors[i].value = len_squared_v3(nors[i].no); + + /* only to get deterministic behavior (for initial normal) */ + if (len_squared_v3(dir_a) > len_squared_v3(dir_b)) { + negate_v3(nors[i].no); + } + } + } + + if (UNLIKELY(is_degenerate)) { + /* no vertices have 2 edges? + * in this case fall back to the average vertex normals */ + } + else { + qsort(nors, nors_tot, sizeof(*nors), BLI_sortutil_cmp_float_reverse); + + copy_v3_v3(normal, nors[0].no); + for (i = 0; i < nors_tot; i++) { + if (UNLIKELY(nors[i].value == -1.0f)) { + break; + } + if (dot_v3v3(normal, nors[i].no) < 0.0f) { + negate_v3(nors[i].no); + } + add_v3_v3(normal, nors[i].no); + } + normalize_v3(normal); + } + + MEM_freeN(nors); } else { - normalize_v3(normal); - normal_pt = normal; + calc_winding = false; } - BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal_pt); - + normalize_v3(normal); + + BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal); + + + /* if we have existing faces, base winding on those */ + if (calc_winding) { + int winding_votes = 0; + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { + BMVert *v_tri[3] = {sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p}; + unsigned int i, i_prev; + + for (i = 0, i_prev = 2; i < 3; i_prev = i++) { + e = BM_edge_exists(v_tri[i], v_tri[i_prev]); + if (e && BM_edge_is_boundary(e) && BMO_elem_flag_test(bm, e, EDGE_MARK)) { + winding_votes += (e->l->v == v_tri[i]) ? 1 : -1; + } + } + } + + if (winding_votes < 0) { + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { + SWAP(struct ScanFillVert *, sf_tri->v2, sf_tri->v3); + } + } + } + + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { - BMFace *f = BM_face_create_quad_tri(bm, - sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p, NULL, - NULL, true); + BMFace *f; BMLoop *l; BMIter liter; + + f = BM_face_create_quad_tri(bm, + sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p, NULL, + NULL, BM_CREATE_NO_DOUBLE); BMO_elem_flag_enable(bm, f, ELE_NEW); BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { @@ -123,7 +228,6 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) } BLI_scanfill_end(&sf_ctx); - BLI_smallhash_release(&hash); if (use_beauty) { BMOperator bmop; diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index 600386893dd..d2d1c0854de 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -63,7 +63,7 @@ void bmo_transform_exec(BMesh *UNUSED(bm), BMOperator *op) if (!is_zero_m4(mat_space)) { invert_m4_m4(imat_space, mat_space); - mul_serie_m4(mat, imat_space, mat, mat_space, NULL, NULL, NULL, NULL, NULL); + mul_m4_series(mat, imat_space, mat, mat_space); } BMO_ITER (v, &iter, op->slots_in, "verts", BM_VERT) { |