diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2017-07-16 13:48:39 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2017-07-16 13:48:39 +0300 |
commit | 65d2374c806ecf42ccf106cd28380e7a7071f789 (patch) | |
tree | d5344de03da74108de00a94b9c227296f25dd2cb /source/blender/bmesh/intern | |
parent | d3349e5e3fb4e5ddc7b7524aa806f726ae4728f6 (diff) | |
parent | a3d9ef2ea50671267792df4a2c220ae157ea7a4c (diff) |
Merge branch 'blender2.8' into strand_editmode2.8
Diffstat (limited to 'source/blender/bmesh/intern')
31 files changed, 856 insertions, 786 deletions
diff --git a/source/blender/bmesh/intern/bmesh_callback_generic.c b/source/blender/bmesh/intern/bmesh_callback_generic.c index 913255bfb33..e9304e8536f 100644 --- a/source/blender/bmesh/intern/bmesh_callback_generic.c +++ b/source/blender/bmesh/intern/bmesh_callback_generic.c @@ -32,7 +32,7 @@ bool BM_elem_cb_check_hflag_ex(BMElem *ele, void *user_data) { - const unsigned int hflag_pair = GET_INT_FROM_POINTER(user_data); + const uint hflag_pair = GET_INT_FROM_POINTER(user_data); const char hflag_p = (hflag_pair & 0xff); const char hflag_n = (hflag_pair >> 8); diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 4d92baab6eb..f8ecbe1756b 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -154,7 +154,7 @@ void BM_face_copy_shared( if (l_other && l_other != l_iter) { BMLoop *l_src[2]; BMLoop *l_dst[2] = {l_iter, l_iter->next}; - unsigned int j; + uint j; if (l_other->v == l_iter->v) { l_src[0] = l_other; @@ -311,7 +311,7 @@ BMFace *BM_face_create_ngon_verts( const bool calc_winding, const bool create_edges) { BMEdge **edge_arr = BLI_array_alloca(edge_arr, len); - unsigned int winding[2] = {0, 0}; + uint winding[2] = {0, 0}; int i, i_prev = len - 1; BMVert *v_winding[2] = {vert_arr[i_prev], vert_arr[0]}; @@ -387,15 +387,11 @@ BMFace *BM_face_create_ngon_verts( * * \note Since this is a vcloud there is no direction. */ -BMFace *BM_face_create_ngon_vcloud( - BMesh *bm, BMVert **vert_arr, int len, - const BMFace *f_example, const eBMCreateFlag create_flag) +void BM_verts_sort_radial_plane(BMVert **vert_arr, int len) { struct SortIntByFloat *vang = BLI_array_alloca(vang, len); BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len); - BMFace *f; - float totv_inv = 1.0f / (float)len; int i = 0; @@ -470,26 +466,9 @@ BMFace *BM_face_create_ngon_vcloud( /* now calculate every points angle around the normal (signed) */ for (i = 0; i < len; i++) { - float co[3]; - float proj_vec[3]; - float angle; - - /* center relative vec */ - sub_v3_v3v3(co, vert_arr[i]->co, cent); - - /* align to plane */ - project_v3_v3v3(proj_vec, co, nor); - sub_v3_v3(co, proj_vec); - - /* now 'co' is valid - we can compare its angle against the far vec */ - angle = angle_v3v3(far_vec, co); - - if (dot_v3v3(co, sign_vec) < 0.0f) { - angle = -angle; - } - - vang[i].sort_value = angle; + vang[i].sort_value = angle_signed_on_axis_v3v3v3_v3(far, cent, vert_arr[i]->co, nor); vang[i].data = i; + vert_arr_map[i] = vert_arr[i]; } /* sort by angle and magic! - we have our ngon */ @@ -497,14 +476,9 @@ BMFace *BM_face_create_ngon_vcloud( /* --- */ - /* create edges and find the winding (if faces are attached to any existing edges) */ for (i = 0; i < len; i++) { - vert_arr_map[i] = vert_arr[vang[i].data]; + vert_arr[i] = vert_arr_map[vang[i].data]; } - - f = BM_face_create_ngon_verts(bm, vert_arr_map, len, f_example, create_flag, true, true); - - return f; } /*************************************************************/ @@ -626,7 +600,7 @@ void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void BM_elem_attrs_copy_ex(bm_src, bm_dst, ele_src, ele_dst, BM_ELEM_SELECT); } -void BM_elem_select_copy(BMesh *bm_dst, BMesh *UNUSED(bm_src), void *ele_dst_v, const void *ele_src_v) +void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v) { BMHeader *ele_dst = ele_dst_v; const BMHeader *ele_src = ele_src_v; diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h index 06bc5465a19..a52a17cd2f3 100644 --- a/source/blender/bmesh/intern/bmesh_construct.h +++ b/source/blender/bmesh/intern/bmesh_construct.h @@ -34,6 +34,9 @@ bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len); bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len); void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len); +/* sort before creation */ +void BM_verts_sort_radial_plane(BMVert **vert_arr, int len); + BMFace *BM_face_create_quad_tri( BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, const BMFace *f_example, const eBMCreateFlag create_flag); @@ -50,15 +53,11 @@ BMFace *BM_face_create_ngon_verts( const BMFace *f_example, const eBMCreateFlag create_flag, const bool calc_winding, const bool create_edges); -BMFace *BM_face_create_ngon_vcloud( - BMesh *bm, BMVert **vert_arr, int len, - const BMFace *f_example, const eBMCreateFlag create_flag); - void BM_elem_attrs_copy_ex( BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v, const char hflag_mask); void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v); -void BM_elem_select_copy(BMesh *bm_dst, BMesh *bm_src, void *ele_dst_v, const void *ele_src_v); +void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v); void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const struct BMAllocTemplate *allocsize); BMesh *BM_mesh_copy(BMesh *bm_old); diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index e83b752947c..4fe14fdf5c9 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -287,7 +287,7 @@ static BMLoop *bm_face_boundary_add( #endif BMLoop *l = bm_loop_create(bm, startv, starte, f, NULL /* starte->l */, create_flag); - bmesh_radial_append(starte, l); + bmesh_radial_loop_append(starte, l); #ifdef USE_BMESH_HOLES lst->first = lst->last = l; @@ -295,8 +295,6 @@ static BMLoop *bm_face_boundary_add( #else f->l_first = l; #endif - - l->f = f; return l; } @@ -446,26 +444,20 @@ BMFace *BM_face_create( if (create_flag & BM_CREATE_NO_DOUBLE) { /* Check if face already exists */ - const bool is_overlap = BM_face_exists(verts, len, &f); - if (is_overlap) { + f = BM_face_exists(verts, len); + if (f != NULL) { return f; } - else { - BLI_assert(f == NULL); - } } f = bm_face_create__internal(bm); startl = lastl = bm_face_boundary_add(bm, f, verts[0], edges[0], create_flag); - - startl->v = verts[0]; - startl->e = edges[0]; + for (i = 1; i < len; i++) { l = bm_loop_create(bm, verts[i], edges[i], f, NULL /* edges[i]->l */, create_flag); - - l->f = f; - bmesh_radial_append(edges[i], l); + + bmesh_radial_loop_append(edges[i], l); l->prev = lastl; lastl->next = l; @@ -904,7 +896,7 @@ void BM_face_kill(BMesh *bm, BMFace *f) do { l_next = l_iter->next; - bmesh_radial_loop_remove(l_iter, l_iter->e); + bmesh_radial_loop_remove(l_iter->e, l_iter); bm_kill_only_loop(bm, l_iter); } while ((l_iter = l_next) != l_first); @@ -949,7 +941,7 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f) l_next = l_iter->next; e = l_iter->e; - bmesh_radial_loop_remove(l_iter, e); + bmesh_radial_loop_remove(e, l_iter); bm_kill_only_loop(bm, l_iter); if (e->l == NULL) { @@ -981,23 +973,8 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f) */ void BM_edge_kill(BMesh *bm, BMEdge *e) { - - if (e->l) { - BMLoop *l = e->l, *lnext, *startl = e->l; - - do { - lnext = l->radial_next; - if (lnext->f == l->f) { - BM_face_kill(bm, l->f); - break; - } - - BM_face_kill(bm, l->f); - - if (l == lnext) - break; - l = lnext; - } while (l != startl); + while (e->l) { + BM_face_kill(bm, e->l->f); } bmesh_disk_edge_remove(e, e->v1); @@ -1011,15 +988,8 @@ void BM_edge_kill(BMesh *bm, BMEdge *e) */ void BM_vert_kill(BMesh *bm, BMVert *v) { - if (v->e) { - BMEdge *e, *e_next; - - e = v->e; - while (v->e) { - e_next = bmesh_disk_edge_next(e, v); - BM_edge_kill(bm, e); - e = e_next; - } + while (v->e) { + BM_edge_kill(bm, v->e); } bm_kill_only_vert(bm, v); @@ -1046,78 +1016,73 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l) * \brief Loop Reverse * * Changes the winding order of a face from CW to CCW or vice versa. - * This euler is a bit peculiar in comparison to others as it is its - * own inverse. - * - * BMESH_TODO: reinsert validation code. * * \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`. * \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp, * (use when flipping normals, disable when mirroring, eg: symmetrize). - * - * \return Success */ -static bool bm_loop_reverse_loop( +void bmesh_kernel_loop_reverse( BMesh *bm, BMFace *f, -#ifdef USE_BMESH_HOLES - BMLoopList *lst, -#endif const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip) { + BMLoop *l_first = f->l_first; -#ifdef USE_BMESH_HOLES - BMLoop *l_first = lst->first; + /* track previous cycles radial state */ + BMEdge *e_prev = l_first->prev->e; + BMLoop *l_prev_radial_next = l_first->prev->radial_next; + BMLoop *l_prev_radial_prev = l_first->prev->radial_prev; + bool is_prev_boundary = l_prev_radial_next == l_prev_radial_next->radial_next; + + BMLoop *l_iter = l_first; + do { + BMEdge *e_iter = l_iter->e; + BMLoop *l_iter_radial_next = l_iter->radial_next; + BMLoop *l_iter_radial_prev = l_iter->radial_prev; + bool is_iter_boundary = l_iter_radial_next == l_iter_radial_next->radial_next; + +#if 0 + bmesh_radial_loop_remove(e_iter, l_iter); + bmesh_radial_loop_append(e_prev, l_iter); #else - BMLoop *l_first = f->l_first; -#endif + /* inline loop reversal */ + if (is_prev_boundary) { + /* boundary */ + l_iter->radial_next = l_iter; + l_iter->radial_prev = l_iter; + } + else { + /* non-boundary, replace radial links */ + l_iter->radial_next = l_prev_radial_next; + l_iter->radial_prev = l_prev_radial_prev; + l_prev_radial_next->radial_prev = l_iter; + l_prev_radial_prev->radial_next = l_iter; + } - const int len = f->len; - BMLoop *l_iter, *oldprev, *oldnext; - BMEdge **edar = BLI_array_alloca(edar, len); - int i, j, edok; + if (e_iter->l == l_iter) { + e_iter->l = l_iter->next; + } + l_iter->e = e_prev; +#endif - for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) { - bmesh_radial_loop_remove(l_iter, (edar[i] = l_iter->e)); - } + SWAP(BMLoop *, l_iter->next, l_iter->prev); - /* actually reverse the loop */ - for (i = 0, l_iter = l_first; i < len; i++) { - oldnext = l_iter->next; - oldprev = l_iter->prev; - l_iter->next = oldprev; - l_iter->prev = oldnext; - l_iter = oldnext; - if (cd_loop_mdisp_offset != -1) { MDisps *md = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset); BKE_mesh_mdisp_flip(md, use_loop_mdisp_flip); } - } - if (len == 2) { /* two edged face */ - /* do some verification here! */ - l_first->e = edar[1]; - l_first->next->e = edar[0]; - } - else { - for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) { - edok = 0; - for (j = 0; j < len; j++) { - edok = BM_verts_in_edge(l_iter->v, l_iter->next->v, edar[j]); - if (edok) { - l_iter->e = edar[j]; - break; - } - } - } - } - /* rebuild radial */ - for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) - bmesh_radial_append(l_iter->e, l_iter); + e_prev = e_iter; + l_prev_radial_next = l_iter_radial_next; + l_prev_radial_prev = l_iter_radial_prev; + is_prev_boundary = is_iter_boundary; + + /* step to next (now swapped) */ + } while ((l_iter = l_iter->prev) != l_first); #ifndef NDEBUG /* validate radial */ - for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) { + int i; + for (i = 0, l_iter = l_first; i < f->len; i++, l_iter = l_iter->next) { BM_CHECK_ELEMENT(l_iter); BM_CHECK_ELEMENT(l_iter->e); BM_CHECK_ELEMENT(l_iter->v); @@ -1129,22 +1094,6 @@ static bool bm_loop_reverse_loop( /* Loop indices are no more valid! */ bm->elem_index_dirty |= BM_LOOP; - - return true; -} - -/** - * \brief Flip the faces direction - */ -bool bmesh_loop_reverse( - BMesh *bm, BMFace *f, - const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip) -{ -#ifdef USE_BMESH_HOLES - return bm_loop_reverse_loop(bm, f, f->loops.first, cd_loop_mdisp_offset, use_loop_mdisp_flip); -#else - return bm_loop_reverse_loop(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip); -#endif } static void bm_elements_systag_enable(void *veles, int tot, const char api_flag) @@ -1193,7 +1142,11 @@ static int UNUSED_FUNCTION(bm_vert_systag_count_disk)(BMVert *v, const char api_ return i; } -static bool disk_is_flagged(BMVert *v, const char api_flag) +/** + * Return true when the vertex is manifold, + * attached to faces which are all flagged. + */ +static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag) { BMEdge *e = v->e; @@ -1252,7 +1205,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) BLI_array_staticdeclare(deledges, BM_DEFAULT_NGON_STACK_SIZE); BLI_array_staticdeclare(delverts, BM_DEFAULT_NGON_STACK_SIZE); BMVert *v1 = NULL, *v2 = NULL; - int i, tote = 0; + int i; const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); if (UNLIKELY(!totface)) { @@ -1282,13 +1235,10 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) v1 = l_iter->v; v2 = BM_edge_other_vert(l_iter->e, l_iter->v); } - tote++; } else if (rlen == 2) { - int d1, d2; - - d1 = disk_is_flagged(l_iter->e->v1, _FLAG_JF); - d2 = disk_is_flagged(l_iter->e->v2, _FLAG_JF); + const bool d1 = bm_vert_is_manifold_flagged(l_iter->e->v1, _FLAG_JF); + const bool d2 = bm_vert_is_manifold_flagged(l_iter->e->v2, _FLAG_JF); if (!d1 && !d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_JF)) { /* don't remove an edge it makes up the side of another face @@ -1332,7 +1282,8 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) } /* create region face */ - f_new = tote ? BM_face_create_ngon(bm, v1, v2, edges, tote, faces[0], BM_CREATE_NOP) : NULL; + f_new = BLI_array_count(edges) ? + BM_face_create_ngon(bm, v1, v2, edges, BLI_array_count(edges), faces[0], BM_CREATE_NOP) : NULL; if (UNLIKELY(f_new == NULL)) { /* Invalid boundary region to join faces */ goto error; @@ -1350,10 +1301,11 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) } while (l2 != l_iter); if (l2 != l_iter) { - /* I think this is correct? */ + /* loops share an edge, shared vert depends on winding */ if (l2->v != l_iter->v) { l2 = l2->next; } + BLI_assert(l_iter->v == l2->v); BM_elem_attrs_copy(bm, bm, l2, l_iter); } @@ -1362,22 +1314,15 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) #ifdef USE_BMESH_HOLES /* add holes */ BLI_movelisttolist(&f_new->loops, &holes); -#endif /* update loop face pointer */ -#ifdef USE_BMESH_HOLES - for (lst = f_new->loops.first; lst; lst = lst->next) -#endif - { -#ifdef USE_BMESH_HOLES + for (lst = f_new->loops.first; lst; lst = lst->next) { l_iter = l_first = lst->first; -#else - l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); -#endif do { l_iter->f = f_new; } while ((l_iter = l_iter->next) != l_first); } +#endif bm_elements_systag_disable(faces, totface, _FLAG_JF); BM_ELEM_API_FLAG_DISABLE(f_new, _FLAG_JF); @@ -1493,7 +1438,7 @@ static BMFace *bm_face_create__sfme(BMesh *bm, BMFace *f_example) * * \return A BMFace pointer */ -BMFace *bmesh_sfme( +BMFace *bmesh_kernel_split_face_make_edge( BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2, BMLoop **r_l, #ifdef USE_BMESH_HOLES @@ -1585,8 +1530,8 @@ BMFace *bmesh_sfme( } while ((l_iter = l_iter->next) != l_first); /* link up the new loops into the new edges radial */ - bmesh_radial_append(e, l_f1); - bmesh_radial_append(e, l_f2); + bmesh_radial_loop_append(e, l_f1); + bmesh_radial_loop_append(e, l_f2); f2->len = f2len; @@ -1639,7 +1584,7 @@ BMFace *bmesh_sfme( * * \return The newly created BMVert pointer. */ -BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) +BMVert *bmesh_kernel_split_edge_make_vert(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) { BMLoop *l_next; BMEdge *e_new; @@ -1693,18 +1638,18 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) #ifndef NDEBUG int radlen = bmesh_radial_length(l_next); #endif - int first1 = 0, first2 = 0; + bool is_first = true; /* Take the next loop. Remove it from radial. Split it. Append to appropriate radials */ while (l_next) { l = l_next; l->f->len++; l_next = l_next != l_next->radial_next ? l_next->radial_next : NULL; - bmesh_radial_loop_remove(l, NULL); + bmesh_radial_loop_unlink(l); l_new = bm_loop_create(bm, NULL, NULL, l->f, l, 0); l_new->prev = l; - l_new->next = (l->next); + l_new->next = l->next; l_new->prev->next = l_new; l_new->next->prev = l_new; l_new->v = v_new; @@ -1715,36 +1660,26 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) l->e = e_new; /* append l into e_new's rad cycle */ - if (!first1) { - first1 = 1; - l->radial_next = l->radial_prev = NULL; - } - - if (!first2) { - first2 = 1; + if (is_first) { + is_first = false; l->radial_next = l->radial_prev = NULL; } - bmesh_radial_append(l_new->e, l_new); - bmesh_radial_append(l->e, l); + bmesh_radial_loop_append(l_new->e, l_new); + bmesh_radial_loop_append(l->e, l); } else if (BM_verts_in_edge(l_new->v, l_new->next->v, e_new)) { l_new->e = e_new; l->e = e; /* append l into e_new's rad cycle */ - if (!first1) { - first1 = 1; - l->radial_next = l->radial_prev = NULL; - } - - if (!first2) { - first2 = 1; + if (is_first) { + is_first = false; l->radial_next = l->radial_prev = NULL; } - bmesh_radial_append(l_new->e, l_new); - bmesh_radial_append(l->e, l); + bmesh_radial_loop_append(l_new->e, l_new); + bmesh_radial_loop_append(l->e, l); } } @@ -1831,7 +1766,7 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) * faces with just 2 edges. It is up to the caller to decide what to do with * these faces. */ -BMEdge *bmesh_jekv( +BMEdge *bmesh_kernel_join_edge_kill_vert( BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool check_edge_double, const bool kill_degenerate_faces) @@ -1839,7 +1774,6 @@ BMEdge *bmesh_jekv( BMEdge *e_old; BMVert *v_old, *v_target; BMLoop *l_kill; - bool halt = false; #ifndef NDEBUG int radlen, i; bool edok; @@ -1860,9 +1794,9 @@ BMEdge *bmesh_jekv( e_old = bmesh_disk_edge_next(e_kill, v_kill); v_target = BM_edge_other_vert(e_kill, v_kill); v_old = BM_edge_other_vert(e_old, v_kill); - halt = BM_verts_in_edge(v_kill, v_target, e_old); /* check for double edges */ - - if (halt) { + + /* check for double edges */ + if (BM_verts_in_edge(v_kill, v_target, e_old)) { return NULL; } else { @@ -1986,7 +1920,7 @@ BMEdge *bmesh_jekv( * * Collapse an edge, merging surrounding data. * - * Unlike #BM_vert_collapse_edge & #bmesh_jekv which only handle 2 valence verts, + * Unlike #BM_vert_collapse_edge & #bmesh_kernel_join_edge_kill_vert which only handle 2 valence verts, * this can handle any number of connected edges/faces. * * <pre> @@ -1998,7 +1932,7 @@ BMEdge *bmesh_jekv( * +-+-+-+ +-+-+-+ * </pre> */ -BMVert *bmesh_jvke( +BMVert *bmesh_kernel_join_vert_kill_edge( BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool check_edge_double, const bool kill_degenerate_faces) @@ -2101,7 +2035,7 @@ BMVert *bmesh_jvke( * In the example A, faces \a f1 and \a f2 are joined by a single edge, * and the euler can safely be used. * In example B however, \a f1 and \a f2 are joined by multiple edges and will produce an error. - * The caller in this case should call #bmesh_jekv on the extra edges + * The caller in this case should call #bmesh_kernel_join_edge_kill_vert on the extra edges * before attempting to fuse \a f1 and \a f2. * * \note The order of arguments decides whether or not certain per-face attributes are present @@ -2110,7 +2044,7 @@ BMVert *bmesh_jvke( * * \return A BMFace pointer */ -BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) +BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) { BMLoop *l_iter, *l_f1 = NULL, *l_f2 = NULL; int newlen = 0, i, f1len = 0, f2len = 0; @@ -2315,7 +2249,7 @@ bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src) } -/** \name BM_vert_separate, bmesh_vert_separate and friends +/** \name BM_vert_separate, bmesh_kernel_vert_separate and friends * \{ */ /* BM_edge_face_count(e) >= 1 */ @@ -2335,7 +2269,7 @@ BLI_INLINE bool bm_edge_supports_separate(const BMEdge *e) * * \return Success */ -void bmesh_vert_separate( +void bmesh_kernel_vert_separate( BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select) { @@ -2413,7 +2347,7 @@ void bmesh_vert_separate( v_new = BM_vert_create(bm, v->co, v, BM_CREATE_NOP); if (copy_select) { - BM_elem_select_copy(bm, bm, v_new, v); + BM_elem_select_copy(bm, v_new, v); } while ((e = BLI_SMALLSTACK_POP(edges))) { @@ -2451,7 +2385,7 @@ void bmesh_vert_separate( * * Takes a list of edges, which have been split from their original. * - * Any edges which failed to split off in #bmesh_vert_separate will be merged back into the original edge. + * Any edges which failed to split off in #bmesh_kernel_vert_separate will be merged back into the original edge. * * \param edges_separate * A list-of-lists, each list is from a single original edge (the first edge is the original), @@ -2464,24 +2398,24 @@ void bmesh_vert_separate( * \note this function looks like it could become slow, * but in common cases its only going to iterate a few times. */ -static void bmesh_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate) +static void bmesh_kernel_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate) { do { LinkNode *n_orig = edges_separate->link; do { - BMEdge *e_orig = n_orig->link; - LinkNode *n_step = n_orig->next; LinkNode *n_prev = n_orig; + LinkNode *n_step = n_orig->next; + BMEdge *e_orig = n_orig->link; do { BMEdge *e = n_step->link; BLI_assert(e != e_orig); - if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2)) { - BM_edge_splice(bm, e_orig, e); + if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2) && + BM_edge_splice(bm, e_orig, e)) + { + /* don't visit again */ n_prev->next = n_step->next; - n_step = n_prev; } - } while ((void) - (n_prev = n_step), + } while ((n_prev = n_step), (n_step = n_step->next)); } while ((n_orig = n_orig->next) && n_orig->next); @@ -2489,7 +2423,7 @@ static void bmesh_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate) } /** - * High level function which wraps both #bmesh_vert_separate and #bmesh_edge_separate + * High level function which wraps both #bmesh_kernel_vert_separate and #bmesh_kernel_edge_separate */ void BM_vert_separate( BMesh *bm, BMVert *v, @@ -2506,7 +2440,7 @@ void BM_vert_separate( LinkNode *edges_orig = NULL; do { BMLoop *l_sep = e->l; - bmesh_edge_separate(bm, e, l_sep, copy_select); + bmesh_kernel_edge_separate(bm, e, l_sep, copy_select); BLI_linklist_prepend_alloca(&edges_orig, l_sep->e); BLI_assert(e != l_sep->e); } while (bm_edge_supports_separate(e)); @@ -2515,10 +2449,10 @@ void BM_vert_separate( } } - bmesh_vert_separate(bm, v, r_vout, r_vout_len, copy_select); + bmesh_kernel_vert_separate(bm, v, r_vout, r_vout_len, copy_select); if (edges_separate) { - bmesh_vert_separate__cleanup(bm, edges_separate); + bmesh_kernel_vert_separate__cleanup(bm, edges_separate); } } @@ -2543,7 +2477,7 @@ void BM_vert_separate_hflag( LinkNode *edges_orig = NULL; do { BMLoop *l_sep = e->l; - bmesh_edge_separate(bm, e, l_sep, copy_select); + bmesh_kernel_edge_separate(bm, e, l_sep, copy_select); /* trick to avoid looping over separated edges */ if (edges_separate == NULL && edges_orig == NULL) { e_first = l_sep->e; @@ -2557,10 +2491,10 @@ void BM_vert_separate_hflag( } } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first); - bmesh_vert_separate(bm, v, r_vout, r_vout_len, copy_select); + bmesh_kernel_vert_separate(bm, v, r_vout, r_vout_len, copy_select); if (edges_separate) { - bmesh_vert_separate__cleanup(bm, edges_separate); + bmesh_kernel_vert_separate__cleanup(bm, edges_separate); } } @@ -2619,8 +2553,8 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src) l = e_src->l; BLI_assert(BM_vert_in_edge(e_dst, l->v)); BLI_assert(BM_vert_in_edge(e_dst, l->next->v)); - bmesh_radial_loop_remove(l, e_src); - bmesh_radial_append(e_dst, l); + bmesh_radial_loop_remove(e_src, l); + bmesh_radial_loop_append(e_dst, l); } BLI_assert(bmesh_radial_length(e_src->l) == 0); @@ -2645,7 +2579,7 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src) * \note Does nothing if \a l_sep is already the only loop in the * edge radial. */ -void bmesh_edge_separate( +void bmesh_kernel_edge_separate( BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select) { @@ -2667,12 +2601,12 @@ void bmesh_edge_separate( } e_new = BM_edge_create(bm, e->v1, e->v2, e, BM_CREATE_NOP); - bmesh_radial_loop_remove(l_sep, e); - bmesh_radial_append(e_new, l_sep); + bmesh_radial_loop_remove(e, l_sep); + bmesh_radial_loop_append(e_new, l_sep); l_sep->e = e_new; if (copy_select) { - BM_elem_select_copy(bm, bm, e_new, e); + BM_elem_select_copy(bm, e_new, e); } BLI_assert(bmesh_radial_length(e->l) == radlen - 1); @@ -2691,7 +2625,7 @@ void bmesh_edge_separate( * * \note Will be a no-op and return original vertex if only two edges at that vertex. */ -BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep) +BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep) { BMVert *v_new = NULL; BMVert *v_sep = l_sep->v; @@ -2701,10 +2635,12 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep) /* peel the face from the edge radials on both sides of the * loop vert, disconnecting the face from its fan */ - if (!BM_edge_is_boundary(l_sep->e)) - bmesh_edge_separate(bm, l_sep->e, l_sep, false); - if (!BM_edge_is_boundary(l_sep->prev->e)) - bmesh_edge_separate(bm, l_sep->prev->e, l_sep->prev, false); + if (!BM_edge_is_boundary(l_sep->e)) { + bmesh_kernel_edge_separate(bm, l_sep->e, l_sep, false); + } + if (!BM_edge_is_boundary(l_sep->prev->e)) { + bmesh_kernel_edge_separate(bm, l_sep->prev->e, l_sep->prev, false); + } /* do inline, below */ #if 0 @@ -2752,19 +2688,23 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep) } /** - * A version of #bmesh_urmv_loop that disconnects multiple loops at once. + * A version of #bmesh_kernel_unglue_region_make_vert that disconnects multiple loops at once. + * The loops must all share the same vertex, can be in any order + * and are all moved to use a single new vertex - which is returned. * - * Handles the task of finding fans boundaries. + * This function handles the details of finding fans boundaries. */ -BMVert *bmesh_urmv_loop_multi( +BMVert *bmesh_kernel_unglue_region_make_vert_multi( BMesh *bm, BMLoop **larr, int larr_len) { BMVert *v_sep = larr[0]->v; BMVert *v_new; + int edges_len = 0; int i; - bool is_mixed_any = false; - - BLI_SMALLSTACK_DECLARE(edges, BMEdge *); + /* any edges not owned by 'larr' loops connected to 'v_sep'? */ + bool is_mixed_edge_any = false; + /* any loops not owned by 'larr' radially connected to 'larr' loop edges? */ + bool is_mixed_loop_any = false; #define LOOP_VISIT _FLAG_WALK #define EDGE_VISIT _FLAG_WALK @@ -2782,58 +2722,74 @@ BMVert *bmesh_urmv_loop_multi( * while doing a radial loop (where loops may be adjacent) */ BM_ELEM_API_FLAG_ENABLE(l_sep->next, LOOP_VISIT); BM_ELEM_API_FLAG_ENABLE(l_sep->prev, LOOP_VISIT); - } - - for (i = 0; i < larr_len; i++) { - BMLoop *l_sep = larr[i]; BMLoop *loop_pair[2] = {l_sep, l_sep->prev}; - int j; - for (j = 0; j < ARRAY_SIZE(loop_pair); j++) { + for (int j = 0; j < ARRAY_SIZE(loop_pair); j++) { BMEdge *e = loop_pair[j]->e; if (!BM_ELEM_API_FLAG_TEST(e, EDGE_VISIT)) { - BMLoop *l_iter, *l_first; - bool is_mixed = false; - BM_ELEM_API_FLAG_ENABLE(e, EDGE_VISIT); + edges_len += 1; + } + } + } - l_iter = l_first = e->l; + BMEdge **edges = BLI_array_alloca(edges, edges_len); + STACK_DECLARE(edges); + + STACK_INIT(edges, edges_len); + + { + BMEdge *e_first, *e_iter; + e_iter = e_first = v_sep->e; + do { + if (BM_ELEM_API_FLAG_TEST(e_iter, EDGE_VISIT)) { + BMLoop *l_iter, *l_first; + bool is_mixed_loop = false; + + l_iter = l_first = e_iter->l; do { if (!BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) { - is_mixed = true; - is_mixed_any = true; + is_mixed_loop = true; break; } } while ((l_iter = l_iter->radial_next) != l_first); - if (is_mixed) { + if (is_mixed_loop) { /* ensure the first loop is one we don't own so we can do a quick check below * on the edge's loop-flag to see if the edge is mixed or not. */ - e->l = l_iter; + e_iter->l = l_iter; + + is_mixed_loop_any = true; } - BLI_SMALLSTACK_PUSH(edges, e); + + STACK_PUSH(edges, e_iter); } - } + else { + /* at least one edge attached isn't connected to our loops */ + is_mixed_edge_any = true; + } + } while ((e_iter = bmesh_disk_edge_next(e_iter, v_sep)) != e_first); } - if (is_mixed_any == false) { + BLI_assert(edges_len == STACK_SIZE(edges)); + + if (is_mixed_loop_any == false && is_mixed_edge_any == false) { /* all loops in 'larr' are the sole owners of their edges. * nothing to split away from, this is a no-op */ v_new = v_sep; } else { - BMEdge *e; - - BLI_assert(!BLI_SMALLSTACK_IS_EMPTY(edges)); - v_new = BM_vert_create(bm, v_sep->co, v_sep, BM_CREATE_NOP); - while ((e = BLI_SMALLSTACK_POP(edges))) { + + for (i = 0; i < STACK_SIZE(edges); i++) { + BMEdge *e = edges[i]; BMLoop *l_iter, *l_first, *l_next; BMEdge *e_new; /* disable so copied edge isn't left dirty (loop edges are cleared last too) */ BM_ELEM_API_FLAG_DISABLE(e, EDGE_VISIT); + /* will always be false when (is_mixed_loop_any == false) */ if (!BM_ELEM_API_FLAG_TEST(e->l, LOOP_VISIT)) { /* edge has some loops owned by us, some owned by other loops */ BMVert *e_new_v_pair[2]; @@ -2855,8 +2811,8 @@ BMVert *bmesh_urmv_loop_multi( do { l_next = l_iter->radial_next; if (BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) { - bmesh_radial_loop_remove(l_iter, e); - bmesh_radial_append(e_new, l_iter); + bmesh_radial_loop_remove(e, l_iter); + bmesh_radial_loop_append(e_new, l_iter); l_iter->e = e_new; } } while ((l_iter = l_next) != l_first); @@ -2922,9 +2878,9 @@ static void bmesh_edge_vert_swap__recursive(BMEdge *e, BMVert *v_dst, BMVert *v_ /** * This function assumes l_sep is apart of a larger fan which has already been - * isolated by calling bmesh_edge_separate to segregate it radially. + * isolated by calling #bmesh_kernel_edge_separate to segregate it radially. */ -BMVert *bmesh_urmv_loop_region(BMesh *bm, BMLoop *l_sep) +BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep) { BMVert *v_new = BM_vert_create(bm, l_sep->v->co, l_sep->v, BM_CREATE_NOP); /* passing either 'l_sep->e', 'l_sep->prev->e' will work */ @@ -2933,20 +2889,6 @@ BMVert *bmesh_urmv_loop_region(BMesh *bm, BMLoop *l_sep) return v_new; } - -/** - * \brief Unglue Region Make Vert (URMV) - * - * Disconnects f_sep from the vertex fan at \a v_sep - * - * \return The newly created BMVert - */ -BMVert *bmesh_urmv(BMesh *bm, BMFace *f_sep, BMVert *v_sep) -{ - BMLoop *l = BM_face_vert_share_loop(f_sep, v_sep); - return bmesh_urmv_loop(bm, l); -} - /** * Avoid calling this where possible, * low level function so both face pointers remain intact but point to swapped data. diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h index fb5702bc574..fb6b66809f3 100644 --- a/source/blender/bmesh/intern/bmesh_core.h +++ b/source/blender/bmesh/intern/bmesh_core.h @@ -64,21 +64,16 @@ void BM_face_kill(BMesh *bm, BMFace *f); void BM_edge_kill(BMesh *bm, BMEdge *e); void BM_vert_kill(BMesh *bm, BMVert *v); -void bmesh_edge_separate( - BMesh *bm, BMEdge *e, BMLoop *l_sep, - const bool copy_select); bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src); bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src); bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b); -void bmesh_vert_separate( - BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, - const bool copy_select); - -bool bmesh_loop_reverse( +void bmesh_kernel_loop_reverse( BMesh *bm, BMFace *f, const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip); +void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b); + BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del); void BM_vert_separate( BMesh *bm, BMVert *v, BMEdge **e_in, int e_in_len, const bool copy_select, @@ -90,34 +85,43 @@ void BM_vert_separate_wire_hflag( BMesh *bm, BMVert *v_dst, BMVert *v_src, const char hflag); -/* EULER API - For modifying structure */ -BMFace *bmesh_sfme( +/** + * BMesh Kernel: For modifying structure. + * + * Names are on the verbose side but these are only for low-level access. + */ +void bmesh_kernel_vert_separate( + BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, + const bool copy_select); +void bmesh_kernel_edge_separate( + BMesh *bm, BMEdge *e, BMLoop *l_sep, + const bool copy_select); + +BMFace *bmesh_kernel_split_face_make_edge( BMesh *bm, BMFace *f, BMLoop *l1, BMLoop *l2, BMLoop **r_l, #ifdef USE_BMESH_HOLES - ListBase *holes, + ListBase *holes, #endif - BMEdge *example, - const bool no_double - ); + BMEdge *example, + const bool no_double + ); -BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e); -BMEdge *bmesh_jekv( +BMVert *bmesh_kernel_split_edge_make_vert( + BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e); +BMEdge *bmesh_kernel_join_edge_kill_vert( BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool check_edge_splice, const bool kill_degenerate_faces); -BMVert *bmesh_jvke( +BMVert *bmesh_kernel_join_vert_kill_edge( BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool check_edge_double, const bool kill_degenerate_faces); -BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e); -BMVert *bmesh_urmv(BMesh *bm, BMFace *f_sep, BMVert *v_sep); -BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep); -BMVert *bmesh_urmv_loop_multi( - BMesh *bm, BMLoop **larr, int larr_len); -BMVert *bmesh_urmv_loop_region(BMesh *bm, BMLoop *l_sep); +BMFace *bmesh_kernel_join_face_kill_edge(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e); -void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b); +BMVert *bmesh_kernel_unglue_region_make_vert(BMesh *bm, BMLoop *l_sep); +BMVert *bmesh_kernel_unglue_region_make_vert_multi(BMesh *bm, BMLoop **larr, int larr_len); +BMVert *bmesh_kernel_unglue_region_make_vert_multi_isolated(BMesh *bm, BMLoop *l_sep); #endif /* __BMESH_CORE_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c index 5e1d9c3a98d..5780dc57d78 100644 --- a/source/blender/bmesh/intern/bmesh_edgeloop.c +++ b/source/blender/bmesh/intern/bmesh_edgeloop.c @@ -58,7 +58,7 @@ static int bm_vert_other_tag( { BMIter iter; BMEdge *e, *e_next = NULL; - unsigned int count = 0; + uint count = 0; BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { if (BM_elem_flag_test(e, BM_ELEM_INTERNAL_TAG)) { diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index 1a4b812f87f..5c076f258de 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -339,7 +339,7 @@ static bool mdisp_in_mdispquad( compute_mdisp_quad(l_dst, l_dst_f_center, v1, v2, v3, v4, e1, e2); /* expand quad a bit */ - cent_quad_v3(c, v1, v2, v3, v4); + mid_v3_v3v3v3v3(c, v1, v2, v3, v4); sub_v3_v3(v1, c); sub_v3_v3(v2, c); sub_v3_v3(v3, c); sub_v3_v3(v4, c); diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c index 961b10d848a..96154f051f9 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.c +++ b/source/blender/bmesh/intern/bmesh_iterators.c @@ -485,9 +485,9 @@ void bmiter__face_of_vert_begin(struct BMIter__face_of_vert *iter) { ((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata); if (((BMIter *)iter)->count) { - iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata); + iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata); + iter->e_first = iter->l_first->e; iter->e_next = iter->e_first; - iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata); iter->l_next = iter->l_first; } else { @@ -526,9 +526,9 @@ void bmiter__loop_of_vert_begin(struct BMIter__loop_of_vert *iter) { ((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata); if (((BMIter *)iter)->count) { - iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata); + iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata); + iter->e_first = iter->l_first->e; iter->e_next = iter->e_first; - iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata); iter->l_next = iter->l_first; } else { diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h index 0551d824131..ab066682081 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.h +++ b/source/blender/bmesh/intern/bmesh_iterators.h @@ -211,12 +211,12 @@ void *BMO_iter_as_arrayN( int BM_iter_mesh_bitmap_from_filter( const char itype, BMesh *bm, - unsigned int *bitmap, + uint *bitmap, bool (*test_fn)(BMElem *, void *user_data), void *user_data); int BM_iter_mesh_bitmap_from_filter_tessface( BMesh *bm, - unsigned int *bitmap, + uint *bitmap, bool (*test_fn)(BMFace *, void *user_data), void *user_data); diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c index 1f64f7b74cc..1d16dbc1836 100644 --- a/source/blender/bmesh/intern/bmesh_log.c +++ b/source/blender/bmesh/intern/bmesh_log.c @@ -45,7 +45,7 @@ #include "bmesh.h" #include "bmesh_log.h" -#include "range_tree_c_api.h" +#include "range_tree.h" #include "BLI_strict_flags.h" @@ -88,7 +88,7 @@ struct BMLog { /* Mapping from unique IDs to vertices and faces * - * Each vertex and face in the log gets a unique unsigned integer + * Each vertex and face in the log gets a unique uinteger * assigned. That ID is taken from the set managed by the * unused_ids range tree. * @@ -120,7 +120,7 @@ typedef struct { } BMLogVert; typedef struct { - unsigned int v_ids[3]; + uint v_ids[3]; char hflag; } BMLogFace; @@ -131,14 +131,14 @@ typedef struct { #define logkey_cmp BLI_ghashutil_intcmp /* Get the vertex's unique ID from the log */ -static unsigned int bm_log_vert_id_get(BMLog *log, BMVert *v) +static uint bm_log_vert_id_get(BMLog *log, BMVert *v) { BLI_assert(BLI_ghash_haskey(log->elem_to_id, v)); return GET_UINT_FROM_POINTER(BLI_ghash_lookup(log->elem_to_id, v)); } /* Set the vertex's unique ID in the log */ -static void bm_log_vert_id_set(BMLog *log, BMVert *v, unsigned int id) +static void bm_log_vert_id_set(BMLog *log, BMVert *v, uint id) { void *vid = SET_UINT_IN_POINTER(id); @@ -147,7 +147,7 @@ static void bm_log_vert_id_set(BMLog *log, BMVert *v, unsigned int id) } /* Get a vertex from its unique ID */ -static BMVert *bm_log_vert_from_id(BMLog *log, unsigned int id) +static BMVert *bm_log_vert_from_id(BMLog *log, uint id) { void *key = SET_UINT_IN_POINTER(id); BLI_assert(BLI_ghash_haskey(log->id_to_elem, key)); @@ -155,14 +155,14 @@ static BMVert *bm_log_vert_from_id(BMLog *log, unsigned int id) } /* Get the face's unique ID from the log */ -static unsigned int bm_log_face_id_get(BMLog *log, BMFace *f) +static uint bm_log_face_id_get(BMLog *log, BMFace *f) { BLI_assert(BLI_ghash_haskey(log->elem_to_id, f)); return GET_UINT_FROM_POINTER(BLI_ghash_lookup(log->elem_to_id, f)); } /* Set the face's unique ID in the log */ -static void bm_log_face_id_set(BMLog *log, BMFace *f, unsigned int id) +static void bm_log_face_id_set(BMLog *log, BMFace *f, uint id) { void *fid = SET_UINT_IN_POINTER(id); @@ -171,7 +171,7 @@ static void bm_log_face_id_set(BMLog *log, BMFace *f, unsigned int id) } /* Get a face from its unique ID */ -static BMFace *bm_log_face_from_id(BMLog *log, unsigned int id) +static BMFace *bm_log_face_from_id(BMLog *log, uint id) { void *key = SET_UINT_IN_POINTER(id); BLI_assert(BLI_ghash_haskey(log->id_to_elem, key)); @@ -255,7 +255,7 @@ static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts) GHASH_ITER (gh_iter, verts) { void *key = BLI_ghashIterator_getKey(&gh_iter); BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter); - unsigned int id = GET_UINT_FROM_POINTER(key); + uint id = GET_UINT_FROM_POINTER(key); BMVert *v = bm_log_vert_from_id(log, id); /* Ensure the log has the final values of the vertex before @@ -271,7 +271,7 @@ static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces) GHashIterator gh_iter; GHASH_ITER (gh_iter, faces) { void *key = BLI_ghashIterator_getKey(&gh_iter); - unsigned int id = GET_UINT_FROM_POINTER(key); + uint id = GET_UINT_FROM_POINTER(key); BMFace *f = bm_log_face_from_id(log, id); BMEdge *e_tri[3]; BMLoop *l_iter; @@ -333,7 +333,7 @@ static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts) GHASH_ITER (gh_iter, verts) { void *key = BLI_ghashIterator_getKey(&gh_iter); BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter); - unsigned int id = GET_UINT_FROM_POINTER(key); + uint id = GET_UINT_FROM_POINTER(key); BMVert *v = bm_log_vert_from_id(log, id); float mask; short normal[3]; @@ -355,7 +355,7 @@ static void bm_log_face_values_swap(BMLog *log, GHash *faces) GHASH_ITER (gh_iter, faces) { void *key = BLI_ghashIterator_getKey(&gh_iter); BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter); - unsigned int id = GET_UINT_FROM_POINTER(key); + uint id = GET_UINT_FROM_POINTER(key); BMFace *f = bm_log_face_from_id(log, id); SWAP(char, f->head.hflag, lf->hflag); @@ -374,13 +374,13 @@ static void bm_log_assign_ids(BMesh *bm, BMLog *log) /* Generate vertex IDs */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - unsigned int id = range_tree_uint_take_any(log->unused_ids); + uint id = range_tree_uint_take_any(log->unused_ids); bm_log_vert_id_set(log, v, id); } /* Generate face IDs */ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - unsigned int id = range_tree_uint_take_any(log->unused_ids); + uint id = range_tree_uint_take_any(log->unused_ids); bm_log_face_id_set(log, f, id); } } @@ -425,7 +425,7 @@ static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash) GHASH_ITER (gh_iter, id_ghash) { void *key = BLI_ghashIterator_getKey(&gh_iter); - unsigned int id = GET_UINT_FROM_POINTER(key); + uint id = GET_UINT_FROM_POINTER(key); range_tree_uint_retake(unused_ids, id); } @@ -433,8 +433,8 @@ static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash) static int uint_compare(const void *a_v, const void *b_v) { - const unsigned int *a = a_v; - const unsigned int *b = b_v; + const uint *a = a_v; + const uint *b = b_v; return (*a) < (*b); } @@ -446,10 +446,10 @@ static int uint_compare(const void *a_v, const void *b_v) * 10 -> 3 * 3 -> 1 */ -static GHash *bm_log_compress_ids_to_indices(unsigned int *ids, unsigned int totid) +static GHash *bm_log_compress_ids_to_indices(uint *ids, uint totid) { GHash *map = BLI_ghash_int_new_ex(__func__, totid); - unsigned int i; + uint i; qsort(ids, totid, sizeof(*ids), uint_compare); @@ -469,7 +469,7 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash) GHASH_ITER (gh_iter, id_ghash) { void *key = BLI_ghashIterator_getKey(&gh_iter); - unsigned int id = GET_UINT_FROM_POINTER(key); + uint id = GET_UINT_FROM_POINTER(key); range_tree_uint_release(log->unused_ids, id); } } @@ -480,7 +480,7 @@ static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash) BMLog *BM_log_create(BMesh *bm) { BMLog *log = MEM_callocN(sizeof(*log), __func__); - const unsigned int reserve_num = (unsigned int)(bm->totvert + bm->totface); + const uint reserve_num = (uint)(bm->totvert + bm->totface); log->unused_ids = range_tree_uint_alloc(0, (unsigned)-1); log->id_to_elem = BLI_ghash_new_ex(logkey_hash, logkey_cmp, __func__, reserve_num); @@ -593,8 +593,8 @@ int BM_log_length(const BMLog *log) /* Apply a consistent ordering to BMesh vertices */ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log) { - unsigned int *varr; - unsigned int *farr; + uint *varr; + uint *farr; GHash *id_to_idx; @@ -602,7 +602,7 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log) BMVert *v; BMFace *f; - unsigned int i; + uint i; /* Put all vertex IDs into an array */ varr = MEM_mallocN(sizeof(int) * (size_t)bm->totvert, __func__); @@ -617,7 +617,7 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log) } /* Create BMVert index remap array */ - id_to_idx = bm_log_compress_ids_to_indices(varr, (unsigned int)bm->totvert); + id_to_idx = bm_log_compress_ids_to_indices(varr, (uint)bm->totvert); BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) { const unsigned id = bm_log_vert_id_get(log, v); const void *key = SET_UINT_IN_POINTER(id); @@ -627,7 +627,7 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log) BLI_ghash_free(id_to_idx, NULL, NULL); /* Create BMFace index remap array */ - id_to_idx = bm_log_compress_ids_to_indices(farr, (unsigned int)bm->totface); + id_to_idx = bm_log_compress_ids_to_indices(farr, (uint)bm->totface); BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) { const unsigned id = bm_log_face_id_get(log, f); const void *key = SET_UINT_IN_POINTER(id); @@ -835,7 +835,7 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o { BMLogEntry *entry = log->current_entry; BMLogVert *lv; - unsigned int v_id = bm_log_vert_id_get(log, v); + uint v_id = bm_log_vert_id_get(log, v); void *key = SET_UINT_IN_POINTER(v_id); void **val_p; @@ -859,7 +859,7 @@ void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_o void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset) { BMLogVert *lv; - unsigned int v_id = range_tree_uint_take_any(log->unused_ids); + uint v_id = range_tree_uint_take_any(log->unused_ids); void *key = SET_UINT_IN_POINTER(v_id); bm_log_vert_id_set(log, v, v_id); @@ -876,7 +876,7 @@ void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset) void BM_log_face_modified(BMLog *log, BMFace *f) { BMLogFace *lf; - unsigned int f_id = bm_log_face_id_get(log, f); + uint f_id = bm_log_face_id_get(log, f); void *key = SET_UINT_IN_POINTER(f_id); lf = bm_log_face_alloc(log, f); @@ -892,7 +892,7 @@ void BM_log_face_modified(BMLog *log, BMFace *f) void BM_log_face_added(BMLog *log, BMFace *f) { BMLogFace *lf; - unsigned int f_id = range_tree_uint_take_any(log->unused_ids); + uint f_id = range_tree_uint_take_any(log->unused_ids); void *key = SET_UINT_IN_POINTER(f_id); /* Only triangles are supported for now */ @@ -922,7 +922,7 @@ void BM_log_face_added(BMLog *log, BMFace *f) void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset) { BMLogEntry *entry = log->current_entry; - unsigned int v_id = bm_log_vert_id_get(log, v); + uint v_id = bm_log_vert_id_get(log, v); void *key = SET_UINT_IN_POINTER(v_id); /* if it has a key, it shouldn't be NULL */ @@ -963,7 +963,7 @@ void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset) void BM_log_face_removed(BMLog *log, BMFace *f) { BMLogEntry *entry = log->current_entry; - unsigned int f_id = bm_log_face_id_get(log, f); + uint f_id = bm_log_face_id_get(log, f); void *key = SET_UINT_IN_POINTER(f_id); /* if it has a key, it shouldn't be NULL */ @@ -991,11 +991,11 @@ void BM_log_all_added(BMesh *bm, BMLog *log) /* avoid unnecessary resizing on initialization */ if (BLI_ghash_size(log->current_entry->added_verts) == 0) { - BLI_ghash_reserve(log->current_entry->added_verts, (unsigned int)bm->totvert); + BLI_ghash_reserve(log->current_entry->added_verts, (uint)bm->totvert); } if (BLI_ghash_size(log->current_entry->added_faces) == 0) { - BLI_ghash_reserve(log->current_entry->added_faces, (unsigned int)bm->totface); + BLI_ghash_reserve(log->current_entry->added_faces, (uint)bm->totface); } /* Log all vertices as newly created */ diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index 7178a8132d2..7f2032d5f53 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -70,7 +70,7 @@ static void recount_totsels(BMesh *bm) } } -/** \name BMesh helper functions for selection flushing. +/** \name BMesh helper functions for selection & hide flushing. * \{ */ static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first) @@ -102,6 +102,20 @@ static bool bm_vert_is_edge_select_any(const BMVert *v) } #endif +static bool bm_vert_is_edge_visible_any(const BMVert *v) +{ + if (v->e) { + const BMEdge *e_iter, *e_first; + e_iter = e_first = v->e; + do { + if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) { + return true; + } + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first); + } + return false; +} + static bool bm_edge_is_face_select_any_other(BMLoop *l_first) { const BMLoop *l_iter = l_first; @@ -131,6 +145,20 @@ static bool bm_edge_is_face_select_any(const BMEdge *e) } #endif +static bool bm_edge_is_face_visible_any(const BMEdge *e) +{ + if (e->l) { + const BMLoop *l_iter, *l_first; + l_iter = l_first = e->l; + do { + if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) { + return true; + } + } while ((l_iter = l_iter->radial_next) != l_first); + } + return false; +} + /** \} */ /** @@ -1198,87 +1226,111 @@ void BM_mesh_elem_hflag_enable_all( /***************** Mesh Hiding stuff *********** */ +/** + * Hide unless any connected elements are visible. + * Run this after hiding a connected edge or face. + */ static void vert_flush_hide_set(BMVert *v) { - BMIter iter; - BMEdge *e; - bool hide = true; - - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - hide = hide && BM_elem_flag_test(e, BM_ELEM_HIDDEN); - } - - BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide); + BM_elem_flag_set(v, BM_ELEM_HIDDEN, !bm_vert_is_edge_visible_any(v)); } -static void edge_flush_hide(BMEdge *e) +/** + * Hide unless any connected elements are visible. + * Run this after hiding a connected face. + */ +static void edge_flush_hide_set(BMEdge *e) { - BMIter iter; - BMFace *f; - bool hide = true; - - BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { - hide = hide && BM_elem_flag_test(f, BM_ELEM_HIDDEN); - } - - BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide); + BM_elem_flag_set(e, BM_ELEM_HIDDEN, !bm_edge_is_face_visible_any(e)); } void BM_vert_hide_set(BMVert *v, const bool hide) { /* vert hiding: vert + surrounding edges and faces */ - BMIter iter, fiter; - BMEdge *e; - BMFace *f; - BLI_assert(v->head.htype == BM_VERT); + if (hide) { + BLI_assert(!BM_elem_flag_test(v, BM_ELEM_SELECT)); + } BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide); - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide); - - BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide); - } + if (v->e) { + BMEdge *e_iter, *e_first; + e_iter = e_first = v->e; + do { + BM_elem_flag_set(e_iter, BM_ELEM_HIDDEN, hide); + if (e_iter->l) { + const BMLoop *l_radial_iter, *l_radial_first; + l_radial_iter = l_radial_first = e_iter->l; + do { + BM_elem_flag_set(l_radial_iter->f, BM_ELEM_HIDDEN, hide); + } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first); + } + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first); } } void BM_edge_hide_set(BMEdge *e, const bool hide) { - BMIter iter; - BMFace *f; - /* BMVert *v; */ - BLI_assert(e->head.htype == BM_EDGE); + if (hide) { + BLI_assert(!BM_elem_flag_test(e, BM_ELEM_SELECT)); + } /* edge hiding: faces around the edge */ - BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { - BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide); + if (e->l) { + const BMLoop *l_iter, *l_first; + l_iter = l_first = e->l; + do { + BM_elem_flag_set(l_iter->f, BM_ELEM_HIDDEN, hide); + } while ((l_iter = l_iter->radial_next) != l_first); } BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide); /* hide vertices if necessary */ - vert_flush_hide_set(e->v1); - vert_flush_hide_set(e->v2); + if (hide) { + vert_flush_hide_set(e->v1); + vert_flush_hide_set(e->v2); + } + else { + BM_elem_flag_disable(e->v1, BM_ELEM_HIDDEN); + BM_elem_flag_disable(e->v2, BM_ELEM_HIDDEN); + } } void BM_face_hide_set(BMFace *f, const bool hide) { - BMIter iter; - BMLoop *l; - BLI_assert(f->head.htype == BM_FACE); + if (hide) { + BLI_assert(!BM_elem_flag_test(f, BM_ELEM_SELECT)); + } BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide); - BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { - edge_flush_hide(l->e); + if (hide) { + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter; + + l_iter = l_first; + do { + edge_flush_hide_set(l_iter->e); + } while ((l_iter = l_iter->next) != l_first); + + l_iter = l_first; + do { + vert_flush_hide_set(l_iter->v); + } while ((l_iter = l_iter->next) != l_first); } + else { + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter; - BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { - vert_flush_hide_set(l->v); + l_iter = l_first; + do { + BM_elem_flag_disable(l_iter->e, BM_ELEM_HIDDEN); + BM_elem_flag_disable(l_iter->v, BM_ELEM_HIDDEN); + } while ((l_iter = l_iter->next) != l_first); } } diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index 57a6d8d2e1a..d5d9e4abe2c 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -486,8 +486,7 @@ static void bm_mesh_edges_sharp_tag( BMesh *bm, const float (*vnos)[3], const float (*fnos)[3], float split_angle, float (*r_lnos)[3]) { - BMIter eiter, viter; - BMVert *v; + BMIter eiter; BMEdge *e; int i; @@ -498,19 +497,13 @@ static void bm_mesh_edges_sharp_tag( } { - char htype = BM_LOOP; + char htype = BM_VERT | BM_LOOP; if (fnos) { htype |= BM_FACE; } BM_mesh_elem_index_ensure(bm, htype); } - /* Clear all vertices' tags (means they are all smooth for now). */ - BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { - BM_elem_index_set(v, i); /* set_inline */ - BM_elem_flag_disable(v, BM_ELEM_TAG); - } - /* This first loop checks which edges are actually smooth, and pre-populate lnos with vnos (as if they were * all smooth). */ @@ -551,20 +544,45 @@ static void bm_mesh_edges_sharp_tag( no = vnos ? vnos[BM_elem_index_get(l_b->v)] : l_b->v->no; copy_v3_v3(r_lnos[BM_elem_index_get(l_b)], no); } - else { - /* Sharp edge, tag its verts as such. */ - BM_elem_flag_enable(e->v1, BM_ELEM_TAG); - BM_elem_flag_enable(e->v2, BM_ELEM_TAG); + } + } + + bm->elem_index_dirty &= ~BM_EDGE; +} + +/* Check whether gievn loop is part of an unknown-so-far cyclic smooth fan, or not. + * Needed because cyclic smooth fans have no obvious 'entry point', and yet we need to walk them once, and only once. */ +static bool bm_mesh_loop_check_cyclic_smooth_fan(BMLoop *l_curr) +{ + BMLoop *lfan_pivot_next = l_curr; + BMEdge *e_next = l_curr->e; + + BLI_assert(!BM_elem_flag_test(lfan_pivot_next, BM_ELEM_TAG)); + BM_elem_flag_enable(lfan_pivot_next, BM_ELEM_TAG); + + while (true) { + /* Much simpler than in sibling code with basic Mesh data! */ + lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot_next, &e_next); + + if (!lfan_pivot_next || !BM_elem_flag_test(e_next, BM_ELEM_TAG)) { + /* Sharp loop/edge, so not a cyclic smooth fan... */ + return false; + } + /* Smooth loop/edge... */ + else if (BM_elem_flag_test(lfan_pivot_next, BM_ELEM_TAG)) { + if (lfan_pivot_next == l_curr) { + /* We walked around a whole cyclic smooth fan without finding any already-processed loop, means we can + * use initial l_curr/l_prev edge as start for this smooth fan. */ + return true; } + /* ... already checked in some previous looping, we can abort. */ + return false; } else { - /* Sharp edge, tag its verts as such. */ - BM_elem_flag_enable(e->v1, BM_ELEM_TAG); - BM_elem_flag_enable(e->v2, BM_ELEM_TAG); + /* ... we can skip it in future, and keep checking the smooth fan. */ + BM_elem_flag_enable(lfan_pivot_next, BM_ELEM_TAG); } } - - bm->elem_index_dirty &= ~(BM_EDGE | BM_VERT); } /* BMesh version of BKE_mesh_normals_loop_split() in mesh_evaluate.c @@ -587,13 +605,11 @@ static void bm_mesh_loops_calc_normals( BLI_Stack *edge_vectors = NULL; { - char htype = BM_LOOP; + char htype = 0; if (vcos) { htype |= BM_VERT; } - if (fnos) { - htype |= BM_FACE; - } + /* Face/Loop indices are set inline below. */ BM_mesh_elem_index_ensure(bm, htype); } @@ -606,6 +622,21 @@ static void bm_mesh_loops_calc_normals( edge_vectors = BLI_stack_new(sizeof(float[3]), __func__); } + /* Clear all loops' tags (means none are to be skipped for now). */ + int index_face, index_loop = 0; + BM_ITER_MESH_INDEX (f_curr, &fiter, bm, BM_FACES_OF_MESH, index_face) { + BMLoop *l_curr, *l_first; + + BM_elem_index_set(f_curr, index_face); /* set_inline */ + + l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr); + do { + BM_elem_index_set(l_curr, index_loop++); /* set_inline */ + BM_elem_flag_disable(l_curr, BM_ELEM_TAG); + } while ((l_curr = l_curr->next) != l_first); + } + bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); + /* We now know edges that can be smoothed (they are tagged), and edges that will be hard (they aren't). * Now, time to generate the normals. */ @@ -614,16 +645,16 @@ static void bm_mesh_loops_calc_normals( l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr); do { + /* A smooth edge, we have to check for cyclic smooth fan case. + * If we find a new, never-processed cyclic smooth fan, we can do it now using that loop/edge as + * 'entry point', otherwise we can skip it. */ + /* Note: In theory, we could make bm_mesh_loop_check_cyclic_smooth_fan() store mlfan_pivot's in a stack, + * to avoid having to fan again around the vert during actual computation of clnor & clnorspace. + * However, this would complicate the code, add more memory usage, and BM_vert_step_fan_loop() + * is quite cheap in term of CPU cycles, so really think it's not worth it. */ if (BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && - (!r_lnors_spacearr || BM_elem_flag_test(l_curr->v, BM_ELEM_TAG))) + (BM_elem_flag_test(l_curr, BM_ELEM_TAG) || !bm_mesh_loop_check_cyclic_smooth_fan(l_curr))) { - /* A smooth edge, and we are not generating lnors_spacearr, or the related vertex is sharp. - * We skip it because it is either: - * - in the middle of a 'smooth fan' already computed (or that will be as soon as we hit - * one of its ends, i.e. one of its two sharp edges), or... - * - the related vertex is a "full smooth" one, in which case pre-populated normals from vertex - * are just fine! - */ } else if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) @@ -1481,23 +1512,6 @@ int BM_mesh_elem_count(BMesh *bm, const char htype) } } -/** - * Special case: Python uses custom-data layers to hold PyObject references. - * These have to be kept in-place, else the PyObject's we point to, wont point back to us. - * - * \note ``ele_src`` Is a duplicate, so we don't need to worry about getting in a feedback loop. - * - * \note If there are other customdata layers which need this functionality, it should be generalized. - * However #BM_mesh_remap is currently the only place where this is done. - */ -static void bm_mesh_remap_cd_update( - BMHeader *ele_dst, BMHeader *ele_src, - const int cd_elem_pyptr) -{ - void **pyptr_dst_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_dst), cd_elem_pyptr); - void **pyptr_src_p = BM_ELEM_CD_GET_VOID_P(((BMElem *)ele_src), cd_elem_pyptr); - *pyptr_dst_p = *pyptr_src_p; -} /** * Remaps the vertices, edges and/or faces of the bmesh as indicated by vert/edge/face_idx arrays @@ -1513,9 +1527,9 @@ static void bm_mesh_remap_cd_update( */ void BM_mesh_remap( BMesh *bm, - const unsigned int *vert_idx, - const unsigned int *edge_idx, - const unsigned int *face_idx) + const uint *vert_idx, + const uint *edge_idx, + const uint *face_idx) { /* Mapping old to new pointers. */ GHash *vptr_map = NULL, *eptr_map = NULL, *fptr_map = NULL; @@ -1538,7 +1552,9 @@ void BM_mesh_remap( if (vert_idx) { BMVert **verts_pool, *verts_copy, **vep; int i, totvert = bm->totvert; - const unsigned int *new_idx; + const uint *new_idx; + /* Special case: Python uses custom - data layers to hold PyObject references. + * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */ const int cd_vert_pyptr = CustomData_get_offset(&bm->vdata, CD_BM_ELEM_PYPTR); /* Init the old-to-new vert pointers mapping */ @@ -1547,9 +1563,14 @@ void BM_mesh_remap( /* Make a copy of all vertices. */ verts_pool = bm->vtable; verts_copy = MEM_mallocN(sizeof(BMVert) * totvert, "BM_mesh_remap verts copy"); + void **pyptrs = (cd_vert_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totvert, __func__) : NULL; for (i = totvert, ve = verts_copy + totvert - 1, vep = verts_pool + totvert - 1; i--; ve--, vep--) { *ve = **vep; /* printf("*vep: %p, verts_pool[%d]: %p\n", *vep, i, verts_pool[i]);*/ + if (cd_vert_pyptr != -1) { + void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)ve), cd_vert_pyptr); + pyptrs[i] = *pyptr; + } } /* Copy back verts to their new place, and update old2new pointers mapping. */ @@ -1562,20 +1583,26 @@ void BM_mesh_remap( /* printf("mapping vert from %d to %d (%p/%p to %p)\n", i, *new_idx, *vep, verts_pool[i], new_vep);*/ BLI_ghash_insert(vptr_map, *vep, new_vep); if (cd_vert_pyptr != -1) { - bm_mesh_remap_cd_update(&(*vep)->head, &new_vep->head, cd_vert_pyptr); + void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_vep), cd_vert_pyptr); + *pyptr = pyptrs[*new_idx]; } } bm->elem_index_dirty |= BM_VERT; bm->elem_table_dirty |= BM_VERT; MEM_freeN(verts_copy); + if (pyptrs) { + MEM_freeN(pyptrs); + } } /* Remap Edges */ if (edge_idx) { BMEdge **edges_pool, *edges_copy, **edp; int i, totedge = bm->totedge; - const unsigned int *new_idx; + const uint *new_idx; + /* Special case: Python uses custom - data layers to hold PyObject references. + * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */ const int cd_edge_pyptr = CustomData_get_offset(&bm->edata, CD_BM_ELEM_PYPTR); /* Init the old-to-new vert pointers mapping */ @@ -1584,8 +1611,13 @@ void BM_mesh_remap( /* Make a copy of all vertices. */ edges_pool = bm->etable; edges_copy = MEM_mallocN(sizeof(BMEdge) * totedge, "BM_mesh_remap edges copy"); + void **pyptrs = (cd_edge_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totedge, __func__) : NULL; for (i = totedge, ed = edges_copy + totedge - 1, edp = edges_pool + totedge - 1; i--; ed--, edp--) { *ed = **edp; + if (cd_edge_pyptr != -1) { + void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)ed), cd_edge_pyptr); + pyptrs[i] = *pyptr; + } } /* Copy back verts to their new place, and update old2new pointers mapping. */ @@ -1598,20 +1630,26 @@ void BM_mesh_remap( BLI_ghash_insert(eptr_map, *edp, new_edp); /* printf("mapping edge from %d to %d (%p/%p to %p)\n", i, *new_idx, *edp, edges_pool[i], new_edp);*/ if (cd_edge_pyptr != -1) { - bm_mesh_remap_cd_update(&(*edp)->head, &new_edp->head, cd_edge_pyptr); + void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_edp), cd_edge_pyptr); + *pyptr = pyptrs[*new_idx]; } } bm->elem_index_dirty |= BM_EDGE; bm->elem_table_dirty |= BM_EDGE; MEM_freeN(edges_copy); + if (pyptrs) { + MEM_freeN(pyptrs); + } } /* Remap Faces */ if (face_idx) { BMFace **faces_pool, *faces_copy, **fap; int i, totface = bm->totface; - const unsigned int *new_idx; + const uint *new_idx; + /* Special case: Python uses custom - data layers to hold PyObject references. + * These have to be kept in - place, else the PyObject's we point to, wont point back to us. */ const int cd_poly_pyptr = CustomData_get_offset(&bm->pdata, CD_BM_ELEM_PYPTR); /* Init the old-to-new vert pointers mapping */ @@ -1620,8 +1658,13 @@ void BM_mesh_remap( /* Make a copy of all vertices. */ faces_pool = bm->ftable; faces_copy = MEM_mallocN(sizeof(BMFace) * totface, "BM_mesh_remap faces copy"); + void **pyptrs = (cd_poly_pyptr != -1) ? MEM_mallocN(sizeof(void *) * totface, __func__) : NULL; for (i = totface, fa = faces_copy + totface - 1, fap = faces_pool + totface - 1; i--; fa--, fap--) { *fa = **fap; + if (cd_poly_pyptr != -1) { + void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)fa), cd_poly_pyptr); + pyptrs[i] = *pyptr; + } } /* Copy back verts to their new place, and update old2new pointers mapping. */ @@ -1633,7 +1676,8 @@ void BM_mesh_remap( *new_fap = *fa; BLI_ghash_insert(fptr_map, *fap, new_fap); if (cd_poly_pyptr != -1) { - bm_mesh_remap_cd_update(&(*fap)->head, &new_fap->head, cd_poly_pyptr); + void **pyptr = BM_ELEM_CD_GET_VOID_P(((BMElem *)new_fap), cd_poly_pyptr); + *pyptr = pyptrs[*new_idx]; } } @@ -1641,6 +1685,9 @@ void BM_mesh_remap( bm->elem_table_dirty |= BM_FACE; MEM_freeN(faces_copy); + if (pyptrs) { + MEM_freeN(pyptrs); + } } /* And now, fix all vertices/edges/faces/loops pointers! */ @@ -2008,4 +2055,4 @@ void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags) vpool_dst, epool_dst, NULL, fpool_dst); bm->use_toolflags = use_toolflags; -}
\ No newline at end of file +} diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h index 6a9540c3b60..01f11f6f942 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.h +++ b/source/blender/bmesh/intern/bmesh_mesh.h @@ -34,7 +34,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm); void BM_mesh_elem_toolflags_clear(BMesh *bm); struct BMeshCreateParams { - unsigned int use_toolflags : 1; + uint use_toolflags : 1; }; BMesh *BM_mesh_create( @@ -88,9 +88,9 @@ int BM_mesh_elem_count(BMesh *bm, const char htype); void BM_mesh_remap( BMesh *bm, - const unsigned int *vert_idx, - const unsigned int *edge_idx, - const unsigned int *face_idx); + const uint *vert_idx, + const uint *edge_idx, + const uint *face_idx); void BM_mesh_rebuild( BMesh *bm, const struct BMeshCreateParams *params, diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c index 998dbee67a4..e73d2f70dbe 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_conv.c +++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c @@ -101,42 +101,6 @@ /* XXX stupid hack: linker otherwise strips bmesh_strands_conv.c because it is not used inside bmesh */ void *__dummy_hack__ = &BM_strands_count_psys_keys; -/** - * Currently this is only used for Python scripts - * which may fail to keep matching UV/TexFace layers. - * - * \note This should only perform any changes in exceptional cases, - * if we need this to be faster we could inline #BM_data_layer_add and only - * call #update_data_blocks once at the end. - */ -void BM_mesh_cd_validate(BMesh *bm) -{ - int totlayer_mtex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); - int totlayer_uv = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV); - - if (LIKELY(totlayer_mtex == totlayer_uv)) { - /* pass */ - } - else if (totlayer_mtex < totlayer_uv) { - const int uv_index_first = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV); - do { - const char *from_name = bm->ldata.layers[uv_index_first + totlayer_mtex].name; - BM_data_layer_add_named(bm, &bm->pdata, CD_MTEXPOLY, from_name); - CustomData_set_layer_unique_name(&bm->pdata, totlayer_mtex); - } while (totlayer_uv != ++totlayer_mtex); - } - else if (totlayer_uv < totlayer_mtex) { - const int mtex_index_first = CustomData_get_layer_index(&bm->pdata, CD_MTEXPOLY); - do { - const char *from_name = bm->pdata.layers[mtex_index_first + totlayer_uv].name; - BM_data_layer_add_named(bm, &bm->ldata, CD_MLOOPUV, from_name); - CustomData_set_layer_unique_name(&bm->ldata, totlayer_uv); - } while (totlayer_mtex != ++totlayer_uv); - } - - BLI_assert(totlayer_mtex == totlayer_uv); -} - void BM_mesh_cd_flag_ensure(BMesh *bm, Mesh *mesh, const char cd_flag) { const char cd_flag_all = BM_mesh_cd_flag_from_bmesh(bm) | cd_flag; @@ -238,7 +202,7 @@ void BM_mesh_bm_from_me( BMEdge *e, **etable = NULL; BMFace *f; float (*keyco)[3] = NULL; - int totuv, totloops, i, j; + int totloops, i, j; CustomDataMask mask = CD_MASK_BMESH | params->cd_mask_extra; /* free custom data */ @@ -270,13 +234,6 @@ void BM_mesh_bm_from_me( CustomData_copy(&me->ldata, &bm->ldata, mask, CD_CALLOC, 0); CustomData_copy(&me->pdata, &bm->pdata, mask, CD_CALLOC, 0); - /* make sure uv layer names are consisten */ - totuv = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY); - for (i = 0; i < totuv; i++) { - int li = CustomData_get_layer_index_n(&bm->pdata, CD_MTEXPOLY, i); - CustomData_set_layer_name(&bm->ldata, CD_MLOOPUV, i, bm->pdata.layers[li].name); - } - if ((params->active_shapekey != 0) && (me->key != NULL)) { actkey = BLI_findlink(&me->key->block, params->active_shapekey - 1); } @@ -949,6 +906,10 @@ void BM_mesh_bm_to_me( /* propagate edited basis offsets to other shapes */ if (apply_offset) { add_v3_v3(fp, *ofs_pt++); + /* Apply back new coordinates of offsetted shapekeys into BMesh. + * Otherwise, in case we call again BM_mesh_bm_to_me on same BMesh, we'll apply diff from previous + * call to BM_mesh_bm_to_me, to shapekey values from *original creation of the BMesh*. See T50524. */ + copy_v3_v3(BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset), fp); } fp += 3; diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.h b/source/blender/bmesh/intern/bmesh_mesh_conv.h index 892b9bef486..e69f3d6c489 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_conv.h +++ b/source/blender/bmesh/intern/bmesh_mesh_conv.h @@ -44,11 +44,11 @@ char BM_mesh_cd_flag_from_bmesh(BMesh *bm); struct BMeshFromMeshParams { - unsigned int calc_face_normal : 1; + uint calc_face_normal : 1; /* add a vertex CD_SHAPE_KEYINDEX layer */ - unsigned int add_key_index : 1; + uint add_key_index : 1; /* set vertex coordinates from the shapekey */ - unsigned int use_shapekey : 1; + uint use_shapekey : 1; /* define the active shape key (index + 1) */ int active_shapekey; int64_t cd_mask_extra; @@ -59,7 +59,7 @@ void BM_mesh_bm_from_me( ATTR_NONNULL(1, 3); struct BMeshToMeshParams { - unsigned int calc_tessface : 1; + uint calc_tessface : 1; int64_t cd_mask_extra; }; void BM_mesh_bm_to_me( diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c index 478194735f3..7c9ebc800a3 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_validate.c +++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c @@ -64,7 +64,7 @@ bool BM_mesh_validate(BMesh *bm) int i, j; - errtot = -1; + errtot = -1; /* 'ERRMSG' next line will set at zero */ fprintf(stderr, "\n"); ERRMSG("This is a debugging function and not intended for general use, running slow test!"); @@ -187,15 +187,22 @@ bool BM_mesh_validate(BMesh *bm) } while ((l_iter = l_iter->next) != l_first); if (j != f->len) { - ERRMSG("face %d: has length if %d but should be %d", i, f->len, j); + ERRMSG("face %d: has length of %d but should be %d", i, f->len, j); } + + /* leave elements un-tagged, not essential but nice to avoid unintended dirty tag use later. */ + do { + BM_elem_flag_disable(l_iter, BM_ELEM_INTERNAL_TAG); + BM_elem_flag_disable(l_iter->v, BM_ELEM_INTERNAL_TAG); + BM_elem_flag_disable(l_iter->e, BM_ELEM_INTERNAL_TAG); + } while ((l_iter = l_iter->next) != l_first); } BLI_edgehash_free(edge_hash, NULL); + const bool is_valid = (errtot == 0); ERRMSG("Finished - errors %d", errtot); - - return (errtot == 0); + return is_valid; } diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index d3c847de64e..1cd51528e06 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -104,7 +104,6 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v) */ bool BM_disk_dissolve(BMesh *bm, BMVert *v) { - BMFace *f, *f2; BMEdge *e, *keepedge = NULL, *baseedge = NULL; int len = 0; @@ -132,16 +131,17 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) #if 0 /* handle specific case for three-valence. solve it by * increasing valence to four. this may be hackish. . */ - BMLoop *loop = e->l; - if (loop->v == v) loop = loop->next; - if (!BM_face_split(bm, loop->f, v, loop->v, NULL, NULL, false)) + BMLoop *l_a = BM_face_vert_share_loop(e->l->f, v); + BMLoop *l_b = (e->l->v == v) ? e->l->next : e->l; + + if (!BM_face_split(bm, e->l->f, l_a, l_b, NULL, NULL, false)) return false; if (!BM_disk_dissolve(bm, v)) { return false; } #else - if (UNLIKELY(!BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true))) { + if (UNLIKELY(!BM_faces_join_pair(bm, e->l, e->l->radial_next, true))) { return false; } else if (UNLIKELY(!BM_vert_collapse_faces(bm, v->e, v, 1.0, true, false, true))) { @@ -159,11 +159,10 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) } /* handle two-valence */ - f = e->l->f; - f2 = e->l->radial_next->f; - - if (f != f2 && !BM_faces_join_pair(bm, f, f2, e, true)) { - return false; + if (e->l != e->l->radial_next) { + if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) { + return false; + } } return true; @@ -176,9 +175,9 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) done = true; e = v->e; do { - f = NULL; + BMFace *f = NULL; if (BM_edge_is_manifold(e) && (e != baseedge) && (e != keepedge)) { - f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true); + f = BM_faces_join_pair(bm, e->l, e->l->radial_next, true); /* return if couldn't join faces in manifold * conditions */ /* !disabled for testing why bad things happen */ @@ -204,12 +203,9 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) if (e->l) { /* get remaining two faces */ - f = e->l->f; - f2 = e->l->radial_next->f; - - if (f != f2) { + if (e->l != e->l->radial_next) { /* join two remaining faces */ - if (!BM_faces_join_pair(bm, f, f2, e, true)) { + if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) { return false; } } @@ -224,30 +220,24 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) * * Joins two adjacent faces together. * - * Because this method calls to #BM_faces_join to do its work, if a pair - * of faces share multiple edges, the pair of faces will be joined at - * every edge (not just edge \a e). This part of the functionality might need - * to be reconsidered. + * \note This method calls to #BM_faces_join to do its work. + * This means connected edges which also share the two faces will be joined. * * If the windings do not match the winding of the new face will follow - * \a f_a's winding (i.e. \a f_b will be reversed before the join). + * \a l_a's winding (i.e. \a l_b will be reversed before the join). * - * \return pointer to the combined face + * \return The combined face or NULL on failure. */ -BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const bool do_del) +BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del) { - BMFace *faces[2] = {f_a, f_b}; - - BMLoop *l_a = BM_face_edge_share_loop(f_a, e); - BMLoop *l_b = BM_face_edge_share_loop(f_b, e); - - BLI_assert(l_a && l_b); + BLI_assert((l_a != l_b) && (l_a->e == l_b->e)); if (l_a->v == l_b->v) { const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); - bmesh_loop_reverse(bm, f_b, cd_loop_mdisp_offset, true); + bmesh_kernel_loop_reverse(bm, l_b->f, cd_loop_mdisp_offset, true); } - + + BMFace *faces[2] = {l_a->f, l_b->f}; return BM_faces_join(bm, faces, 2, do_del); } @@ -298,9 +288,9 @@ BMFace *BM_face_split( } #ifdef USE_BMESH_HOLES - f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, NULL, example, no_double); + f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, r_l, NULL, example, no_double); #else - f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, example, no_double); + f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, r_l, example, no_double); #endif if (f_new) { @@ -356,7 +346,7 @@ BMFace *BM_face_split_n( BMLoop **r_l, BMEdge *example) { BMFace *f_new, *f_tmp; - BMLoop *l_dummy; + BMLoop *l_new; BMEdge *e, *e_new; BMVert *v_new; // BMVert *v_a = l_a->v; /* UNUSED */ @@ -378,24 +368,21 @@ BMFace *BM_face_split_n( } f_tmp = BM_face_copy(bm, bm, f, true, true); - - if (!r_l) - r_l = &l_dummy; #ifdef USE_BMESH_HOLES - f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, NULL, example, false); + f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, &l_new, NULL, example, false); #else - f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, example, false); + f_new = bmesh_kernel_split_face_make_edge(bm, f, l_a, l_b, &l_new, example, false); #endif - /* bmesh_sfme returns in r_l a Loop for f_new going from v_a to v_b. - * The radial_next is for f and goes from v_b to v_a */ + /* bmesh_kernel_split_face_make_edge returns in 'l_new' a Loop for f_new going from 'v_a' to 'v_b'. + * The radial_next is for 'f' and goes from 'v_b' to 'v_a' */ if (f_new) { - e = (*r_l)->e; + e = l_new->e; for (i = 0; i < n; i++) { - v_new = bmesh_semv(bm, v_b, e, &e_new); + v_new = bmesh_kernel_split_edge_make_vert(bm, v_b, e, &e_new); BLI_assert(v_new != NULL); - /* bmesh_semv returns in e_new the edge going from v_new to tv */ + /* bmesh_kernel_split_edge_make_vert returns in 'e_new' the edge going from 'v_new' to 'v_b' */ copy_v3_v3(v_new->co, cos[i]); /* interpolate the loop data for the loops with (v == v_new), using orig face */ @@ -415,6 +402,10 @@ BMFace *BM_face_split_n( BM_face_verts_kill(bm, f_tmp); + if (r_l) { + *r_l = l_new; + } + return f_new; } @@ -516,7 +507,7 @@ BMEdge *BM_vert_collapse_faces( /* single face or no faces */ /* same as BM_vert_collapse_edge() however we already * have vars to perform this operation so don't call. */ - e_new = bmesh_jekv(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces); + e_new = bmesh_kernel_join_edge_kill_vert(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces); /* e_new = BM_edge_exists(tv, tv2); */ /* same as return above */ } @@ -551,7 +542,7 @@ BMEdge *BM_vert_collapse_edge( BMVert *tv2 = BM_edge_other_vert(e2, v_kill); if (tv2) { /* only action, other calls here only get the edge to return */ - e_new = bmesh_jekv(bm, e_kill, v_kill, do_del); + e_new = bmesh_kernel_join_edge_kill_vert(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces); } } } @@ -573,7 +564,7 @@ BMVert *BM_edge_collapse( BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces) { - return bmesh_jvke(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces); + return bmesh_kernel_join_vert_kill_edge(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces); } /** @@ -598,18 +589,13 @@ BMVert *BM_edge_collapse( BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) { BMVert *v_new, *v_other; + BMEdge *e_new; BMFace **oldfaces = NULL; - BMEdge *e_dummy; BLI_array_staticdeclare(oldfaces, 32); const int cd_loop_mdisp_offset = BM_edge_is_wire(e) ? -1 : CustomData_get_offset(&bm->ldata, CD_MDISPS); BLI_assert(BM_vert_in_edge(e, v) == true); - /* we need this for handling multi-res */ - if (!r_e) { - r_e = &e_dummy; - } - /* do we have a multi-res layer? */ if (cd_loop_mdisp_offset != -1) { BMLoop *l; @@ -630,17 +616,20 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) } v_other = BM_edge_other_vert(e, v); - v_new = bmesh_semv(bm, v, e, r_e); + v_new = bmesh_kernel_split_edge_make_vert(bm, v, e, &e_new); + if (r_e != NULL) { + *r_e = e_new; + } BLI_assert(v_new != NULL); - BLI_assert(BM_vert_in_edge(*r_e, v) && BM_vert_in_edge(*r_e, v_new)); + BLI_assert(BM_vert_in_edge(e_new, v) && BM_vert_in_edge(e_new, v_new)); BLI_assert(BM_vert_in_edge(e, v_new) && BM_vert_in_edge(e, v_other)); sub_v3_v3v3(v_new->co, v_other->co, v->co); madd_v3_v3v3fl(v_new->co, v->co, v_new->co, fac); - (*r_e)->head.hflag = e->head.hflag; - BM_elem_attrs_copy(bm, bm, e, *r_e); + e_new->head.hflag = e->head.hflag; + BM_elem_attrs_copy(bm, bm, e, e_new); /* v->v_new->v2 */ BM_data_interp_face_vert_edge(bm, v_other, v, v_new, e, fac); @@ -656,7 +645,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) BM_face_calc_center_mean(oldfaces[i], f_center_old); for (j = 0; j < 2; j++) { - BMEdge *e1 = j ? *r_e : e; + BMEdge *e1 = j ? e_new : e; BMLoop *l; l = e1->l; @@ -689,7 +678,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) /* fix boundaries a bit, doesn't work too well quite yet */ #if 0 for (j = 0; j < 2; j++) { - BMEdge *e1 = j ? *r_e : e; + BMEdge *e1 = j ? e_new : e; BMLoop *l, *l2; l = e1->l; @@ -991,6 +980,7 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f BMLoop *l1, *l2; BMFace *f; BMEdge *e_new = NULL; + char f_active_prev = 0; char f_hflag_prev_1; char f_hflag_prev_2; @@ -1041,8 +1031,18 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f f_hflag_prev_1 = l1->f->head.hflag; f_hflag_prev_2 = l2->f->head.hflag; + /* maintain active face */ + if (bm->act_face == l1->f) { + f_active_prev = 1; + } + else if (bm->act_face == l2->f) { + f_active_prev = 2; + } + + const bool is_flipped = !BM_edge_is_contiguous(e); + /* don't delete the edge, manually remove the edge after so we can copy its attributes */ - f = BM_faces_join_pair(bm, l1->f, l2->f, e, true); + f = BM_faces_join_pair(bm, BM_face_edge_share_loop(l1->f, e), BM_face_edge_share_loop(l2->f, e), true); if (f == NULL) { return NULL; @@ -1062,6 +1062,22 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f if (BM_edge_face_pair(e_new, &fa, &fb)) { fa->head.hflag = f_hflag_prev_1; fb->head.hflag = f_hflag_prev_2; + + if (f_active_prev == 1) { + bm->act_face = fa; + } + else if (f_active_prev == 2) { + bm->act_face = fb; + } + + if (is_flipped) { + BM_face_normal_flip(bm, fb); + + if (ccw) { + /* needed otherwise ccw toggles direction */ + e_new->l = e_new->l->radial_next; + } + } } } else { @@ -1074,23 +1090,18 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f /** * \brief Rip a single face from a vertex fan */ -BMVert *BM_face_vert_separate(BMesh *bm, BMFace *sf, BMVert *sv) +BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep) { - return bmesh_urmv(bm, sf, sv); + return bmesh_kernel_unglue_region_make_vert(bm, l_sep); } -/** - * \brief Rip a single face from a vertex fan - * - * \note same as #BM_face_vert_separate but faster (avoids a loop lookup) - */ -BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *sl) +BMVert *BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep) { - return bmesh_urmv_loop(bm, sl); + return bmesh_kernel_unglue_region_make_vert_multi_isolated(bm, l_sep); } -BMVert *BM_face_loop_separate_multi( - BMesh *bm, BMLoop **larr, int larr_len) +BMVert *BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len) { - return bmesh_urmv_loop_multi(bm, larr, larr_len); + return bmesh_kernel_unglue_region_make_vert_multi(bm, larr, larr_len); } + diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h index 2e557e3b606..330a714418d 100644 --- a/source/blender/bmesh/intern/bmesh_mods.h +++ b/source/blender/bmesh/intern/bmesh_mods.h @@ -31,7 +31,7 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v); bool BM_disk_dissolve(BMesh *bm, BMVert *v); -BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, const bool do_del); +BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del); /** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */ @@ -86,9 +86,8 @@ enum { }; -BMVert *BM_face_vert_separate(BMesh *bm, BMFace *sf, BMVert *sv); -BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *sl); -BMVert *BM_face_loop_separate_multi( - BMesh *bm, BMLoop **larr, int larr_len); +BMVert *BM_face_loop_separate(BMesh *bm, BMLoop *l_sep); +BMVert *BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep); +BMVert *BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len); #endif /* __BMESH_MODS_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 79c2f80d6aa..a55df234264 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1037,7 +1037,7 @@ static BMOpDefine bmo_extrude_face_region_def = { /* slots_in */ {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* edges and faces */ {"edges_exclude", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_EMPTY}}, - {"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry */ + {"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry (requires ``geom`` to include edges). */ {"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */ {{'\0'}}, }, @@ -1284,7 +1284,7 @@ static BMOpDefine bmo_bisect_plane_def = { {"clear_inner", BMO_OP_SLOT_BOOL}, /* when enabled. remove all geometry on the negative side of the plane */ {{'\0'}}, }, - {{"geom_cut.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE}}, /* output new geometry from the cut */ + {{"geom_cut.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE}}, /* output geometry aligned with the plane (new and existing) */ {"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input and output geometry (result of cut) */ {{'\0'}}}, bmo_bisect_plane_exec, @@ -1635,7 +1635,8 @@ static BMOpDefine bmo_create_icosphere_def = { static BMOpDefine bmo_create_monkey_def = { "create_monkey", /* slots_in */ - {{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */ + {{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */ + {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */ {{'\0'}}, }, /* slots_out */ @@ -1740,6 +1741,8 @@ static BMOpDefine bmo_bevel_def = { }, /* slots_out */ {{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */ + {"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* output edges */ + {"verts.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* output verts */ {{'\0'}}, }, @@ -1911,7 +1914,6 @@ static BMOpDefine bmo_wireframe_def = { {"use_even_offset", BMO_OP_SLOT_BOOL}, {"use_crease", BMO_OP_SLOT_BOOL}, {"crease_weight", BMO_OP_SLOT_FLT}, - {"thickness", BMO_OP_SLOT_FLT}, {"use_relative_offset", BMO_OP_SLOT_BOOL}, {"material_offset", BMO_OP_SLOT_INT}, {{'\0'}}, diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c index 706a7f74ed2..44445aae25a 100644 --- a/source/blender/bmesh/intern/bmesh_operators.c +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -128,7 +128,7 @@ void BMO_pop(BMesh *bm) static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args) { BMOpSlot *slot; - unsigned int i; + uint i; for (i = 0; slot_types[i].type; i++) { slot = &slot_args[i]; slot->slot_name = slot_types[i].name; @@ -149,7 +149,7 @@ static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args static void bmo_op_slots_free(const BMOSlotType *slot_types, BMOpSlot *slot_args) { BMOpSlot *slot; - unsigned int i; + uint i; for (i = 0; slot_types[i].type; i++) { slot = &slot_args[i]; switch (slot->slot_type) { @@ -311,9 +311,9 @@ void _bmo_slot_copy( } else { /* check types */ - const unsigned int tot = slot_src->len; - unsigned int i; - unsigned int out = 0; + const uint tot = slot_src->len; + uint i; + uint out = 0; BMElem **ele_src = (BMElem **)slot_src->data.buf; for (i = 0; i < tot; i++, ele_src++) { if ((*ele_src)->head.htype & dst_elem_flag) { @@ -333,8 +333,8 @@ void _bmo_slot_copy( } else { /* only copy compatible elements */ - const unsigned int tot = slot_src->len; - unsigned int i; + const uint tot = slot_src->len; + uint i; BMElem **ele_src = (BMElem **)slot_src->data.buf; BMElem **ele_dst = (BMElem **)slot_dst->data.buf; for (i = 0; i < tot; i++, ele_src++) { @@ -1639,8 +1639,8 @@ static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], cons int BMO_opcode_from_opname(const char *opname) { - const unsigned int tot = bmo_opdefines_total; - unsigned int i; + const uint tot = bmo_opdefines_total; + uint i; for (i = 0; i < tot; i++) { if (STREQ(bmo_opdefines[i]->opname, opname)) { return i; diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h index 0a4fb1d56a4..80b57eb3565 100644 --- a/source/blender/bmesh/intern/bmesh_operators.h +++ b/source/blender/bmesh/intern/bmesh_operators.h @@ -77,13 +77,13 @@ enum { /* similar face selection slot values */ enum { SIMFACE_MATERIAL = 201, - SIMFACE_IMAGE, SIMFACE_AREA, SIMFACE_SIDES, SIMFACE_PERIMETER, SIMFACE_NORMAL, SIMFACE_COPLANAR, SIMFACE_SMOOTH, + SIMFACE_FACEMAP, #ifdef WITH_FREESTYLE SIMFACE_FREESTYLE #endif @@ -141,12 +141,19 @@ void BM_mesh_esubdivide( const short use_only_quads, const int seed); -void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsigned int y_segments, const short oflag); -void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag); -void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, const short oflag); +void BM_mesh_calc_uvs_grid( + BMesh *bm, const uint x_segments, const uint y_segments, + const short oflag, const int cd_loop_uv_offset); +void BM_mesh_calc_uvs_sphere( + BMesh *bm, + const short oflag, const int cd_loop_uv_offset); +void BM_mesh_calc_uvs_circle( + BMesh *bm, float mat[4][4], const float radius, + const short oflag, const int cd_loop_uv_offset); void BM_mesh_calc_uvs_cone( BMesh *bm, float mat[4][4], - const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, const short oflag); + const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, + const short oflag, const int cd_loop_uv_offset); void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag); #include "intern/bmesh_operator_api_inline.h" diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index c500d7b9ec2..a4621b45fe6 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -132,7 +132,7 @@ static void bm_face_calc_poly_center_mean_vertex_cos( */ void BM_face_calc_tessellation( const BMFace *f, const bool use_fixed_quad, - BMLoop **r_loops, unsigned int (*r_index)[3]) + BMLoop **r_loops, uint (*r_index)[3]) { BMLoop *l_first = BM_FACE_FIRST_LOOP(f); BMLoop *l_iter; @@ -196,7 +196,7 @@ void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]) * but without this we can't be sure the point is inside a concave face. */ const int tottri = f->len - 2; BMLoop **loops = BLI_array_alloca(loops, f->len); - unsigned int (*index)[3] = BLI_array_alloca(index, tottri); + uint (*index)[3] = BLI_array_alloca(index, tottri); int j; int j_best = 0; /* use as fallback when unset */ float area_best = -1.0f; @@ -225,24 +225,16 @@ void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]) */ float BM_face_calc_area(const BMFace *f) { + /* inline 'area_poly_v3' logic, avoid creating a temp array */ const BMLoop *l_iter, *l_first; - float (*verts)[3] = BLI_array_alloca(verts, f->len); - float area; - unsigned int i = 0; + float n[3]; + zero_v3(n); l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - copy_v3_v3(verts[i++], l_iter->v->co); + add_newell_cross_v3_v3v3(n, l_iter->v->co, l_iter->next->v->co); } while ((l_iter = l_iter->next) != l_first); - - if (f->len == 3) { - area = area_tri_v3(verts[0], verts[1], verts[2]); - } - else { - area = area_poly_v3((const float (*)[3])verts, f->len); - } - - return area; + return len_v3(n) * 0.5f; } /** @@ -583,11 +575,11 @@ void BM_face_calc_center_mean_weighted(const BMFace *f, float r_cent[3]) * Rotates a polygon so that it's * normal is pointing towards the mesh Z axis */ -void poly_rotate_plane(const float normal[3], float (*verts)[3], const unsigned int nverts) +void poly_rotate_plane(const float normal[3], float (*verts)[3], const uint nverts) { float mat[3][3]; float co[3]; - unsigned int i; + uint i; co[2] = 0.0f; @@ -852,7 +844,7 @@ void BM_face_normal_flip_ex( BMesh *bm, BMFace *f, const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip) { - bmesh_loop_reverse(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip); + bmesh_kernel_loop_reverse(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip); negate_v3(f->no); } @@ -949,7 +941,7 @@ void BM_face_triangulate( { BMLoop **loops = BLI_array_alloca(loops, f->len); - unsigned int (*tris)[3] = BLI_array_alloca(tris, f->len); + uint (*tris)[3] = BLI_array_alloca(tris, f->len); const int totfilltri = f->len - 2; const int last_tri = f->len - 3; int i; @@ -1433,7 +1425,7 @@ void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptri float axis_mat[3][3]; float (*projverts)[2]; - unsigned int (*tris)[3]; + uint (*tris)[3]; const int totfilltri = efa->len - 2; @@ -1459,7 +1451,7 @@ void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptri for (j = 0; j < totfilltri; j++) { BMLoop **l_ptr = looptris[i++]; - unsigned int *tri = tris[j]; + uint *tri = tris[j]; l_ptr[0] = l_arr[tri[0]]; l_ptr[1] = l_arr[tri[1]]; diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h index 1e50a504875..d944f3a8bc5 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.h +++ b/source/blender/bmesh/intern/bmesh_polygon.h @@ -36,7 +36,7 @@ void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptr void BM_face_calc_tessellation( const BMFace *f, const bool use_fixed_quad, - BMLoop **r_loops, unsigned int (*r_index)[3]); + BMLoop **r_loops, uint (*r_index)[3]); void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]); float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL(); float BM_face_calc_normal_vcos( diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index 5ee0e904a33..e515f9af63f 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -62,15 +62,16 @@ #define EDGE_NET _FLAG_WALK /* tag verts we've visit */ #define VERT_VISIT _FLAG_WALK +#define VERT_IN_QUEUE _FLAG_WALK_ALT struct VertOrder { float angle; BMVert *v; }; -static unsigned int bm_edge_flagged_radial_count(BMEdge *e) +static uint bm_edge_flagged_radial_count(BMEdge *e) { - unsigned int count = 0; + uint count = 0; BMLoop *l; if ((l = e->l)) { @@ -133,7 +134,7 @@ static bool bm_face_split_edgenet_find_loop_pair( e = e_first = v_init->e; do { if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) { - const unsigned int count = bm_edge_flagged_radial_count(e); + const uint count = bm_edge_flagged_radial_count(e); if (count == 1) { BLI_SMALLSTACK_PUSH(edges_boundary, e); edges_boundary_len++; @@ -161,7 +162,7 @@ static bool bm_face_split_edgenet_find_loop_pair( e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary); if (edges_boundary_len > 2) { - BLI_SMALLSTACK_SWAP(edges_search, edges_wire); + BLI_SMALLSTACK_SWAP(edges_search, edges_boundary); } } else { @@ -238,7 +239,7 @@ static bool bm_face_split_edgenet_find_loop_pair_exists( e = e_first = v_init->e; do { if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) { - const unsigned int count = bm_edge_flagged_radial_count(e); + const uint count = bm_edge_flagged_radial_count(e); if (count == 1) { edges_boundary_len++; } @@ -274,7 +275,7 @@ static bool bm_face_split_edgenet_find_loop_pair_exists( static bool bm_face_split_edgenet_find_loop_walk( BMVert *v_init, const float face_normal[3], /* cache to avoid realloc every time */ - struct VertOrder *edge_order, const unsigned int edge_order_len, + struct VertOrder *edge_order, const uint edge_order_len, BMEdge *e_pair[2]) { /* fast-path for the common case (avoid push-pop). @@ -381,7 +382,7 @@ walk_nofork: /* sort by angle if needed */ if (STACK_SIZE(edge_order) > 1) { - unsigned int j; + uint j; BMVert *v_prev = BM_edge_other_vert(v->e, v); for (j = 0; j < STACK_SIZE(edge_order); j++) { @@ -420,7 +421,7 @@ finally: static bool bm_face_split_edgenet_find_loop( BMVert *v_init, const float face_normal[3], float face_normal_matrix[3][3], /* cache to avoid realloc every time */ - struct VertOrder *edge_order, const unsigned int edge_order_len, + struct VertOrder *edge_order, const uint edge_order_len, BMVert **r_face_verts, int *r_face_verts_len) { BMEdge *e_pair[2]; @@ -434,7 +435,7 @@ static bool bm_face_split_edgenet_find_loop( (bm_edge_flagged_radial_count(e_pair[1]) == 1)); if (bm_face_split_edgenet_find_loop_walk(v_init, face_normal, edge_order, edge_order_len, e_pair)) { - unsigned int i = 0; + uint i = 0; r_face_verts[i++] = v_init; v = BM_edge_other_vert(e_pair[1], v_init); @@ -474,7 +475,7 @@ bool BM_face_split_edgenet( int i; struct VertOrder *edge_order; - const unsigned int edge_order_len = edge_net_len + 2; + const uint edge_order_len = edge_net_len + 2; BMVert *v; @@ -512,13 +513,21 @@ bool BM_face_split_edgenet( } while ((l_iter = l_iter->next) != l_first); #endif + /* Note: 'VERT_IN_QUEUE' is often not needed at all, + * however in rare cases verts are added multiple times to the queue, + * that on it's own is harmless but in _very_ rare cases, + * the queue will overflow its maximum size, + * so we better be strict about this! see: T51539 */ for (i = 0; i < edge_net_len; i++) { BM_ELEM_API_FLAG_ENABLE(edge_net[i], EDGE_NET); + BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v1, VERT_IN_QUEUE); + BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v2, VERT_IN_QUEUE); } l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET); + BM_ELEM_API_FLAG_DISABLE(l_iter->v, VERT_IN_QUEUE); } while ((l_iter = l_iter->next) != l_first); float face_normal_matrix[3][3]; @@ -527,8 +536,10 @@ bool BM_face_split_edgenet( /* any vert can be used to begin with */ STACK_PUSH(vert_queue, l_first->v); + BM_ELEM_API_FLAG_ENABLE(l_first->v, VERT_IN_QUEUE); while ((v = STACK_POP(vert_queue))) { + BM_ELEM_API_FLAG_DISABLE(v, VERT_IN_QUEUE); if (bm_face_split_edgenet_find_loop( v, f->no, face_normal_matrix, edge_order, edge_order_len, face_verts, &face_verts_len)) @@ -558,8 +569,12 @@ bool BM_face_split_edgenet( * (verts between boundary and manifold edges) */ l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); do { - if (bm_face_split_edgenet_find_loop_pair_exists(l_iter->v)) { + /* Avoid adding to queue multiple times (not common but happens). */ + if (!BM_ELEM_API_FLAG_TEST(l_iter->v, VERT_IN_QUEUE) && + bm_face_split_edgenet_find_loop_pair_exists(l_iter->v)) + { STACK_PUSH(vert_queue, l_iter->v); + BM_ELEM_API_FLAG_ENABLE(l_iter->v, VERT_IN_QUEUE); } } while ((l_iter = l_iter->next) != l_first); } @@ -721,13 +736,13 @@ BLI_INLINE bool edge_isect_verts_point_2d( */ struct EdgeGroupIsland { LinkNode edge_links; /* keep first */ - unsigned int vert_len, edge_len; + uint vert_len, edge_len; /* Set the following vars once we have >1 groups */ /* when when an edge in a previous group connects to this one, * so theres no need to create one pointing back. */ - unsigned int has_prev_edge : 1; + uint has_prev_edge : 1; /* verts in the group which has the lowest & highest values, * the lower vertex is connected to the first edge */ @@ -758,7 +773,7 @@ struct Edges_VertVert_BVHTreeTest { BMVert *v_origin; BMVert *v_other; - const unsigned int *vert_range; + const uint *vert_range; }; struct Edges_VertRay_BVHTreeTest { @@ -766,7 +781,7 @@ struct Edges_VertRay_BVHTreeTest { BMVert *v_origin; - const unsigned int *vert_range; + const uint *vert_range; }; static void bvhtree_test_edges_isect_2d_vert_cb( @@ -831,12 +846,12 @@ static void bvhtree_test_edges_isect_2d_ray_cb( struct EdgeGroup_FindConnection_Args { BVHTree *bvhtree; BMEdge **edge_arr; - unsigned int edge_arr_len; + uint edge_arr_len; BMEdge **edge_arr_new; - unsigned int edge_arr_new_len; + uint edge_arr_new_len; - const unsigned int *vert_range; + const uint *vert_range; }; static BMEdge *test_edges_isect_2d_vert( @@ -869,7 +884,7 @@ static BMEdge *test_edges_isect_2d_vert( /* check existing connections (no spatial optimization here since we're continually adding). */ if (LIKELY(index == -1)) { float t_best = 1.0f; - for (unsigned int i = 0; i < args->edge_arr_new_len; i++) { + for (uint i = 0; i < args->edge_arr_new_len; i++) { float co_isect[2]; if (UNLIKELY(edge_isect_verts_point_2d(args->edge_arr_new[i], v_origin, v_other, co_isect))) { const float t_test = line_point_factor_v2(co_isect, v_origin->co, v_other->co); @@ -914,7 +929,7 @@ static BMEdge *test_edges_isect_2d_ray( /* check existing connections (no spatial optimization here since we're continually adding). */ if (LIKELY(index != -1)) { - for (unsigned int i = 0; i < args->edge_arr_new_len; i++) { + for (uint i = 0; i < args->edge_arr_new_len; i++) { BMEdge *e = args->edge_arr_new[i]; float dist_new; if (isect_ray_seg_v2(v_origin->co, dir, e->v1->co, e->v2->co, &dist_new, NULL)) { @@ -1031,7 +1046,7 @@ static BMVert *bm_face_split_edgenet_partial_connect(BMesh *bm, BMVert *v_delimi /* initial check - see if we have 3+ flagged edges attached to 'v_delimit' * if not, we can early exit */ LinkNode *e_delimit_list = NULL; - unsigned int e_delimit_list_len = 0; + uint e_delimit_list_len = 0; #define EDGE_NOT_IN_STACK BM_ELEM_INTERNAL_TAG #define VERT_NOT_IN_STACK BM_ELEM_INTERNAL_TAG @@ -1169,10 +1184,10 @@ static bool bm_vert_partial_connect_check_overlap( */ bool BM_face_split_edgenet_connect_islands( BMesh *bm, - BMFace *f, BMEdge **edge_net_init, const unsigned int edge_net_init_len, + BMFace *f, BMEdge **edge_net_init, const uint edge_net_init_len, bool use_partial_connect, MemArena *mem_arena, - BMEdge ***r_edge_net_new, unsigned int *r_edge_net_new_len) + BMEdge ***r_edge_net_new, uint *r_edge_net_new_len) { /* -------------------------------------------------------------------- */ /* This function has 2 main parts. @@ -1186,7 +1201,7 @@ bool BM_face_split_edgenet_connect_islands( * (avoid thrashing the area when the initial check isn't so intensive on the stack). */ - const unsigned int edge_arr_len = (unsigned int)edge_net_init_len + (unsigned int)f->len; + const uint edge_arr_len = (uint)edge_net_init_len + (uint)f->len; BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len); bool ok = false; @@ -1197,7 +1212,7 @@ bool BM_face_split_edgenet_connect_islands( #define VERT_NOT_IN_STACK BM_ELEM_INTERNAL_TAG { - unsigned int i = edge_net_init_len; + uint i = edge_net_init_len; BMLoop *l_iter, *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { @@ -1206,7 +1221,7 @@ bool BM_face_split_edgenet_connect_islands( BLI_assert(i == edge_arr_len); } - for (unsigned int i = 0; i < edge_arr_len; i++) { + for (uint i = 0; i < edge_arr_len; i++) { BM_elem_flag_enable(edge_arr[i], EDGE_NOT_IN_STACK); BM_elem_flag_enable(edge_arr[i]->v1, VERT_NOT_IN_STACK); BM_elem_flag_enable(edge_arr[i]->v2, VERT_NOT_IN_STACK); @@ -1224,12 +1239,12 @@ bool BM_face_split_edgenet_connect_islands( struct { struct TempVertPair *list; - unsigned int len; + uint len; int *remap; /* temp -> orig mapping */ } temp_vert_pairs = {NULL}; if (use_partial_connect) { - for (unsigned int i = 0; i < edge_net_init_len; i++) { + for (uint i = 0; i < edge_net_init_len; i++) { for (unsigned j = 0; j < 2; j++) { BMVert *v_delimit = (&edge_arr[i]->v1)[j]; BMVert *v_other; @@ -1254,19 +1269,19 @@ bool BM_face_split_edgenet_connect_islands( - unsigned int group_arr_len = 0; + uint group_arr_len = 0; LinkNode *group_head = NULL; { /* scan 'edge_arr' backwards so the outer face boundary is handled first * (since its likely to be the largest) */ - unsigned int edge_index = (edge_arr_len - 1); - unsigned int edge_in_group_tot = 0; + uint edge_index = (edge_arr_len - 1); + uint edge_in_group_tot = 0; BLI_SMALLSTACK_DECLARE(vstack, BMVert *); while (true) { LinkNode *edge_links = NULL; - unsigned int unique_verts_in_group = 0, unique_edges_in_group = 0; + uint unique_verts_in_group = 0, unique_edges_in_group = 0; /* list of groups */ BLI_assert(BM_elem_flag_test(edge_arr[edge_index]->v1, VERT_NOT_IN_STACK)); @@ -1333,7 +1348,7 @@ bool BM_face_split_edgenet_connect_islands( #define VERT_IN_ARRAY BM_ELEM_INTERNAL_TAG struct EdgeGroupIsland **group_arr = BLI_memarena_alloc(mem_arena, sizeof(*group_arr) * group_arr_len); - unsigned int vert_arr_len = 0; + uint vert_arr_len = 0; /* sort groups by lowest value vertex */ { /* fill 'groups_arr' in reverse order so the boundary face is first */ @@ -1389,7 +1404,7 @@ bool BM_face_split_edgenet_connect_islands( /* we don't know how many unique verts there are connecting the edges, so over-alloc */ BMVert **vert_arr = BLI_memarena_alloc(mem_arena, sizeof(*vert_arr) * vert_arr_len); /* map vertex -> group index */ - unsigned int *verts_group_table = BLI_memarena_alloc(mem_arena, sizeof(*verts_group_table) * vert_arr_len); + uint *verts_group_table = BLI_memarena_alloc(mem_arena, sizeof(*verts_group_table) * vert_arr_len); float (*vert_coords_backup)[3] = BLI_memarena_alloc(mem_arena, sizeof(*vert_coords_backup) * vert_arr_len); @@ -1398,7 +1413,7 @@ bool BM_face_split_edgenet_connect_islands( const float f_co_ref[3] = {UNPACK3(BM_FACE_FIRST_LOOP(f)->v->co)}; int v_index = 0; /* global vert index */ - for (unsigned int g_index = 0; g_index < group_arr_len; g_index++) { + for (uint g_index = 0; g_index < group_arr_len; g_index++) { LinkNode *edge_links = group_arr[g_index]->edge_links.link; do { BMEdge *e = edge_links->link; @@ -1436,7 +1451,7 @@ bool BM_face_split_edgenet_connect_islands( /* Now create bvh tree*/ BVHTree *bvhtree = BLI_bvhtree_new(edge_arr_len, 0.0f, 8, 8); - for (unsigned int i = 0; i < edge_arr_len; i++) { + for (uint i = 0; i < edge_arr_len; i++) { const float e_cos[2][3] = { {UNPACK2(edge_arr[i]->v1->co), 0.0f}, {UNPACK2(edge_arr[i]->v2->co), 0.0f}, @@ -1465,15 +1480,15 @@ bool BM_face_split_edgenet_connect_islands( /* Create connections between groups */ /* may be an over-alloc, but not by much */ - unsigned int edge_net_new_len = (unsigned int)edge_net_init_len + ((group_arr_len - 1) * 2); + uint edge_net_new_len = (uint)edge_net_init_len + ((group_arr_len - 1) * 2); BMEdge **edge_net_new = BLI_memarena_alloc(mem_arena, sizeof(*edge_net_new) * edge_net_new_len); memcpy(edge_net_new, edge_net_init, sizeof(*edge_net_new) * (size_t)edge_net_init_len); { - unsigned int edge_net_new_index = edge_net_init_len; + uint edge_net_new_index = edge_net_init_len; /* start-end of the verts in the current group */ - unsigned int vert_range[2]; + uint vert_range[2]; vert_range[0] = 0; vert_range[1] = group_arr[0]->vert_len; @@ -1492,7 +1507,7 @@ bool BM_face_split_edgenet_connect_islands( .vert_range = vert_range, }; - for (unsigned int g_index = 1; g_index < group_arr_len; g_index++) { + for (uint g_index = 1; g_index < group_arr_len; g_index++) { struct EdgeGroupIsland *g = group_arr[g_index]; /* the range of verts this group uses in 'verts_arr' (not uncluding the last index) */ @@ -1551,7 +1566,7 @@ bool BM_face_split_edgenet_connect_islands( } /* tell the 'next' group it doesn't need to create its own back-link */ - unsigned int g_index_other = verts_group_table[index_other]; + uint g_index_other = verts_group_table[index_other]; group_arr[g_index_other]->has_prev_edge = true; } } @@ -1567,7 +1582,7 @@ bool BM_face_split_edgenet_connect_islands( *r_edge_net_new_len = edge_net_new_len; ok = true; - for (unsigned int i = 0; i < vert_arr_len; i++) { + for (uint i = 0; i < vert_arr_len; i++) { copy_v3_v3(vert_arr[i]->co, vert_coords_backup[i]); } @@ -1600,7 +1615,7 @@ finally: /* Remove edges which have become doubles since splicing vertices together, * its less trouble then detecting future-doubles on edge-creation. */ - for (unsigned int i = edge_net_init_len; i < edge_net_new_len; i++) { + for (uint i = edge_net_init_len; i < edge_net_new_len; i++) { while (BM_edge_find_double(edge_net_new[i])) { BM_edge_kill(bm, edge_net_new[i]); edge_net_new_len--; @@ -1616,7 +1631,7 @@ finally: #endif - for (unsigned int i = 0; i < edge_arr_len; i++) { + for (uint i = 0; i < edge_arr_len; i++) { BM_elem_flag_disable(edge_arr[i], EDGE_NOT_IN_STACK); BM_elem_flag_disable(edge_arr[i]->v1, VERT_NOT_IN_STACK); BM_elem_flag_disable(edge_arr[i]->v2, VERT_NOT_IN_STACK); diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h index 72ae7695f0f..bf5cea59e30 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h @@ -32,10 +32,10 @@ bool BM_face_split_edgenet( bool BM_face_split_edgenet_connect_islands( BMesh *bm, - BMFace *f, BMEdge **edge_net_init, const unsigned int edge_net_init_len, + BMFace *f, BMEdge **edge_net_init, const uint edge_net_init_len, bool use_partial_connect, struct MemArena *arena, - BMEdge ***r_edge_net_new, unsigned int *r_edge_net_new_len) + BMEdge ***r_edge_net_new, uint *r_edge_net_new_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3, 6, 7, 8); #endif /* __BMESH_POLYGON_EDGENET_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h index d8d297c9298..4161fbe90fb 100644 --- a/source/blender/bmesh/intern/bmesh_private.h +++ b/source/blender/bmesh/intern/bmesh_private.h @@ -73,7 +73,7 @@ enum { }; #define BM_ELEM_API_FLAG_ENABLE(element, f) { ((element)->head.api_flag |= (f)); } (void)0 -#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= (unsigned char)~(f)); } (void)0 +#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= (uchar)~(f)); } (void)0 #define BM_ELEM_API_FLAG_TEST(element, f) ((element)->head.api_flag & (f)) #define BM_ELEM_API_FLAG_CLEAR(element) { ((element)->head.api_flag = 0); } (void)0 diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index b5f9575aff5..668fb998254 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -102,17 +102,10 @@ BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v) */ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) { - BMIter liter; - BMLoop *l_iter; + BMLoop *l_iter = BM_face_vert_share_loop(f, v); BLI_assert(BM_edge_exists(v_prev, v) != NULL); - BM_ITER_ELEM (l_iter, &liter, v, BM_LOOPS_OF_VERT) { - if (l_iter->f == f) { - break; - } - } - if (l_iter) { if (l_iter->prev->v == v_prev) { return l_iter->next; @@ -149,7 +142,6 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) * The faces loop direction is ignored. * </pre> */ - BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) { #if 0 /* works but slow */ @@ -178,9 +170,6 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) return l->next->next; } } - - - #endif } @@ -392,17 +381,7 @@ BMFace *BM_vert_pair_share_face_by_angle( */ BMLoop *BM_vert_find_first_loop(BMVert *v) { - BMEdge *e; - - if (!v->e) - return NULL; - - e = bmesh_disk_faceedge_find_first(v->e, v); - - if (!e) - return NULL; - - return bmesh_radial_faceloop_find_first(e->l, v); + return v->e ? bmesh_disk_faceloop_find_first(v->e, v) : NULL; } /** @@ -878,9 +857,18 @@ int BM_vert_face_count_ex(const BMVert *v, int count_max) * * same as ``BM_vert_face_count(v) != 0`` or ``BM_vert_find_first_loop(v) == NULL`` */ -bool BM_vert_face_check(BMVert *v) +bool BM_vert_face_check(const BMVert *v) { - return v->e && (bmesh_disk_faceedge_find_first(v->e, v) != NULL); + if (v->e != NULL) { + const BMEdge *e_iter, *e_first; + e_first = e_iter = v->e; + do { + if (e_iter->l != NULL) { + return true; + } + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first); + } + return false; } /** @@ -910,7 +898,7 @@ bool BM_vert_is_wire(const BMVert *v) * A vertex is non-manifold if it meets the following conditions: * 1: Loose - (has no edges/faces incident upon it). * 2: Joins two distinct regions - (two pyramids joined at the tip). - * 3: Is part of a an edge with more than 2 faces. + * 3: Is part of an edge with more than 2 faces. * 4: Is part of a wire edge. */ bool BM_vert_is_manifold(const BMVert *v) @@ -926,7 +914,8 @@ bool BM_vert_is_manifold(const BMVert *v) /* count edges while looking for non-manifold edges */ e_first = e_iter = v->e; - l_first = e_iter->l ? e_iter->l : NULL; + /* may be null */ + l_first = e_iter->l; do { /* loose edge or edge shared by more than two faces, * edges with 1 face user are OK, otherwise we could @@ -1522,20 +1511,68 @@ float BM_loop_calc_face_angle(const BMLoop *l) * Calculate the normal at this loop corner or fallback to the face normal on straight lines. * * \param l The loop to calculate the normal at + * \param epsilon: Value to avoid numeric errors (1e-5f works well). * \param r_normal Resulting normal */ -void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) +float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon_sq, float r_normal[3]) { - if (normal_tri_v3(r_normal, - l->prev->v->co, - l->v->co, - l->next->v->co) != 0.0f) - { - /* pass */ + /* Note: we cannot use result of normal_tri_v3 here to detect colinear vectors (vertex on a straight line) + * from zero value, because it does not normalize both vectors before making crossproduct. + * Instead of adding two costly normalize computations, just check ourselves for colinear case. */ + /* Note: FEPSILON might need some finer tweaking at some point? Seems to be working OK for now though. */ + float v1[3], v2[3], v_tmp[3]; + sub_v3_v3v3(v1, l->prev->v->co, l->v->co); + sub_v3_v3v3(v2, l->next->v->co, l->v->co); + + const float fac = + ((v2[0] == 0.0f) ? + ((v2[1] == 0.0f) ? + ((v2[2] == 0.0f) ? 0.0f : v1[2] / v2[2]) : v1[1] / v2[1]) : v1[0] / v2[0]); + + mul_v3_v3fl(v_tmp, v2, fac); + sub_v3_v3(v_tmp, v1); + if (fac != 0.0f && !is_zero_v3(v1) && len_squared_v3(v_tmp) > epsilon_sq) { + /* Not co-linear, we can compute crossproduct and normalize it into normal. */ + cross_v3_v3v3(r_normal, v1, v2); + return normalize_v3(r_normal); } else { copy_v3_v3(r_normal, l->f->no); + return 0.0f; + } +} + +/** + * #BM_loop_calc_face_normal_safe_ex with pre-defined sane epsilon. + * + * Since this doesn't scale baed on triangle size, fixed value works well. + */ +float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) +{ + return BM_loop_calc_face_normal_safe_ex(l, 1e-5f, r_normal); +} + +/** + * \brief BM_loop_calc_face_normal + * + * Calculate the normal at this loop corner or fallback to the face normal on straight lines. + * + * \param l The loop to calculate the normal at + * \param r_normal Resulting normal + * \return The length of the cross product (double the area). + */ +float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) +{ + float v1[3], v2[3]; + sub_v3_v3v3(v1, l->prev->v->co, l->v->co); + sub_v3_v3v3(v2, l->next->v->co, l->v->co); + + cross_v3_v3v3(r_normal, v1, v2); + const float len = normalize_v3(r_normal); + if (UNLIKELY(len == 0.0f)) { + copy_v3_v3(r_normal, l->f->no); } + return len; } /** @@ -1924,7 +1961,7 @@ BMEdge *BM_edge_find_double(BMEdge *e) * * \note there used to be a BM_face_exists_overlap function that checks for partial overlap. */ -bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) +BMFace *BM_face_exists(BMVert **varr, int len) { if (varr[0]->e) { BMEdge *e_iter, *e_first; @@ -1963,10 +2000,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) } if (i_walk == len) { - if (r_existface) { - *r_existface = l_iter_radial->f; - } - return true; + return l_iter_radial->f; } } } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial); @@ -1975,10 +2009,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, varr[0])) != e_first); } - if (r_existface) { - *r_existface = NULL; - } - return false; + return NULL; } @@ -2121,26 +2152,21 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len) * \note The face may contain other verts \b not in \a varr. * * \note Its possible there are more than one overlapping faces, - * in this case the first one found will be assigned to \a r_f_overlap. + * in this case the first one found will be returned. * * \param varr Array of unordered verts. * \param len \a varr array length. - * \param r_f_overlap The overlapping face to return. - * \return Success + * \return The face or NULL. */ -bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) +BMFace *BM_face_exists_overlap(BMVert **varr, const int len) { BMIter viter; BMFace *f; int i; - bool is_overlap = false; + BMFace *f_overlap = NULL; LinkNode *f_lnk = NULL; - if (r_f_overlap) { - *r_f_overlap = NULL; - } - #ifdef DEBUG /* check flag isn't already set */ for (i = 0; i < len; i++) { @@ -2154,10 +2180,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) { if (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0) { if (len <= BM_verts_in_face_count(varr, len, f)) { - if (r_f_overlap) - *r_f_overlap = f; - - is_overlap = true; + f_overlap = f; break; } @@ -2171,7 +2194,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) BM_ELEM_API_FLAG_DISABLE((BMFace *)f_lnk->link, _FLAG_OVERLAP); } - return is_overlap; + return f_overlap; } /** @@ -2351,7 +2374,7 @@ static void bm_mesh_calc_volume_face(const BMFace *f, float *r_vol) { const int tottri = f->len - 2; BMLoop **loops = BLI_array_alloca(loops, f->len); - unsigned int (*index)[3] = BLI_array_alloca(index, tottri); + uint (*index)[3] = BLI_array_alloca(index, tottri); int j; BM_face_calc_tessellation(f, false, loops, index); @@ -2420,8 +2443,8 @@ int BM_mesh_calc_face_groups( int group_curr = 0; - unsigned int tot_faces = 0; - unsigned int tot_touch = 0; + uint tot_faces = 0; + uint tot_touch = 0; BMFace **stack; STACK_DECLARE(stack); @@ -2578,8 +2601,8 @@ int BM_mesh_calc_edge_groups( int group_curr = 0; - unsigned int tot_edges = 0; - unsigned int tot_touch = 0; + uint tot_edges = 0; + uint tot_touch = 0; BMEdge **stack; STACK_DECLARE(stack); diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 10e4b9a15aa..83977fa8be0 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -86,7 +86,7 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT AT bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b); -bool BM_vert_face_check(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); @@ -113,7 +113,9 @@ BMLoop *BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq BMLoop *BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq); float BM_loop_calc_face_angle(const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -void BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL(); +float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3]) ATTR_NONNULL(); +float BM_loop_calc_face_normal_safe(const BMLoop *l, float r_normal[3]) ATTR_NONNULL(); +float BM_loop_calc_face_normal_safe_ex(const BMLoop *l, const float epsilon, float r_normal[3]) ATTR_NONNULL(); void BM_loop_calc_face_direction(const BMLoop *l, float r_normal[3]); void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]); @@ -135,12 +137,12 @@ BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNUL BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) ATTR_NONNULL(1); +BMFace *BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1); bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +BMFace *BM_face_exists_overlap(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT; bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/bmesh/intern/bmesh_strands_conv.c b/source/blender/bmesh/intern/bmesh_strands_conv.c index d74ceac4d32..6cd39798126 100644 --- a/source/blender/bmesh/intern/bmesh_strands_conv.c +++ b/source/blender/bmesh/intern/bmesh_strands_conv.c @@ -159,12 +159,12 @@ static KeyBlock *bm_set_shapekey_from_psys(BMesh *bm, ParticleSystem *psys, int #endif /* create vertex and edge data for BMesh based on particle hair keys */ -static void bm_make_particles(BMesh *bm, Object *ob, ParticleSystem *psys, struct DerivedMesh *emitter_dm, float (*keyco)[3], int cd_shape_keyindex_offset) +static void bm_make_particles(BMesh *bm, Object *ob, ParticleSystem *psys, struct DerivedMesh *emitter_dm, float (*keyco)[3], int UNUSED(cd_shape_keyindex_offset)) { // KeyBlock *block; ParticleData *pa; HairKey *hkey; - int p, k, j; + int p, k; int vindex, eindex; BMVert *v = NULL, *v_prev; @@ -265,9 +265,9 @@ static void bm_make_particles(BMesh *bm, Object *ob, ParticleSystem *psys, struc * \brief ParticleSystem -> BMesh */ void BM_strands_bm_from_psys(BMesh *bm, Object *ob, ParticleSystem *psys, struct DerivedMesh *emitter_dm, - const bool set_key, int act_key_nr) + const bool set_key, int UNUSED(act_key_nr)) { - KeyBlock *actkey; + /*KeyBlock *actkey;*/ float (*keyco)[3] = NULL; int totvert, totedge; @@ -507,7 +507,7 @@ static void make_particle_hair(BMesh *bm, BMVert *root, Object *ob, ParticleSyst void BM_strands_bm_to_psys(BMesh *bm, Object *ob, ParticleSystem *psys, struct DerivedMesh *emitter_dm, struct BVHTreeFromMesh *emitter_bvhtree) { ParticleData *particles, *oldparticles; - int ototpart, ototkey, ntotpart; + int ototpart, ntotpart; BMVert *root; BMIter iter; @@ -515,7 +515,6 @@ void BM_strands_bm_to_psys(BMesh *bm, Object *ob, ParticleSystem *psys, struct D int p; ototpart = psys->totpart; - ototkey = BM_strands_count_psys_keys(psys); ntotpart = BM_strands_count(bm); @@ -711,11 +710,11 @@ void BM_strands_bm_to_psys(BMesh *bm, Object *ob, ParticleSystem *psys, struct D #endif if (oldparticles) { - ParticleData *pa; - int p; - for (p = 0, pa = oldparticles; p < ototpart; ++p, ++pa) - if (pa->hair) - MEM_freeN(pa->hair); + ParticleData *opa; + int op; + for (op = 0, opa = oldparticles; op < ototpart; ++op, ++opa) + if (opa->hair) + MEM_freeN(opa->hair); MEM_freeN(oldparticles); } } diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c index cb302139a4c..8e484841568 100644 --- a/source/blender/bmesh/intern/bmesh_structure.c +++ b/source/blender/bmesh/intern/bmesh_structure.c @@ -143,7 +143,7 @@ void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src) * to store non-manifold conditions since BM does not keep track of region/shell information. * * Functions relating to this cycle: - * - #bmesh_radial_append + * - #bmesh_radial_loop_append * - #bmesh_radial_loop_remove * - #bmesh_radial_facevert_count * - #bmesh_radial_facevert_check @@ -264,10 +264,12 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v) { BMEdge *e_iter; - if (!BM_vert_in_edge(e, v)) + if (!BM_vert_in_edge(e, v)) { return false; - if (bmesh_disk_count_ex(v, len + 1) != len || len == 0) + } + if (len == 0 || bmesh_disk_count_ex(v, len + 1) != len) { return false; + } e_iter = e; do { @@ -336,13 +338,28 @@ int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) */ BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) { - const BMEdge *e_find = e; + const BMEdge *e_iter = e; do { - if (e_find->l && bmesh_radial_facevert_check(e_find->l, v)) { - return (BMEdge *)e_find; + if (e_iter->l != NULL) { + return (BMEdge *)((e_iter->l->v == v) ? e_iter : e_iter->l->next->e); } - } while ((e_find = bmesh_disk_edge_next(e_find, v)) != e); + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e); + return NULL; +} +/** + * Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls. + * + * The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first + */ +BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) +{ + const BMEdge *e_iter = e; + do { + if (e_iter->l != NULL) { + return (e_iter->l->v == v) ? e_iter->l : e_iter->l->next; + } + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e); return NULL; } @@ -389,6 +406,30 @@ bool bmesh_radial_validate(int radlen, BMLoop *l) return true; } +void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) +{ + if (e->l == NULL) { + e->l = l; + l->radial_next = l->radial_prev = l; + } + else { + l->radial_prev = e->l; + l->radial_next = e->l->radial_next; + + e->l->radial_next->radial_prev = l; + e->l->radial_next = l; + + e->l = l; + } + + if (UNLIKELY(l->e && l->e != e)) { + /* l is already in a radial cycle for a different edge */ + BMESH_ASSERT(0); + } + + l->e = e; +} + /** * \brief BMESH RADIAL REMOVE LOOP * @@ -397,28 +438,27 @@ bool bmesh_radial_validate(int radlen, BMLoop *l) * updated (in the case that the edge's link into the radial * cycle was the loop which is being removed from the cycle). */ -void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) +void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) { /* if e is non-NULL, l must be in the radial cycle of e */ - if (UNLIKELY(e && e != l->e)) { + if (UNLIKELY(e != l->e)) { BMESH_ASSERT(0); } if (l->radial_next != l) { - if (e && l == e->l) + if (l == e->l) { e->l = l->radial_next; + } l->radial_next->radial_prev = l->radial_prev; l->radial_prev->radial_next = l->radial_next; } else { - if (e) { - if (l == e->l) { - e->l = NULL; - } - else { - BMESH_ASSERT(0); - } + if (l == e->l) { + e->l = NULL; + } + else { + BMESH_ASSERT(0); } } @@ -428,6 +468,22 @@ void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) l->e = NULL; } +/** + * A version of #bmesh_radial_loop_remove which only performs the radial unlink, + * leaving the edge untouched. + */ +void bmesh_radial_loop_unlink(BMLoop *l) +{ + if (l->radial_next != l) { + l->radial_next->radial_prev = l->radial_prev; + l->radial_prev->radial_next = l->radial_next; + } + + /* l is no longer in a radial cycle; empty the links + * to the cycle and the link back to an edge */ + l->radial_next = l->radial_prev = NULL; + l->e = NULL; +} /** * \brief BME RADIAL FIND FIRST FACE VERT @@ -484,30 +540,6 @@ int bmesh_radial_length(const BMLoop *l) return i; } -void bmesh_radial_append(BMEdge *e, BMLoop *l) -{ - if (e->l == NULL) { - e->l = l; - l->radial_next = l->radial_prev = l; - } - else { - l->radial_prev = e->l; - l->radial_next = e->l->radial_next; - - e->l->radial_next->radial_prev = l; - e->l->radial_next = l; - - e->l = l; - } - - if (UNLIKELY(l->e && l->e != e)) { - /* l is already in a radial cycle for a different edge */ - BMESH_ASSERT(0); - } - - l->e = e; -} - /** * \brief RADIAL COUNT FACE VERT * diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h index 07f94796bb2..0efb25da37c 100644 --- a/source/blender/bmesh/intern/bmesh_structure.h +++ b/source/blender/bmesh/intern/bmesh_structure.h @@ -52,11 +52,13 @@ BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_W int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* RADIAL CYCLE MANAGMENT */ -void bmesh_radial_append(BMEdge *e, BMLoop *l) ATTR_NONNULL(); -void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) ATTR_NONNULL(1); +void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) ATTR_NONNULL(); +void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) ATTR_NONNULL(); +void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL(); /* note: * bmesh_radial_loop_next(BMLoop *l) / prev. * just use member access l->radial_next, l->radial_prev now */ |