diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2015-06-29 17:41:00 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2015-06-29 18:18:11 +0300 |
commit | d140e70c496122915eb5c05aba83153e2e0d7998 (patch) | |
tree | 1e589247d69da64aa7b0e7802319237ec050b5d6 /source/blender/bmesh/operators | |
parent | 147bd16ed1bb3415b30408b0eab110d0854eadd2 (diff) | |
parent | 295d0c52a26730edc6d4ed1276e4051cce006be5 (diff) |
Merge branch 'master' into temp-ghash-experimentstemp-ghash-experiments
Note that 'store hash' feature was removed for now - to complex to maintain (conflicts)
and relatively easy to re-add if we ever really want this one day.
Conflicts:
source/blender/blenlib/BLI_ghash.h
source/blender/blenlib/intern/BLI_ghash.c
source/blender/blenlib/intern/hash_mm2a.c
source/blender/bmesh/tools/bmesh_region_match.c
tests/gtests/blenlib/BLI_ghash_performance_test.cc
tests/gtests/blenlib/BLI_ghash_test.cc
tests/gtests/blenlib/CMakeLists.txt
Diffstat (limited to 'source/blender/bmesh/operators')
17 files changed, 1027 insertions, 408 deletions
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index 6002dcf2c0d..b4570e03c83 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -87,8 +87,9 @@ static void bm_vert_loop_pair(BMesh *bm, BMVert *v1, BMVert *v2, BMLoop **l1, BM } /* el_b can have any offset */ -static float bm_edgeloop_offset_length(LinkData *el_a, LinkData *el_b, - LinkData *el_b_first, const float len_max) +static float bm_edgeloop_offset_length( + LinkData *el_a, LinkData *el_b, + LinkData *el_b_first, const float len_max) { float len = 0.0f; BLI_assert(el_a->prev == NULL); /* must be first */ @@ -137,10 +138,11 @@ static bool bm_edge_test_cb(BMEdge *e, void *bm_v) return BMO_elem_flag_test((BMesh *)bm_v, e, EDGE_MARK); } -static void bridge_loop_pair(BMesh *bm, - struct BMEdgeLoopStore *el_store_a, - struct BMEdgeLoopStore *el_store_b, - const bool use_merge, const float merge_factor, const int twist_offset) +static void bridge_loop_pair( + BMesh *bm, + struct BMEdgeLoopStore *el_store_a, + struct BMEdgeLoopStore *el_store_b, + const bool use_merge, const float merge_factor, const int twist_offset) { const float eps = 0.00001f; LinkData *el_a_first, *el_b_first; diff --git a/source/blender/bmesh/operators/bmo_connect_concave.c b/source/blender/bmesh/operators/bmo_connect_concave.c index a00f65bd10f..107aead6994 100644 --- a/source/blender/bmesh/operators/bmo_connect_concave.c +++ b/source/blender/bmesh/operators/bmo_connect_concave.c @@ -79,8 +79,8 @@ static bool bm_face_split_by_concave( struct Heap *pf_heap, struct EdgeHash *pf_ehash) { const int f_base_len = f_base->len; - int faces_array_tot = f_base->len - 3; - int edges_array_tot = f_base->len - 3; + int faces_array_tot = f_base_len - 3; + int edges_array_tot = f_base_len - 3; BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot); BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot); const int quad_method = 0, ngon_method = 0; /* beauty */ diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c index fbc128b375f..cf0e233fe6c 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -152,8 +152,9 @@ static void min_dist_dir_update(MinDistDir *dist, const float dist_dir[3]) /** \} */ -static int state_isect_co_pair(const PathContext *pc, - const float co_a[3], const float co_b[3]) +static int state_isect_co_pair( + const PathContext *pc, + const float co_a[3], const float co_b[3]) { const float diff_a = dot_m3_v3_row_x((float (*)[3])pc->matrix, co_a) - pc->axis_sep; const float diff_b = dot_m3_v3_row_x((float (*)[3])pc->matrix, co_b) - pc->axis_sep; @@ -169,15 +170,17 @@ static int state_isect_co_pair(const PathContext *pc, } } -static int state_isect_co_exact(const PathContext *pc, - const float co[3]) +static int state_isect_co_exact( + const PathContext *pc, + const float co[3]) { const float diff = dot_m3_v3_row_x((float (*)[3])pc->matrix, co) - pc->axis_sep; return (fabsf(diff) <= CONNECT_EPS); } -static float state_calc_co_pair_fac(const PathContext *pc, - const float co_a[3], const float co_b[3]) +static float state_calc_co_pair_fac( + const PathContext *pc, + const float co_a[3], const float co_b[3]) { float diff_a, diff_b, diff_tot; @@ -187,9 +190,10 @@ static float state_calc_co_pair_fac(const PathContext *pc, return (diff_tot > FLT_EPSILON) ? (diff_a / diff_tot) : 0.5f; } -static void state_calc_co_pair(const PathContext *pc, - const float co_a[3], const float co_b[3], - float r_co[3]) +static void state_calc_co_pair( + const PathContext *pc, + const float co_a[3], const float co_b[3], + float r_co[3]) { const float fac = state_calc_co_pair_fac(pc, co_a, co_b); interp_v3_v3v3(r_co, co_a, co_b, fac); @@ -213,8 +217,9 @@ static bool state_link_find(const PathLinkState *state, BMElem *ele) return false; } -static void state_link_add(PathContext *pc, PathLinkState *state, - BMElem *ele, BMElem *ele_from) +static void state_link_add( + PathContext *pc, PathLinkState *state, + BMElem *ele, BMElem *ele_from) { PathLink *step_new = BLI_mempool_alloc(pc->link_pool); BLI_assert(ele != ele_from); diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index ecb41363761..ac0466a74d2 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -494,7 +494,7 @@ void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op) static void bm_mesh_edge_collapse_flagged(BMesh *bm, const int flag, const short oflag) { - BMO_op_callf(bm, flag, "collapse edges=%fe", oflag); + BMO_op_callf(bm, flag, "collapse edges=%fe uvs=%b", oflag, true); } void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index a5a6480c187..33048e6c86e 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -44,9 +44,10 @@ * * Copy an existing vertex from one bmesh to another. */ -static BMVert *bmo_vert_copy(BMOperator *op, - BMOpSlot *slot_vertmap_out, - BMesh *bm_dst, BMesh *bm_src, BMVert *v_src, GHash *vhash) +static BMVert *bmo_vert_copy( + BMOperator *op, + BMOpSlot *slot_vertmap_out, + BMesh *bm_dst, BMesh *bm_src, BMVert *v_src, GHash *vhash) { BMVert *v_dst; @@ -72,12 +73,13 @@ static BMVert *bmo_vert_copy(BMOperator *op, * * Copy an existing edge from one bmesh to another. */ -static BMEdge *bmo_edge_copy(BMOperator *op, - BMOpSlot *slot_edgemap_out, - BMOpSlot *slot_boundarymap_out, - BMesh *bm_dst, BMesh *bm_src, - BMEdge *e_src, - GHash *vhash, GHash *ehash) +static BMEdge *bmo_edge_copy( + BMOperator *op, + BMOpSlot *slot_edgemap_out, + BMOpSlot *slot_boundarymap_out, + BMesh *bm_dst, BMesh *bm_src, + BMEdge *e_src, + GHash *vhash, GHash *ehash) { BMEdge *e_dst; BMVert *e_dst_v1, *e_dst_v2; @@ -131,11 +133,12 @@ static BMEdge *bmo_edge_copy(BMOperator *op, * * Copy an existing face from one bmesh to another. */ -static BMFace *bmo_face_copy(BMOperator *op, - BMOpSlot *slot_facemap_out, - BMesh *bm_dst, BMesh *bm_src, - BMFace *f_src, - GHash *vhash, GHash *ehash) +static BMFace *bmo_face_copy( + BMOperator *op, + BMOpSlot *slot_facemap_out, + BMesh *bm_dst, BMesh *bm_src, + BMFace *f_src, + GHash *vhash, GHash *ehash) { BMFace *f_dst; BMVert **vtar = BLI_array_alloca(vtar, f_src->len); diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c index aa92c3054cd..435b9e60949 100644 --- a/source/blender/bmesh/operators/bmo_extrude.c +++ b/source/blender/bmesh/operators/bmo_extrude.c @@ -39,6 +39,8 @@ #include "intern/bmesh_operators_private.h" /* own include */ +#define USE_EDGE_REGION_FLAGS + enum { EXT_INPUT = 1, EXT_KEEP = 2, @@ -287,6 +289,39 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EXT_KEEP); } +#ifdef USE_EDGE_REGION_FLAGS +/** + * When create an edge for an extruded face region + * check surrounding edge flags before creating a new edge. + */ +static bool bm_extrude_region_edge_flag(const BMVert *v, char r_e_hflag[2]) +{ + BMEdge *e_iter; + const char hflag_enable = BM_ELEM_SEAM; + const char hflag_disable = BM_ELEM_SMOOTH; + bool ok = false; + + r_e_hflag[0] = 0x0; + r_e_hflag[1] = 0xff; + + /* clear flags on both disks */ + e_iter = v->e; + do { + if (e_iter->l && !BM_edge_is_boundary(e_iter)) { + r_e_hflag[0] |= e_iter->head.hflag; + r_e_hflag[1] &= e_iter->head.hflag; + ok = true; + } + } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != v->e); + + if (ok) { + r_e_hflag[0] &= hflag_enable; + r_e_hflag[1] = hflag_disable & ~r_e_hflag[1]; + } + return ok; +} +#endif /* USE_EDGE_REGION_FLAGS */ + void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) { BMOperator dupeop, delop; @@ -413,6 +448,9 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) slot_edges_exclude = BMO_slot_get(op->slots_in, "edges_exclude"); for (e = BMO_iter_new(&siter, dupeop.slots_out, "boundary_map.out", 0); e; e = BMO_iter_step(&siter)) { BMVert *f_verts[4]; +#ifdef USE_EDGE_REGION_FLAGS + BMEdge *f_edges[4]; +#endif /* this should always be wire, so this is mainly a speedup to avoid map lookup */ if (BM_edge_is_wire(e) && BMO_slot_map_contains(slot_edges_exclude, e)) { @@ -465,8 +503,38 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) f_verts[3] = e_new->v2; } - /* not sure what to do about example face, pass NULL for now */ +#ifdef USE_EDGE_REGION_FLAGS + /* handle new edges */ + f_edges[0] = e; + f_edges[2] = e_new; + + f_edges[1] = BM_edge_exists(f_verts[1], f_verts[2]); + if (f_edges[1] == NULL) { + char e_hflag[2]; + bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[2], e_hflag); + f_edges[1] = BM_edge_create(bm, f_verts[1], f_verts[2], NULL, BM_CREATE_NOP); + if (e_hflag_ok) { + BM_elem_flag_enable(f_edges[1], e_hflag[0]); + BM_elem_flag_disable(f_edges[1], e_hflag[1]); + } + } + + f_edges[3] = BM_edge_exists(f_verts[3], f_verts[0]); + if (f_edges[3] == NULL) { + char e_hflag[2]; + bool e_hflag_ok = bm_extrude_region_edge_flag(f_verts[3], e_hflag); + f_edges[3] = BM_edge_create(bm, f_verts[3], f_verts[0], NULL, BM_CREATE_NOP); + if (e_hflag_ok) { + BM_elem_flag_enable(f_edges[3], e_hflag[0]); + BM_elem_flag_disable(f_edges[3], e_hflag[1]); + } + } + + f = BM_face_create(bm, f_verts, f_edges, 4, NULL, BM_CREATE_NOP); +#else f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true); +#endif + bm_extrude_copy_face_loop_attributes(bm, f); } diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c index d9f50ac891c..85bca744d86 100644 --- a/source/blender/bmesh/operators/bmo_fill_attribute.c +++ b/source/blender/bmesh/operators/bmo_fill_attribute.c @@ -61,8 +61,9 @@ static bool bm_loop_is_face_untag(BMElem *ele, void *UNUSED(user_data)) /** * Copy all attributes from adjacent untagged faces. */ -static void bm_face_copy_shared_all(BMesh *bm, BMLoop *l, - const bool use_normals, const bool use_data) +static void bm_face_copy_shared_all( + BMesh *bm, BMLoop *l, + const bool use_normals, const bool use_data) { BMLoop *l_other = l->radial_next; BMFace *f = l->f, *f_other; @@ -90,8 +91,9 @@ static void bm_face_copy_shared_all(BMesh *bm, BMLoop *l, /** * Flood fill attributes. */ -static unsigned int bmesh_face_attribute_fill(BMesh *bm, - const bool use_normals, const bool use_data) +static unsigned int bmesh_face_attribute_fill( + BMesh *bm, + const bool use_normals, const bool use_data) { BLI_LINKSTACK_DECLARE(loop_queue_prev, BMLoop *); BLI_LINKSTACK_DECLARE(loop_queue_next, BMLoop *); diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c index dd954adcd55..fd1e91a0b30 100644 --- a/source/blender/bmesh/operators/bmo_fill_grid.c +++ b/source/blender/bmesh/operators/bmo_fill_grid.c @@ -114,8 +114,9 @@ static void quad_verts_to_barycentric_tri( /** * Assign a loop pair from 2 verts (which _must_ share an edge) */ -static void bm_loop_pair_from_verts(BMVert *v_a, BMVert *v_b, - BMLoop *l_pair[2]) +static void bm_loop_pair_from_verts( + BMVert *v_a, BMVert *v_b, + BMLoop *l_pair[2]) { BMEdge *e = BM_edge_exists(v_a, v_b); if (e->l) { @@ -185,8 +186,9 @@ static void bm_loop_interp_from_grid_boundary_2(BMesh *bm, BMLoop *l, BMLoop *l_ /** * Avoids calling #barycentric_weights_v2_quad often by caching weights into an array. */ -static void barycentric_weights_v2_grid_cache(const unsigned int xtot, const unsigned int ytot, - float (*weight_table)[4]) +static void barycentric_weights_v2_grid_cache( + const unsigned int xtot, const unsigned int ytot, + float (*weight_table)[4]) { float x_step = 1.0f / (float)(xtot - 1); float y_step = 1.0f / (float)(ytot - 1); @@ -216,9 +218,10 @@ static void barycentric_weights_v2_grid_cache(const unsigned int xtot, const uns * * \param v_grid 2d array of verts, all boundary verts must be set, we fill in the middle. */ -static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const unsigned int xtot, unsigned const int ytot, - const short mat_nr, const bool use_smooth, - const bool use_flip, const bool use_interp_simple) +static void bm_grid_fill_array( + BMesh *bm, BMVert **v_grid, const unsigned int xtot, unsigned const int ytot, + const short mat_nr, const bool use_smooth, + const bool use_flip, const bool use_interp_simple) { const bool use_vert_interp = CustomData_has_interp(&bm->vdata); const bool use_loop_interp = CustomData_has_interp(&bm->ldata); @@ -485,10 +488,11 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const unsigned int xt #undef XY } -static void bm_grid_fill(BMesh *bm, - struct BMEdgeLoopStore *estore_a, struct BMEdgeLoopStore *estore_b, - struct BMEdgeLoopStore *estore_rail_a, struct BMEdgeLoopStore *estore_rail_b, - const short mat_nr, const bool use_smooth, const bool use_interp_simple) +static void bm_grid_fill( + BMesh *bm, + struct BMEdgeLoopStore *estore_a, struct BMEdgeLoopStore *estore_b, + struct BMEdgeLoopStore *estore_rail_a, struct BMEdgeLoopStore *estore_rail_b, + const short mat_nr, const bool use_smooth, const bool use_interp_simple) { #define USE_FLIP_DETECT diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c index fb99c9777d0..2dfad5a1f47 100644 --- a/source/blender/bmesh/operators/bmo_hull.c +++ b/source/blender/bmesh/operators/bmo_hull.c @@ -67,8 +67,9 @@ typedef struct HullTriangle { /*************************** Hull Triangles ***************************/ -static void hull_add_triangle(BMesh *bm, GSet *hull_triangles, BLI_mempool *pool, - BMVert *v1, BMVert *v2, BMVert *v3) +static void hull_add_triangle( + BMesh *bm, GSet *hull_triangles, BLI_mempool *pool, + BMVert *v1, BMVert *v2, BMVert *v3) { HullTriangle *t; int i; @@ -189,8 +190,9 @@ static LinkData *final_edges_find_link(ListBase *adj, BMVert *v) return NULL; } -static int hull_final_edges_lookup(HullFinalEdges *final_edges, - BMVert *v1, BMVert *v2) +static int hull_final_edges_lookup( + HullFinalEdges *final_edges, + BMVert *v1, BMVert *v2) { ListBase *adj; @@ -259,8 +261,9 @@ static void hull_final_edges_free(HullFinalEdges *final_edges) /**************************** Final Output ****************************/ -static void hull_remove_overlapping(BMesh *bm, GSet *hull_triangles, - HullFinalEdges *final_edges) +static void hull_remove_overlapping( + BMesh *bm, GSet *hull_triangles, + HullFinalEdges *final_edges) { GSetIterator hull_iter; @@ -296,8 +299,9 @@ static void hull_remove_overlapping(BMesh *bm, GSet *hull_triangles, } } -static void hull_mark_interior_elements(BMesh *bm, BMOperator *op, - HullFinalEdges *final_edges) +static void hull_mark_interior_elements( + BMesh *bm, BMOperator *op, + HullFinalEdges *final_edges) { BMEdge *e; BMFace *f; @@ -425,8 +429,9 @@ static int hull_input_vert_count(BMOperator *op) return count; } -static BMVert **hull_input_verts_copy(BMOperator *op, - const int num_input_verts) +static BMVert **hull_input_verts_copy( + BMOperator *op, + const int num_input_verts) { BMOIter oiter; BMVert *v; @@ -441,8 +446,9 @@ static BMVert **hull_input_verts_copy(BMOperator *op, return input_verts; } -static float (*hull_verts_for_bullet(BMVert **input_verts, - const int num_input_verts))[3] +static float (*hull_verts_for_bullet( + BMVert **input_verts, + const int num_input_verts))[3] { float (*coords)[3] = MEM_callocN(sizeof(*coords) * num_input_verts, __func__); int i; @@ -454,9 +460,10 @@ static float (*hull_verts_for_bullet(BMVert **input_verts, return coords; } -static BMVert **hull_verts_from_bullet(plConvexHull hull, - BMVert **input_verts, - const int num_input_verts) +static BMVert **hull_verts_from_bullet( + plConvexHull hull, + BMVert **input_verts, + const int num_input_verts) { const int num_verts = plConvexHullNumVertices(hull); BMVert **hull_verts = MEM_mallocN(sizeof(*hull_verts) * @@ -478,9 +485,10 @@ static BMVert **hull_verts_from_bullet(plConvexHull hull, return hull_verts; } -static void hull_from_bullet(BMesh *bm, BMOperator *op, - GSet *hull_triangles, - BLI_mempool *pool) +static void hull_from_bullet( + BMesh *bm, BMOperator *op, + GSet *hull_triangles, + BLI_mempool *pool) { int *fvi = NULL; BLI_array_declare(fvi); @@ -529,6 +537,9 @@ static void hull_from_bullet(BMesh *bm, BMOperator *op, } BLI_array_free(fvi); + + plConvexHullDelete(hull); + MEM_freeN(hull_verts); MEM_freeN(coords); MEM_freeN(input_verts); diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c index 27e140eb990..6664bf6dc46 100644 --- a/source/blender/bmesh/operators/bmo_inset.c +++ b/source/blender/bmesh/operators/bmo_inset.c @@ -660,9 +660,10 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) es->l = es->e_old->l; /* must be a boundary */ } - /* run the separate arg */ - bmesh_edge_separate(bm, es->e_old, es->l, false); + if (!BM_edge_is_boundary(es->e_old)) { + bmesh_edge_separate(bm, es->e_old, es->l, false); + } /* calc edge-split info */ es->e_new = es->l->e; @@ -974,7 +975,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) v_glue = v_split; } else { - BM_vert_splice(bm, v_split, v_glue); + BM_vert_splice(bm, v_glue, v_split); } } } diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c index 6562f26062f..b873e6bacb3 100644 --- a/source/blender/bmesh/operators/bmo_join_triangles.c +++ b/source/blender/bmesh/operators/bmo_join_triangles.c @@ -42,173 +42,276 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define FACE_OUT (1 << 0) - /* assumes edges are validated before reaching this poin */ -static float measure_facepair(const float v1[3], const float v2[3], - const float v3[3], const float v4[3], float limit) +static float quad_calc_error( + const float v1[3], const float v2[3], + const float v3[3], const float v4[3]) { /* gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make */ /* Note: this is more complicated than it needs to be and should be cleaned up.. */ - float n1[3], n2[3], measure = 0.0f, angle1, angle2, diff; - float edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3]; - float minarea, maxarea, areaA, areaB; - - /* First Test: Normal difference */ - normal_tri_v3(n1, v1, v2, v3); - normal_tri_v3(n2, v1, v3, v4); - angle1 = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2); - - normal_tri_v3(n1, v2, v3, v4); - normal_tri_v3(n2, v4, v1, v2); - angle2 = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2); - - measure += (angle1 + angle2) * 0.5f; - if (measure > limit) { - return measure; + float error = 0.0f; + + /* Normal difference */ + { + float n1[3], n2[3]; + float angle_a, angle_b; + float diff; + + normal_tri_v3(n1, v1, v2, v3); + normal_tri_v3(n2, v1, v3, v4); + angle_a = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2); + + normal_tri_v3(n1, v2, v3, v4); + normal_tri_v3(n2, v4, v1, v2); + angle_b = (compare_v3v3(n1, n2, FLT_EPSILON)) ? 0.0f : angle_normalized_v3v3(n1, n2); + + diff = (angle_a + angle_b) / (float)(M_PI * 2); + + error += diff; } - /* Second test: Colinearity */ - sub_v3_v3v3(edgeVec1, v1, v2); - sub_v3_v3v3(edgeVec2, v2, v3); - sub_v3_v3v3(edgeVec3, v3, v4); - sub_v3_v3v3(edgeVec4, v4, v1); - - normalize_v3(edgeVec1); - normalize_v3(edgeVec2); - normalize_v3(edgeVec3); - normalize_v3(edgeVec4); - - /* a completely skinny face is 'pi' after halving */ - diff = 0.25f * (fabsf(angle_normalized_v3v3(edgeVec1, edgeVec2) - (float)M_PI_2) + - fabsf(angle_normalized_v3v3(edgeVec2, edgeVec3) - (float)M_PI_2) + - fabsf(angle_normalized_v3v3(edgeVec3, edgeVec4) - (float)M_PI_2) + - fabsf(angle_normalized_v3v3(edgeVec4, edgeVec1) - (float)M_PI_2)); - - if (!diff) { - return 0.0; + /* Colinearity */ + { + float edge_vecs[4][3]; + float diff; + + sub_v3_v3v3(edge_vecs[0], v1, v2); + sub_v3_v3v3(edge_vecs[1], v2, v3); + sub_v3_v3v3(edge_vecs[2], v3, v4); + sub_v3_v3v3(edge_vecs[3], v4, v1); + + normalize_v3(edge_vecs[0]); + normalize_v3(edge_vecs[1]); + normalize_v3(edge_vecs[2]); + normalize_v3(edge_vecs[3]); + + /* a completely skinny face is 'pi' after halving */ + diff = (fabsf(angle_normalized_v3v3(edge_vecs[0], edge_vecs[1]) - (float)M_PI_2) + + fabsf(angle_normalized_v3v3(edge_vecs[1], edge_vecs[2]) - (float)M_PI_2) + + fabsf(angle_normalized_v3v3(edge_vecs[2], edge_vecs[3]) - (float)M_PI_2) + + fabsf(angle_normalized_v3v3(edge_vecs[3], edge_vecs[0]) - (float)M_PI_2)) / (float)(M_PI * 2); + + error += diff; } - measure += diff; - if (measure > limit) { - return measure; + /* Concavity */ + { + float area_min, area_max, area_a, area_b; + float diff; + + area_a = area_tri_v3(v1, v2, v3) + area_tri_v3(v1, v3, v4); + area_b = area_tri_v3(v2, v3, v4) + area_tri_v3(v4, v1, v2); + + area_min = min_ff(area_a, area_b); + area_max = max_ff(area_a, area_b); + + diff = area_max ? (1.0 - (area_min / area_max)) : 1.0f; + + error += diff; } - /* Third test: Concavity */ - areaA = area_tri_v3(v1, v2, v3) + area_tri_v3(v1, v3, v4); - areaB = area_tri_v3(v2, v3, v4) + area_tri_v3(v4, v1, v2); + return error; +} + +static void bm_edge_to_quad_verts(const BMEdge *e, const BMVert *r_v_quad[4]) +{ + BLI_assert(e->l->f->len == 3 && e->l->radial_next->f->len == 3); + BLI_assert(BM_edge_is_manifold(e)); + r_v_quad[0] = e->l->v; + r_v_quad[1] = e->l->prev->v; + r_v_quad[2] = e->l->next->v; + r_v_quad[3] = e->l->radial_next->prev->v; +} + +/* cache customdata delimiters */ +struct DelimitData_CD { + int cd_type; + int cd_size; + int cd_offset; + int cd_offset_end; +}; + +struct DelimitData { + unsigned int do_seam : 1; + unsigned int do_sharp : 1; + unsigned int do_mat : 1; + unsigned int do_angle_face : 1; + unsigned int do_angle_shape : 1; - if (areaA <= areaB) minarea = areaA; - else minarea = areaB; + float angle_face; + float angle_face__cos; - if (areaA >= areaB) maxarea = areaA; - else maxarea = areaB; + float angle_shape; - if (!maxarea) measure += 1; - else measure += (1 - (minarea / maxarea)); + struct DelimitData_CD cdata[4]; + int cdata_len; +}; - return measure; +static bool bm_edge_is_contiguous_loop_cd_all( + const BMEdge *e, const struct DelimitData_CD *delimit_data) +{ + int cd_offset; + for (cd_offset = delimit_data->cd_offset; + cd_offset < delimit_data->cd_offset_end; + cd_offset += delimit_data->cd_size) + { + if (BM_edge_is_contiguous_loop_cd(e, delimit_data->cd_type, cd_offset) == false) { + return false; + } + } + + return true; } -#define T2QUV_LIMIT 0.005f -#define T2QCOL_LIMIT 3 +static bool bm_edge_delimit_cdata( + CustomData *ldata, CustomDataType type, + struct DelimitData_CD *r_delim_cd) +{ + const int layer_len = CustomData_number_of_layers(ldata, type); + r_delim_cd->cd_type = type; + r_delim_cd->cd_size = CustomData_sizeof(r_delim_cd->cd_type); + r_delim_cd->cd_offset = CustomData_get_n_offset(ldata, type, 0); + r_delim_cd->cd_offset_end = r_delim_cd->cd_size * layer_len; + return (r_delim_cd->cd_offset != -1); +} -static bool bm_edge_faces_cmp(BMesh *bm, BMEdge *e, const bool do_uv, const bool do_tf, const bool do_vcol) +static float bm_edge_is_delimit( + const BMEdge *e, + const struct DelimitData *delimit_data) { - /* first get loops */ - BMLoop *l[4]; - - l[0] = e->l; - l[2] = e->l->radial_next; - - /* match up loops on each side of an edge corresponding to each vert */ - if (l[0]->v == l[2]->v) { - l[1] = l[0]->next; - l[3] = l[1]->next; + BMFace *f_a = e->l->f, *f_b = e->l->radial_next->f; +#if 0 + const bool is_contig = BM_edge_is_contiguous(e); + float angle; +#endif + + if ((delimit_data->do_seam) && + (BM_elem_flag_test(e, BM_ELEM_SEAM))) + { + goto fail; } - else { - l[1] = l[0]->next; - l[3] = l[2]; - l[2] = l[3]->next; + if ((delimit_data->do_sharp) && + (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == 0)) + { + goto fail; } - /* Test UV's */ - if (do_uv) { - const MLoopUV *luv[4] = { - CustomData_bmesh_get(&bm->ldata, l[0]->head.data, CD_MLOOPUV), - CustomData_bmesh_get(&bm->ldata, l[1]->head.data, CD_MLOOPUV), - CustomData_bmesh_get(&bm->ldata, l[2]->head.data, CD_MLOOPUV), - CustomData_bmesh_get(&bm->ldata, l[3]->head.data, CD_MLOOPUV), - }; - - /* do UV */ - if (luv[0] && (!compare_v2v2(luv[0]->uv, luv[2]->uv, T2QUV_LIMIT) || - !compare_v2v2(luv[1]->uv, luv[3]->uv, T2QUV_LIMIT))) - { - return false; + if ((delimit_data->do_mat) && + (f_a->mat_nr != f_b->mat_nr)) + { + goto fail; + } + + if (delimit_data->do_angle_face) { + if (dot_v3v3(f_a->no, f_b->no) < delimit_data->angle_face__cos) { + goto fail; } } - if (do_tf) { - const MTexPoly *tp[2] = { - CustomData_bmesh_get(&bm->pdata, l[0]->f->head.data, CD_MTEXPOLY), - CustomData_bmesh_get(&bm->pdata, l[1]->f->head.data, CD_MTEXPOLY), - }; + if (delimit_data->do_angle_shape) { + const BMVert *verts[4]; + bm_edge_to_quad_verts(e, verts); - if (tp[0] && (tp[0]->tpage != tp[1]->tpage)) { - return false; + /* if we're checking the shape at all, a flipped face is out of the question */ + if (is_quad_flip_v3(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co)) { + goto fail; + } + else { + float edge_vecs[4][3]; + + sub_v3_v3v3(edge_vecs[0], verts[0]->co, verts[1]->co); + sub_v3_v3v3(edge_vecs[1], verts[1]->co, verts[2]->co); + sub_v3_v3v3(edge_vecs[2], verts[2]->co, verts[3]->co); + sub_v3_v3v3(edge_vecs[3], verts[3]->co, verts[0]->co); + + normalize_v3(edge_vecs[0]); + normalize_v3(edge_vecs[1]); + normalize_v3(edge_vecs[2]); + normalize_v3(edge_vecs[3]); + + if ((fabsf(angle_normalized_v3v3(edge_vecs[0], edge_vecs[1]) - (float)M_PI_2) > delimit_data->angle_shape) || + (fabsf(angle_normalized_v3v3(edge_vecs[1], edge_vecs[2]) - (float)M_PI_2) > delimit_data->angle_shape) || + (fabsf(angle_normalized_v3v3(edge_vecs[2], edge_vecs[3]) - (float)M_PI_2) > delimit_data->angle_shape) || + (fabsf(angle_normalized_v3v3(edge_vecs[3], edge_vecs[0]) - (float)M_PI_2) > delimit_data->angle_shape)) + { + goto fail; + } } } - /* Test Vertex Colors */ - if (do_vcol) { - const MLoopCol *lcol[4] = { - CustomData_bmesh_get(&bm->ldata, l[0]->head.data, CD_MLOOPCOL), - CustomData_bmesh_get(&bm->ldata, l[1]->head.data, CD_MLOOPCOL), - CustomData_bmesh_get(&bm->ldata, l[2]->head.data, CD_MLOOPCOL), - CustomData_bmesh_get(&bm->ldata, l[3]->head.data, CD_MLOOPCOL), - }; - - if (lcol[0]) { - if (!compare_rgb_uchar((unsigned char *)&lcol[0]->r, (unsigned char *)&lcol[2]->r, T2QCOL_LIMIT) || - !compare_rgb_uchar((unsigned char *)&lcol[1]->r, (unsigned char *)&lcol[3]->r, T2QCOL_LIMIT)) - { - return false; + if (delimit_data->cdata_len) { + int i; + for (i = 0; i < delimit_data->cdata_len; i++) { + if (!bm_edge_is_contiguous_loop_cd_all(e, &delimit_data->cdata[i])) { + goto fail; } } } + return false; + +fail: return true; } -#define EDGE_MARK 1 -#define EDGE_CHOSEN 2 - -#define FACE_MARK 1 -#define FACE_INPUT 2 - +#define EDGE_MARK (1 << 0) +#define FACE_OUT (1 << 0) +#define FACE_INPUT (1 << 2) void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) { - const bool do_sharp = BMO_slot_bool_get(op->slots_in, "cmp_sharp"); - const bool do_uv = BMO_slot_bool_get(op->slots_in, "cmp_uvs"); - const bool do_tf = do_uv; /* texture face, make make its own option eventually */ - const bool do_vcol = BMO_slot_bool_get(op->slots_in, "cmp_vcols"); - const bool do_mat = BMO_slot_bool_get(op->slots_in, "cmp_materials"); - const float limit = BMO_slot_float_get(op->slots_in, "limit"); + float angle_face, angle_shape; BMIter iter; BMOIter siter; BMFace *f; - BMEdge *e, *e_next; + BMEdge *e; /* data: edge-to-join, sort_value: error weight */ struct SortPointerByFloat *jedges; unsigned i, totedge; unsigned int totedge_tag = 0; + struct DelimitData delimit_data = {0}; + + delimit_data.do_seam = BMO_slot_bool_get(op->slots_in, "cmp_seam"); + delimit_data.do_sharp = BMO_slot_bool_get(op->slots_in, "cmp_sharp"); + delimit_data.do_mat = BMO_slot_bool_get(op->slots_in, "cmp_materials"); + + angle_face = BMO_slot_float_get(op->slots_in, "angle_face_threshold"); + if (angle_face < DEG2RADF(180.0f)) { + delimit_data.angle_face = angle_face; + delimit_data.angle_face__cos = cosf(angle_face); + delimit_data.do_angle_face = true; + } + else { + delimit_data.do_angle_face = false; + } + + angle_shape = BMO_slot_float_get(op->slots_in, "angle_shape_threshold"); + if (angle_shape < DEG2RADF(180.0f)) { + delimit_data.angle_shape = angle_shape; + delimit_data.do_angle_shape = true; + } + else { + delimit_data.do_angle_shape = false; + } + + if (BMO_slot_bool_get(op->slots_in, "cmp_uvs") && + bm_edge_delimit_cdata(&bm->ldata, CD_MLOOPUV, &delimit_data.cdata[delimit_data.cdata_len])) + { + delimit_data.cdata_len += 1; + } + + delimit_data.cdata[delimit_data.cdata_len].cd_offset = -1; + if (BMO_slot_bool_get(op->slots_in, "cmp_vcols") && + bm_edge_delimit_cdata(&bm->ldata, CD_MLOOPCOL, &delimit_data.cdata[delimit_data.cdata_len])) + { + delimit_data.cdata_len += 1; + } + /* flag all edges of all input face */ BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { if (f->len == 3) { @@ -220,10 +323,13 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { BMFace *f_a, *f_b; if (BM_edge_face_pair(e, &f_a, &f_b) && - (BMO_elem_flag_test(bm, f_a, FACE_INPUT) && BMO_elem_flag_test(bm, f_b, FACE_INPUT))) + (BMO_elem_flag_test(bm, f_a, FACE_INPUT) && + BMO_elem_flag_test(bm, f_b, FACE_INPUT))) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); - totedge_tag++; + if (!bm_edge_is_delimit(e, &delimit_data)) { + BMO_elem_flag_enable(bm, e, EDGE_MARK); + totedge_tag++; + } } } @@ -236,36 +342,19 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) i = 0; BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - BMVert *v1, *v2, *v3, *v4; - BMFace *f_a, *f_b; - float measure; + const BMVert *verts[4]; + float error; if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) continue; - f_a = e->l->f; - f_b = e->l->radial_next->f; + bm_edge_to_quad_verts(e, verts); - if (do_sharp && !BM_elem_flag_test(e, BM_ELEM_SMOOTH)) - continue; + error = quad_calc_error(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co); - if (do_mat && f_a->mat_nr != f_b->mat_nr) - continue; - - if ((do_uv || do_tf || do_vcol) && (bm_edge_faces_cmp(bm, e, do_uv, do_tf, do_vcol) == false)) - continue; - - v1 = e->l->v; - v2 = e->l->prev->v; - v3 = e->l->next->v; - v4 = e->l->radial_next->prev->v; - - measure = measure_facepair(v1->co, v2->co, v3->co, v4->co, limit); - if (measure < limit) { - jedges[i].data = e; - jedges[i].sort_value = measure; - i++; - } + jedges[i].data = e; + jedges[i].sort_value = error; + i++; } totedge = i; @@ -279,27 +368,8 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) f_b = e->l->radial_next->f; /* check if another edge already claimed this face */ - if ((BMO_elem_flag_test(bm, f_a, FACE_MARK) == false) || - (BMO_elem_flag_test(bm, f_b, FACE_MARK) == false)) - { - BMO_elem_flag_enable(bm, f_a, FACE_MARK); - BMO_elem_flag_enable(bm, f_b, FACE_MARK); - BMO_elem_flag_enable(bm, e, EDGE_CHOSEN); - } - } - - MEM_freeN(jedges); - - /* join best weighted */ - BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { - BMFace *f_new; - BMFace *f_a, *f_b; - - if (!BMO_elem_flag_test(bm, e, EDGE_CHOSEN)) - continue; - - BM_edge_face_pair(e, &f_a, &f_b); /* checked above */ - if ((f_a->len == 3 && f_b->len == 3)) { + if ((f_a->len == 3) && (f_b->len == 3)) { + BMFace *f_new; f_new = BM_faces_join_pair(bm, f_a, f_b, e, true); if (f_new) { BMO_elem_flag_enable(bm, f_new, FACE_OUT); @@ -307,39 +377,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) } } - /* join 2-tri islands */ - BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { - BMLoop *l_a, *l_b; - BMFace *f_a, *f_b; - - /* ok, this edge wasn't merged, check if it's - * in a 2-tri-pair island, and if so merge */ - l_a = e->l; - l_b = e->l->radial_next; - - f_a = l_a->f; - f_b = l_b->f; - - /* check the other 2 edges in both tris are untagged */ - if ((f_a->len == 3 && f_b->len == 3) && - (BMO_elem_flag_test(bm, l_a->next->e, EDGE_MARK) == false) && - (BMO_elem_flag_test(bm, l_a->prev->e, EDGE_MARK) == false) && - (BMO_elem_flag_test(bm, l_b->next->e, EDGE_MARK) == false) && - (BMO_elem_flag_test(bm, l_b->prev->e, EDGE_MARK) == false) && - /* check for faces that use same verts, this is supported but raises an error - * and cancels the operation when performed from editmode, since this is only - * two triangles we only need to compare a single vertex */ - (LIKELY(l_a->prev->v != l_b->prev->v))) - { - BMFace *f_new; - f_new = BM_faces_join_pair(bm, f_a, f_b, e, true); - if (f_new) { - BMO_elem_flag_enable(bm, f_new, FACE_OUT); - } - } - } - } + MEM_freeN(jedges); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT); } diff --git a/source/blender/bmesh/operators/bmo_offset_edgeloops.c b/source/blender/bmesh/operators/bmo_offset_edgeloops.c new file mode 100644 index 00000000000..a2f3f0bb519 --- /dev/null +++ b/source/blender/bmesh/operators/bmo_offset_edgeloops.c @@ -0,0 +1,290 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/operators/bmo_offset_edgeloops.c + * \ingroup bmesh + * + * Simple edge offset functionality. + * + * \note Actual offset is done by edge-slide. + * (this only changes topology) + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_alloca.h" +#include "BLI_stackdefines.h" + +#include "BKE_customdata.h" + +#include "bmesh.h" + +#include "intern/bmesh_operators_private.h" /* own include */ + +#define USE_CAP_OPTION + +#define ELE_NEW (1 << 0) + +#ifdef USE_CAP_OPTION +#define ELE_VERT_ENDPOINT (1 << 1) +#endif + +/* set for debugging */ +#define OFFSET 0.0f + +static BMFace *bm_face_split_walk_back( + BMesh *bm, BMLoop *l_src, + BMLoop **r_l) +{ + float (*cos)[3]; + BMLoop *l_dst; + BMFace *f; + int num, i; + + for (l_dst = l_src->prev, num = 0; BM_elem_index_get(l_dst->prev->v) != -1; l_dst = l_dst->prev, num++) { + /* pass */ + } + + BLI_assert(num != 0); + + cos = BLI_array_alloca( + cos, num); + + for (l_dst = l_src->prev, i = 0; BM_elem_index_get(l_dst->prev->v) != -1; l_dst = l_dst->prev, i++) { + copy_v3_v3(cos[num - (i + 1)], l_dst->v->co); + } + + f = BM_face_split_n( bm, l_src->f, l_dst->prev, l_src->next, cos, num, r_l, NULL); + + return f; +} + +void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op) +{ + const int edges_num = BMO_slot_buffer_count(op->slots_in, "edges"); + BMVert **verts; + STACK_DECLARE(verts); + int i; + +#ifdef USE_CAP_OPTION + bool use_cap_endpoint = BMO_slot_bool_get(op->slots_in, "use_cap_endpoint"); + int v_edges_max = 0; +#endif + + BMOIter oiter; + + /* only so we can detect new verts (index == -1) */ + BM_mesh_elem_index_ensure(bm, BM_VERT); + + BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false); + + /* over alloc */ + verts = MEM_mallocN(sizeof(*verts) * (edges_num * 2), __func__); + + STACK_INIT(verts, (edges_num * 2)); + + { + BMEdge *e; + BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) { + int j; + + BM_elem_flag_enable(e, BM_ELEM_TAG); + + for (j = 0; j < 2; j++) { + BMVert *v_edge = *(&(e->v1) + j); + if (!BM_elem_flag_test(v_edge, BM_ELEM_TAG)) { + BM_elem_flag_enable(v_edge, BM_ELEM_TAG); + STACK_PUSH(verts, v_edge); + } + } + } + } + + + /* -------------------------------------------------------------------- */ + /* Remove verts only used by tagged edges */ + + for (i = 0; i < STACK_SIZE(verts); i++) { + BMIter iter; + int flag = 0; + BMEdge *e; + + BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) { + flag |= BM_elem_flag_test(e, BM_ELEM_TAG) ? 1 : 2; + if (flag == (1 | 2)) { + break; + } + } + + /* only boundary verts are interesting */ + if (flag != (1 | 2)) { + STACK_REMOVE(verts, i); + } + } + + /* possible but unlikely we have no mixed vertices */ + if (UNLIKELY(STACK_SIZE(verts) == 0)) { + MEM_freeN(verts); + return; + } + + /* main loop */ + for (i = 0; i < STACK_SIZE(verts); i++) { + int v_edges_num = 0; + int v_edges_num_untag = 0; + BMVert *v = verts[i]; + BMIter iter; + BMEdge *e; + + BM_ITER_ELEM (e, &iter, verts[i], BM_EDGES_OF_VERT) { + if (!BM_elem_flag_test(e, BM_ELEM_TAG)) { + BMVert *v_other; + BMIter liter; + BMLoop *l; + + BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { + BM_elem_flag_enable(l->f, BM_ELEM_TAG); + } + + v_other = BM_edge_other_vert(e, v); + BM_edge_split(bm, e, v_other, NULL, 1.0f - OFFSET); + } + else { + v_edges_num_untag += 1; + } + + v_edges_num += 1; + } + +#ifdef USE_CAP_OPTION + if (v_edges_num_untag == 1) { + BMO_elem_flag_enable(bm, v, ELE_VERT_ENDPOINT); + } + + CLAMP_MIN(v_edges_max, v_edges_num); +#endif + + } + + + for (i = 0; i < STACK_SIZE(verts); i++) { + BMVert *v = verts[i]; + BMIter liter; + BMLoop *l; + + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + if (BM_elem_flag_test(l->f, BM_ELEM_TAG) && + (l->f->len != 3)) + { + BMFace *f_cmp = l->f; + if ((BM_elem_index_get(l->next->v) == -1) && + (BM_elem_index_get(l->prev->v) == -1)) + { +#ifdef USE_CAP_OPTION + if (use_cap_endpoint || (BMO_elem_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0)) +#endif + { + BMLoop *l_new; + BM_face_split(bm, l->f, l->prev, l->next, &l_new, NULL, true); + BLI_assert(f_cmp == l->f); + BLI_assert(f_cmp != l_new->f); + UNUSED_VARS_NDEBUG(f_cmp); + BMO_elem_flag_enable(bm, l_new->e, ELE_NEW); + } + } + else if (l->f->len > 4) { + if (BM_elem_flag_test(l->e, BM_ELEM_TAG) != + BM_elem_flag_test(l->prev->e, BM_ELEM_TAG)) + { + if (BM_elem_index_get(l->next->v) == -1) { + if (BM_elem_index_get(l->prev->prev->v) == -1) { + BMLoop *l_new; + BM_face_split(bm, l->f, l->prev->prev, l->next, &l_new, NULL, true); + BLI_assert(f_cmp == l->f); + BLI_assert(f_cmp != l_new->f); + BMO_elem_flag_enable(bm, l_new->e, ELE_NEW); + BM_elem_flag_disable(l->f, BM_ELEM_TAG); + } + else { + /* walk backwards */ + BMLoop *l_new; + bm_face_split_walk_back(bm, l, &l_new); + do { + BMO_elem_flag_enable(bm, l_new->e, ELE_NEW); + l_new = l_new->next; + } while (BM_vert_is_edge_pair(l_new->v)); + BM_elem_flag_disable(l->f, BM_ELEM_TAG); + } + } + + /* Note: instead of duplicate code in alternate direction, + * we can be sure to hit the other vertex, so the code above runs. */ +#if 0 + else if (BM_elem_index_get(l->prev->v) == -1) { + if (BM_elem_index_get(l->next->next->v) == -1) { + } + } +#endif + } + } + } + } + } + +#ifdef USE_CAP_OPTION + if (use_cap_endpoint == false) { + BMVert **varr = BLI_array_alloca(varr, v_edges_max); + STACK_DECLARE(varr); + BMVert *v; + + for (i = 0; i < STACK_SIZE(verts); i++) { + BMIter iter; + BMEdge *e; + + v = verts[i]; + + STACK_INIT(varr, v_edges_max); + + BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { + BMVert *v_other; + v_other = BM_edge_other_vert(e, v); + if (BM_elem_index_get(v_other) == -1) { + if (BM_vert_is_edge_pair(v_other)) { + /* defer bmesh_jekv to avoid looping over data we're removing */ + v_other->e = e; + STACK_PUSH(varr, v_other); + } + } + } + + while ((v = STACK_POP(varr))) { + bmesh_jekv(bm, v->e, v, true, false); + } + } + } +#endif + + MEM_freeN(verts); + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_NEW); +} diff --git a/source/blender/bmesh/operators/bmo_planar_faces.c b/source/blender/bmesh/operators/bmo_planar_faces.c new file mode 100644 index 00000000000..4e3ac58a813 --- /dev/null +++ b/source/blender/bmesh/operators/bmo_planar_faces.c @@ -0,0 +1,158 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/operators/bmo_planar_faces.c + * \ingroup bmesh + * + * Iternatively flatten 4+ sided faces. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_ghash.h" + +#include "bmesh.h" + +#include "intern/bmesh_operators_private.h" /* own include */ + +#define ELE_VERT_ADJUST (1 << 0) +#define ELE_FACE_ADJUST (1 << 1) + +struct VertAccum { + float co[3]; + int co_tot; +}; + +void bmo_planar_faces_exec(BMesh *bm, BMOperator *op) +{ + const float fac = BMO_slot_float_get(op->slots_in, "factor"); + const int iterations = BMO_slot_int_get(op->slots_in, "iterations"); + const int faces_num = BMO_slot_buffer_count(op->slots_in, "faces"); + + const float eps = 0.00001f; + const float eps_sq = SQUARE(eps); + + BMOIter oiter; + BMFace *f; + BLI_mempool *vert_accum_pool; + GHash *vaccum_map; + float (*faces_center)[3]; + int i, iter_step, shared_vert_num; + + faces_center = MEM_mallocN(sizeof(*faces_center) * faces_num, __func__); + + shared_vert_num = 0; + BMO_ITER_INDEX (f, &oiter, op->slots_in, "faces", BM_FACE, i) { + BMLoop *l_iter, *l_first; + + if (f->len == 3) { + continue; + } + + BM_face_calc_center_mean_weighted(f, faces_center[i]); + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (!BMO_elem_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) { + BMO_elem_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST); + shared_vert_num += 1; + } + } while ((l_iter = l_iter->next) != l_first); + + BMO_elem_flag_enable(bm, f, ELE_FACE_ADJUST); + } + + vert_accum_pool = BLI_mempool_create(sizeof(struct VertAccum), 0, 512, BLI_MEMPOOL_NOP); + vaccum_map = BLI_ghash_ptr_new_ex(__func__, shared_vert_num); + + for (iter_step = 0; iter_step < iterations; iter_step++) { + GHashIterator gh_iter; + bool changed = false; + + BMO_ITER_INDEX (f, &oiter, op->slots_in, "faces", BM_FACE, i) { + BMLoop *l_iter, *l_first; + float plane[4]; + + if (!BMO_elem_flag_test(bm, f, ELE_FACE_ADJUST)) { + continue; + } + BMO_elem_flag_disable(bm, f, ELE_FACE_ADJUST); + + BLI_assert(f->len != 3); + + /* keep original face data (else we 'move' the face) */ +#if 0 + BM_face_normal_update(f); + BM_face_calc_center_mean_weighted(f, f_center); +#endif + + plane_from_point_normal_v3(plane, faces_center[i], f->no); + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + struct VertAccum *va; + void **va_p; + float co[3]; + + if (!BLI_ghash_ensure_p(vaccum_map, l_iter->v, &va_p)) { + *va_p = BLI_mempool_calloc(vert_accum_pool); + } + va = *va_p; + + closest_to_plane_v3(co, plane, l_iter->v->co); + va->co_tot += 1; + + interp_v3_v3v3(va->co, va->co, co, 1.0f / (float)va->co_tot); + } while ((l_iter = l_iter->next) != l_first); + } + + GHASH_ITER (gh_iter, vaccum_map) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + struct VertAccum *va = BLI_ghashIterator_getValue(&gh_iter); + BMIter iter; + + if (len_squared_v3v3(v->co, va->co) > eps_sq) { + BMO_elem_flag_enable(bm, v, ELE_VERT_ADJUST); + interp_v3_v3v3(v->co, v->co, va->co, fac); + changed = true; + } + + /* tag for re-calculation */ + BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { + if (f->len != 3) { + BMO_elem_flag_enable(bm, f, ELE_FACE_ADJUST); + } + } + } + + /* if nothing changed, break out early */ + if (changed == false) { + break; + } + + BLI_ghash_clear(vaccum_map, NULL, NULL); + BLI_mempool_clear(vert_accum_pool); + } + + MEM_freeN(faces_center); + BLI_ghash_free(vaccum_map, NULL, NULL); + BLI_mempool_destroy(vert_accum_pool); +} diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index 871bee64c19..42373ad0ef0 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -29,9 +29,9 @@ #include "MEM_guardedalloc.h" #include "BLI_math.h" -#include "BLI_array.h" #include "BLI_alloca.h" #include "BLI_stackdefines.h" +#include "BLI_stack.h" #include "BKE_customdata.h" @@ -198,7 +198,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) BMO_elem_flag_enable(bm, e, EDGE_COL); } else if (!BM_edge_exists(v1, v2)) { - BM_edge_create(bm, v1, v2, e, BM_CREATE_NO_DOUBLE); + BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP); } BMO_elem_flag_enable(bm, e, ELE_DEL); @@ -261,7 +261,7 @@ void bmo_pointmerge_facedata_exec(BMesh *bm, BMOperator *op) BMOIter siter; BMIter iter; BMVert *v, *vert_snap; - BMLoop *l, *firstl = NULL; + BMLoop *l, *l_first = NULL; float fac; int i, tot; @@ -273,33 +273,35 @@ void bmo_pointmerge_facedata_exec(BMesh *bm, BMOperator *op) fac = 1.0f / tot; BM_ITER_ELEM (l, &iter, vert_snap, BM_LOOPS_OF_VERT) { - if (!firstl) { - firstl = l; + if (l_first == NULL) { + l_first = l; } for (i = 0; i < bm->ldata.totlayer; i++) { if (CustomData_layer_has_math(&bm->ldata, i)) { - int type = bm->ldata.layers[i].type; + const int type = bm->ldata.layers[i].type; + const int offset = bm->ldata.layers[i].offset; void *e1, *e2; - e1 = CustomData_bmesh_get_layer_n(&bm->ldata, firstl->head.data, i); - e2 = CustomData_bmesh_get_layer_n(&bm->ldata, l->head.data, i); + e1 = BM_ELEM_CD_GET_VOID_P(l_first, offset); + e2 = BM_ELEM_CD_GET_VOID_P(l, offset); CustomData_data_multiply(type, e2, fac); - if (l != firstl) + if (l != l_first) { CustomData_data_add(type, e1, e2); + } } } } BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { - if (l == firstl) { + if (l == l_first) { continue; } - CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, firstl->head.data, &l->head.data); + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_first->head.data, &l->head.data); } } } @@ -311,19 +313,20 @@ void bmo_average_vert_facedata_exec(BMesh *bm, BMOperator *op) BMVert *v; BMLoop *l /* , *firstl = NULL */; CDBlockBytes min, max; - void *block; - int i, type; + int i; for (i = 0; i < bm->ldata.totlayer; i++) { + const int type = bm->ldata.layers[i].type; + const int offset = bm->ldata.layers[i].offset; + if (!CustomData_layer_has_math(&bm->ldata, i)) continue; - type = bm->ldata.layers[i].type; CustomData_data_initminmax(type, &min, &max); BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { - block = CustomData_bmesh_get_layer_n(&bm->ldata, l->head.data, i); + void *block = BM_ELEM_CD_GET_VOID_P(l, offset); CustomData_data_dominmax(type, block, &min, &max); } } @@ -334,7 +337,7 @@ void bmo_average_vert_facedata_exec(BMesh *bm, BMOperator *op) BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) { - block = CustomData_bmesh_get_layer_n(&bm->ldata, l->head.data, i); + void *block = BM_ELEM_CD_GET_VOID_P(l, offset); CustomData_data_copy_value(type, &min, block); } } @@ -375,13 +378,14 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op) BMOperator weldop; BMWalker walker; BMIter iter; - BMEdge *e, **edges = NULL; - BLI_array_declare(edges); - float min[3], max[3], center[3]; - unsigned int i, tot; + BMEdge *e; + BLI_Stack *edge_stack; BMOpSlot *slot_targetmap; - - BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges"); + + if (BMO_slot_bool_get(op->slots_in, "uvs")) { + BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges"); + } + BMO_op_init(bm, &weldop, op->flag, "weld_verts"); slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap"); @@ -392,18 +396,20 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op) BMW_FLAG_NOP, /* no need to use BMW_FLAG_TEST_HIDDEN, already marked data */ BMW_NIL_LAY); + edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__); + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + float min[3], max[3], center[3]; BMVert *v_tar; if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) continue; - BLI_array_empty(edges); + BLI_assert(BLI_stack_is_empty(edge_stack)); INIT_MINMAX(min, max); - for (e = BMW_begin(&walker, e->v1), tot = 0; e; e = BMW_step(&walker), tot++) { - BLI_array_grow_one(edges); - edges[tot] = e; + for (e = BMW_begin(&walker, e->v1); e; e = BMW_step(&walker)) { + BLI_stack_push(edge_stack, &e); minmax_v3v3_v3(min, max, e->v1->co); minmax_v3v3_v3(min, max, e->v2->co); @@ -413,79 +419,90 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op) BM_elem_flag_disable(e->v2, BM_ELEM_TAG); } - mid_v3_v3v3(center, min, max); + if (!BLI_stack_is_empty(edge_stack)) { + + mid_v3_v3v3(center, min, max); - /* snap edges to a point. for initial testing purposes anyway */ - v_tar = edges[0]->v1; + /* snap edges to a point. for initial testing purposes anyway */ + e = *(BMEdge **)BLI_stack_peek(edge_stack); + v_tar = e->v1; - for (i = 0; i < tot; i++) { - unsigned int j; + while (!BLI_stack_is_empty(edge_stack)) { + unsigned int j; + BLI_stack_pop(edge_stack, &e); - for (j = 0; j < 2; j++) { - BMVert *v_src = *((&edges[i]->v1) + j); + for (j = 0; j < 2; j++) { + BMVert *v_src = *((&e->v1) + j); - copy_v3_v3(v_src->co, center); - if ((v_src != v_tar) && !BM_elem_flag_test(v_src, BM_ELEM_TAG)) { - BM_elem_flag_enable(v_src, BM_ELEM_TAG); - BMO_slot_map_elem_insert(&weldop, slot_targetmap, v_src, v_tar); + copy_v3_v3(v_src->co, center); + if ((v_src != v_tar) && !BM_elem_flag_test(v_src, BM_ELEM_TAG)) { + BM_elem_flag_enable(v_src, BM_ELEM_TAG); + BMO_slot_map_elem_insert(&weldop, slot_targetmap, v_src, v_tar); + } } } } } - + + BLI_stack_free(edge_stack); + BMO_op_exec(bm, &weldop); BMO_op_finish(bm, &weldop); BMW_end(&walker); - BLI_array_free(edges); } /* uv collapse function */ static void bmo_collapsecon_do_layer(BMesh *bm, const int layer, const short oflag) { + const int type = bm->ldata.layers[layer].type; + const int offset = bm->ldata.layers[layer].offset; BMIter iter, liter; BMFace *f; BMLoop *l, *l2; BMWalker walker; - void **blocks = NULL; - BLI_array_declare(blocks); + BLI_Stack *block_stack; CDBlockBytes min, max; - int i, tot, type = bm->ldata.layers[layer].type; BMW_init(&walker, bm, BMW_LOOPDATA_ISLAND, BMW_MASK_NOP, oflag, BMW_MASK_NOP, BMW_FLAG_NOP, /* no need to use BMW_FLAG_TEST_HIDDEN, already marked data */ layer); + block_stack = BLI_stack_new(sizeof(void *), __func__); + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { if (BMO_elem_flag_test(bm, l->e, oflag)) { /* walk */ - BLI_array_empty(blocks); + BLI_assert(BLI_stack_is_empty(block_stack)); CustomData_data_initminmax(type, &min, &max); - for (l2 = BMW_begin(&walker, l), tot = 0; l2; l2 = BMW_step(&walker), tot++) { - BLI_array_grow_one(blocks); - blocks[tot] = CustomData_bmesh_get_layer_n(&bm->ldata, l2->head.data, layer); - CustomData_data_dominmax(type, blocks[tot], &min, &max); + for (l2 = BMW_begin(&walker, l); l2; l2 = BMW_step(&walker)) { + void *block = BM_ELEM_CD_GET_VOID_P(l2, offset); + CustomData_data_dominmax(type, block, &min, &max); + BLI_stack_push(block_stack, &block); } - if (tot) { + if (!BLI_stack_is_empty(block_stack)) { CustomData_data_multiply(type, &min, 0.5f); CustomData_data_multiply(type, &max, 0.5f); CustomData_data_add(type, &min, &max); /* snap CD (uv, vcol) points to their centroid */ - for (i = 0; i < tot; i++) { - CustomData_data_copy_value(type, &min, blocks[i]); + while (!BLI_stack_is_empty(block_stack)) { + void *block; + BLI_stack_pop(block_stack, &block); + CustomData_data_copy_value(type, &min, block); } } } } } + BLI_stack_free(block_stack); + BMW_end(&walker); - BLI_array_free(blocks); } void bmo_collapse_uvs_exec(BMesh *bm, BMOperator *op) @@ -519,8 +536,9 @@ void bmo_collapse_uvs_exec(BMesh *bm, BMOperator *op) } -static void bmesh_find_doubles_common(BMesh *bm, BMOperator *op, - BMOperator *optarget, BMOpSlot *optarget_slot) +static void bmesh_find_doubles_common( + BMesh *bm, BMOperator *op, + BMOperator *optarget, BMOpSlot *optarget_slot) { BMVert **verts; int verts_len; diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c index 003c27671a5..e3304298647 100644 --- a/source/blender/bmesh/operators/bmo_subdivide.c +++ b/source/blender/bmesh/operators/bmo_subdivide.c @@ -80,8 +80,9 @@ static void bmo_subd_init_shape_info(BMesh *bm, SubDParams *params) } -typedef void (*subd_pattern_fill_fp)(BMesh *bm, BMFace *face, BMVert **verts, - const SubDParams *params); +typedef void (*subd_pattern_fill_fp)( + BMesh *bm, BMFace *face, BMVert **verts, + const SubDParams *params); /* * note: this is a pattern-based edge subdivider. @@ -163,10 +164,11 @@ static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace return NULL; } /* calculates offset for co, based on fractal, sphere or smooth settings */ -static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params, float perc, - BMVert *vsta, BMVert *vend) +static void alter_co( + BMVert *v, BMEdge *UNUSED(e_orig), + const SubDParams *params, const float perc, + const BMVert *v_a, const BMVert *v_b) { - float tvec[3], fac; float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp); int i; @@ -178,28 +180,26 @@ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params } else if (params->use_smooth) { /* we calculate an offset vector vec1[], to be added to *co */ - float len, nor[3], nor1[3], nor2[3], val; + float dir[3], tvec[3]; + float fac, len, val; - sub_v3_v3v3(nor, vsta->co, vend->co); - len = 0.5f * normalize_v3(nor); - - copy_v3_v3(nor1, vsta->no); - copy_v3_v3(nor2, vend->no); + sub_v3_v3v3(dir, v_a->co, v_b->co); + len = M_SQRT1_2 * normalize_v3(dir); /* cosine angle */ - fac = dot_v3v3(nor, nor1); - mul_v3_v3fl(tvec, nor1, fac); + fac = dot_v3v3(dir, v_a->no); + mul_v3_v3fl(tvec, v_a->no, fac); /* cosine angle */ - fac = -dot_v3v3(nor, nor2); - madd_v3_v3fl(tvec, nor2, fac); + fac = -dot_v3v3(dir, v_b->no); + madd_v3_v3fl(tvec, v_b->no, fac); /* falloff for multi subdivide */ val = fabsf(1.0f - 2.0f * fabsf(0.5f - perc)); val = bmesh_subd_falloff_calc(params->smooth_falloff, val); if (params->use_smooth_even) { - val *= BM_vert_calc_shell_factor(v); + val *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no); } mul_v3_fl(tvec, params->smooth * val * len); @@ -208,12 +208,13 @@ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params } if (params->use_fractal) { - const float len = len_v3v3(vsta->co, vend->co); - float normal[3], co2[3], base1[3], base2[3]; + float normal[3], co2[3], base1[3], base2[3], tvec[3]; + const float len = len_v3v3(v_a->co, v_b->co); + float fac; fac = params->fractal * len; - mid_v3_v3v3(normal, vsta->no, vend->no); + mid_v3_v3v3(normal, v_a->no, v_b->no); ortho_basis_v3v3_v3(base1, base2, normal); add_v3_v3v3(co2, v->co, params->fractal_ofs); @@ -234,9 +235,12 @@ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params * this by getting the normals and coords for each shape key and * re-calculate the smooth value for each but this is quite involved. * for now its ok to simply apply the difference IMHO - campbell */ - sub_v3_v3v3(tvec, v->co, co); if (params->shape_info.totlayer > 1) { + float tvec[3]; + + sub_v3_v3v3(tvec, v->co, co); + /* skip the last layer since its the temp */ i = params->shape_info.totlayer - 1; co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset); @@ -250,19 +254,21 @@ static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params /* assumes in the edge is the correct interpolated vertices already */ /* percent defines the interpolation, rad and flag are for special options */ /* results in new vertex with correct coordinate, vertex normal and weight group info */ -static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge, BMEdge *oedge, - const SubDParams *params, float percent, - float percent2, - BMEdge **out, BMVert *vsta, BMVert *vend) +static BMVert *bm_subdivide_edge_addvert( + BMesh *bm, BMEdge *edge, BMEdge *e_orig, + const SubDParams *params, + const float factor_edge_split, const float factor_subd, + BMVert *v_a, BMVert *v_b, + BMEdge **r_edge) { - BMVert *ev; + BMVert *v_new; - ev = BM_edge_split(bm, edge, edge->v1, out, percent); + v_new = BM_edge_split(bm, edge, edge->v1, r_edge, factor_edge_split); - BMO_elem_flag_enable(bm, ev, ELE_INNER); + BMO_elem_flag_enable(bm, v_new, ELE_INNER); /* offset for smooth or sphere or fractal */ - alter_co(ev, oedge, params, percent2, vsta, vend); + alter_co(v_new, e_orig, params, factor_subd, v_a, v_b); #if 0 //BMESH_TODO /* clip if needed by mirror modifier */ @@ -279,35 +285,40 @@ static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge, BMEdge *oedge, } #endif - interp_v3_v3v3(ev->no, vsta->no, vend->no, percent2); - normalize_v3(ev->no); + interp_v3_v3v3(v_new->no, v_a->no, v_b->no, factor_subd); + normalize_v3(v_new->no); - return ev; + return v_new; } -static BMVert *subdivideedgenum(BMesh *bm, BMEdge *edge, BMEdge *oedge, - int curpoint, int totpoint, const SubDParams *params, - BMEdge **newe, BMVert *vsta, BMVert *vend) +static BMVert *subdivide_edge_num( + BMesh *bm, BMEdge *edge, BMEdge *e_orig, + int curpoint, int totpoint, const SubDParams *params, + BMVert *v_a, BMVert *v_b, + BMEdge **r_edge) { - BMVert *ev; - float percent, percent2 = 0.0f; + BMVert *v_new; + float factor_edge_split, factor_subd; if (BMO_elem_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) { - percent = BMO_slot_map_float_get(params->slot_edge_percents, edge); + factor_edge_split = BMO_slot_map_float_get(params->slot_edge_percents, edge); + factor_subd = 0.0f; } else { - percent = 1.0f / (float)(totpoint + 1 - curpoint); - percent2 = (float)(curpoint + 1) / (float)(totpoint + 1); - + factor_edge_split = 1.0f / (float)(totpoint + 1 - curpoint); + factor_subd = (float)(curpoint + 1) / (float)(totpoint + 1); } - ev = bm_subdivide_edge_addvert(bm, edge, oedge, params, percent, - percent2, newe, vsta, vend); - return ev; + v_new = bm_subdivide_edge_addvert( + bm, edge, e_orig, params, + factor_edge_split, factor_subd, + v_a, v_b, r_edge); + return v_new; } -static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, const SubDParams *params, - BMVert *vsta, BMVert *vend) +static void bm_subdivide_multicut( + BMesh *bm, BMEdge *edge, const SubDParams *params, + BMVert *v_a, BMVert *v_b) { BMEdge *eed = edge, *e_new, e_tmp = *edge; BMVert *v, v1_tmp = *edge->v1, v2_tmp = *edge->v2, *v1 = edge->v1, *v2 = edge->v2; @@ -317,7 +328,7 @@ static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, const SubDParams *par e_tmp.v2 = &v2_tmp; for (i = 0; i < numcuts; i++) { - v = subdivideedgenum(bm, eed, &e_tmp, i, params->numcuts, params, &e_new, vsta, vend); + v = subdivide_edge_num(bm, eed, &e_tmp, i, params->numcuts, params, v_a, v_b, &e_new); BMO_elem_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT); BMO_elem_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT); @@ -434,7 +445,7 @@ static void quad_2edge_split_innervert(BMesh *bm, BMFace *UNUSED(face), BMVert * e = connect_smallest_face(bm, verts[i], verts[numcuts + (numcuts - i)], &f_new); e_tmp = *e; - v = bm_subdivide_edge_addvert(bm, e, &e_tmp, params, 0.5f, 0.5f, &e_new, e->v1, e->v2); + v = bm_subdivide_edge_addvert(bm, e, &e_tmp, params, 0.5f, 0.5f, e->v1, e->v2, &e_new); if (i != numcuts - 1) { connect_smallest_face(bm, v_last, v, &f_new); @@ -577,8 +588,7 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts e_tmp = *e; for (a = 0; a < numcuts; a++) { - v = subdivideedgenum(bm, e, &e_tmp, a, numcuts, params, &e_new, - v1, v2); + v = subdivide_edge_num(bm, e, &e_tmp, a, numcuts, params, v1, v2, &e_new); BMESH_ASSERT(v != NULL); @@ -685,8 +695,7 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, e_tmp.v1 = &v1_tmp; e_tmp.v2 = &v2_tmp; for (j = 0; j < i; j++) { - v = subdivideedgenum(bm, e, &e_tmp, j, i, params, &e_new, - verts[a], verts[b]); + v = subdivide_edge_num(bm, e, &e_tmp, j, i, params, verts[a], verts[b], &e_new); lines[i + 1][j + 1] = v; BMO_elem_flag_enable(bm, e_new, ELE_INNER); @@ -1168,14 +1177,15 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) } /* editmesh-emulating function */ -void BM_mesh_esubdivide(BMesh *bm, const char edge_hflag, - const float smooth, const short smooth_falloff, const bool use_smooth_even, - const float fractal, const float along_normal, - const int numcuts, - const int seltype, const int cornertype, - const short use_single_edge, const short use_grid_fill, - const short use_only_quads, - const int seed) +void BM_mesh_esubdivide( + BMesh *bm, const char edge_hflag, + const float smooth, const short smooth_falloff, const bool use_smooth_even, + const float fractal, const float along_normal, + const int numcuts, + const int seltype, const int cornertype, + const short use_single_edge, const short use_grid_fill, + const short use_only_quads, + const int seed) { BMOperator op; diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index c01ad10d716..0e619b4cece 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -80,8 +80,9 @@ static unsigned int bm_verts_tag_count(BMesh *bm) } #endif -static float bezier_handle_calc_length_v3(const float co_a[3], const float no_a[3], - const float co_b[3], const float no_b[3]) +static float bezier_handle_calc_length_v3( + const float co_a[3], const float no_a[3], + const float co_b[3], const float no_b[3]) { const float dot = dot_v3v3(no_a, no_b); /* gives closest approx at a circle with 2 parallel handles */ @@ -538,12 +539,13 @@ static void bm_edgering_pair_store_free( /* -------------------------------------------------------------------- */ /* Interpolation Function */ -static void bm_edgering_pair_interpolate(BMesh *bm, LoopPairStore *lpair, - struct BMEdgeLoopStore *el_store_a, - struct BMEdgeLoopStore *el_store_b, - ListBase *eloops_ring, - const int interp_mode, const int cuts, const float smooth, - const float *falloff_cache) +static void bm_edgering_pair_interpolate( + BMesh *bm, LoopPairStore *lpair, + struct BMEdgeLoopStore *el_store_a, + struct BMEdgeLoopStore *el_store_b, + ListBase *eloops_ring, + const int interp_mode, const int cuts, const float smooth, + const float *falloff_cache) { const int resolu = cuts + 2; const int dims = 3; @@ -878,9 +880,10 @@ static bool bm_edgering_pair_order_is_flipped(BMesh *UNUSED(bm), * Takes 2 edge loops that share edges, * sort their verts and rotates the list so the lined up. */ -static void bm_edgering_pair_order(BMesh *bm, - struct BMEdgeLoopStore *el_store_a, - struct BMEdgeLoopStore *el_store_b) +static void bm_edgering_pair_order( + BMesh *bm, + struct BMEdgeLoopStore *el_store_a, + struct BMEdgeLoopStore *el_store_b) { ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); @@ -951,11 +954,12 @@ static void bm_edgering_pair_order(BMesh *bm, * * \note loops are _not_ aligned. */ -static void bm_edgering_pair_subdiv(BMesh *bm, - struct BMEdgeLoopStore *el_store_a, - struct BMEdgeLoopStore *el_store_b, - ListBase *eloops_ring, - const int cuts) +static void bm_edgering_pair_subdiv( + BMesh *bm, + struct BMEdgeLoopStore *el_store_a, + struct BMEdgeLoopStore *el_store_b, + ListBase *eloops_ring, + const int cuts) { ListBase *lb_a = BM_edgeloop_verts_get(el_store_a); // ListBase *lb_b = BM_edgeloop_verts_get(el_store_b); @@ -1043,11 +1047,12 @@ static void bm_edgering_pair_subdiv(BMesh *bm, bm_edgeloop_vert_tag(el_store_b, false); } -static void bm_edgering_pair_ringsubd(BMesh *bm, LoopPairStore *lpair, - struct BMEdgeLoopStore *el_store_a, - struct BMEdgeLoopStore *el_store_b, - const int interp_mode, const int cuts, const float smooth, - const float *falloff_cache) +static void bm_edgering_pair_ringsubd( + BMesh *bm, LoopPairStore *lpair, + struct BMEdgeLoopStore *el_store_a, + struct BMEdgeLoopStore *el_store_b, + const int interp_mode, const int cuts, const float smooth, + const float *falloff_cache) { ListBase eloops_ring = {NULL}; bm_edgering_pair_order(bm, el_store_a, el_store_b); diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index da1991a187d..964d0b1dfc6 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -208,7 +208,7 @@ static void bmo_region_extend_expand( BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) { + if (!BMO_elem_flag_test(bm, e, SEL_ORIG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { found = true; break; } @@ -221,7 +221,7 @@ static void bmo_region_extend_expand( BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, SEL_FLAG)) { + if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { BMO_elem_flag_enable(bm, e, SEL_FLAG); BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); } @@ -232,7 +232,7 @@ static void bmo_region_extend_expand( BMFace *f; BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, SEL_FLAG)) { + if (!BMO_elem_flag_test(bm, f, SEL_FLAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { bmo_face_flag_set_flush(bm, f, SEL_FLAG, true); } } @@ -243,7 +243,7 @@ static void bmo_region_extend_expand( BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { if (BM_edge_is_wire(e)) { - if (!BMO_elem_flag_test(bm, e, SEL_FLAG)) { + if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { BMO_elem_flag_enable(bm, e, SEL_FLAG); BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); } @@ -267,7 +267,9 @@ static void bmo_region_extend_expand( BMFace *f_other; BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG)) { + if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && + !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN)) + { BMO_elem_flag_enable(bm, f_other, SEL_FLAG); } } @@ -277,7 +279,9 @@ static void bmo_region_extend_expand( BMFace *f_other; BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG)) { + if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && + !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN)) + { BMO_elem_flag_enable(bm, f_other, SEL_FLAG); } } |