diff options
-rw-r--r-- | source/blender/editors/include/ED_mesh.h | 1 | ||||
-rw-r--r-- | source/blender/editors/mesh/editmesh_utils.c | 99 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_uv.c | 5 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_convert_mesh_uv.c | 2 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_ops.c | 2 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_select.c | 2 | ||||
-rw-r--r-- | source/blender/editors/uvedit/uvedit_smart_stitch.c | 2 |
7 files changed, 107 insertions, 6 deletions
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index b6a652bd3ab..26743a2bd08 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -139,6 +139,7 @@ struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm, const struct Scene *scene, bool uv_selected, bool use_winding, + bool use_seams, bool do_islands); void BM_uv_element_map_free(struct UvElementMap *element_map); struct UvElement *BM_uv_element_get(const struct UvElementMap *map, diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index a6a6b095c31..cca2aa11ac3 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -851,10 +851,99 @@ static void bm_uv_build_islands(UvElementMap *element_map, MEM_SAFE_FREE(map); } +/* return true if `loop` has UV co-ordinates which match `luv_a` and `luv_b` */ +static bool loop_uv_match(BMLoop *loop, MLoopUV *luv_a, MLoopUV *luv_b, int cd_loop_uv_offset) +{ + MLoopUV *luv_c = BM_ELEM_CD_GET_VOID_P(loop, cd_loop_uv_offset); + MLoopUV *luv_d = BM_ELEM_CD_GET_VOID_P(loop->next, cd_loop_uv_offset); + return compare_v2v2(luv_a->uv, luv_c->uv, STD_UV_CONNECT_LIMIT) && + compare_v2v2(luv_b->uv, luv_d->uv, STD_UV_CONNECT_LIMIT); +} + +/* Given `anchor` and `edge`, return true if there are edges that fan between them that are + * seam-free. */ +static bool seam_connected_recursive(BMVert *anchor, + BMEdge *edge, + MLoopUV *luv_anchor, + MLoopUV *luv_fan, + BMLoop *needle, + GSet *visited, + int cd_loop_uv_offset) +{ + BLI_assert(edge->v1 == anchor || edge->v2 == anchor); + BLI_assert(needle->v == anchor || needle->next->v == anchor); + + if (BM_elem_flag_test(edge, BM_ELEM_SEAM)) { + return false; /* Edge is a seam, don't traverse. */ + } + + if (!BLI_gset_add(visited, edge)) { + return false; /* Already visited. */ + } + + BMLoop *loop; + BMIter liter; + BM_ITER_ELEM (loop, &liter, edge, BM_LOOPS_OF_EDGE) { + if (loop->v == anchor) { + if (!loop_uv_match(loop, luv_anchor, luv_fan, cd_loop_uv_offset)) { + continue; /* `loop` is disjoint in UV space. */ + } + + if (loop->prev == needle) { + return true; /* Success. */ + } + + MLoopUV *luv_far = BM_ELEM_CD_GET_VOID_P(loop->prev, cd_loop_uv_offset); + if (seam_connected_recursive( + anchor, loop->prev->e, luv_anchor, luv_far, needle, visited, cd_loop_uv_offset)) { + return true; + } + } + else { + BLI_assert(loop->next->v == anchor); + if (!loop_uv_match(loop, luv_fan, luv_anchor, cd_loop_uv_offset)) { + continue; /* `loop` is disjoint in UV space. */ + } + + if (loop->next == needle) { + return true; /* Success. */ + } + + MLoopUV *luv_far = BM_ELEM_CD_GET_VOID_P(loop->next->next, cd_loop_uv_offset); + if (seam_connected_recursive( + anchor, loop->next->e, luv_anchor, luv_far, needle, visited, cd_loop_uv_offset)) { + return true; + } + } + } + + return false; +} + +/* Given `loop_a` and `loop_b` originate from the same vertex and share a UV, + * return true if there are edges that fan between them that are seam-free. + * return false otherwise. + */ +static bool seam_connected(BMLoop *loop_a, BMLoop *loop_b, GSet *visited, int cd_loop_uv_offset) +{ + BLI_assert(loop_a && loop_b); + BLI_assert(loop_a != loop_b); + BLI_assert(loop_a->v == loop_b->v); + + BLI_gset_clear(visited, NULL); + + MLoopUV *luv_anchor = BM_ELEM_CD_GET_VOID_P(loop_a, cd_loop_uv_offset); + MLoopUV *luv_fan = BM_ELEM_CD_GET_VOID_P(loop_a->next, cd_loop_uv_offset); + const bool result = seam_connected_recursive( + loop_a->v, loop_a->e, luv_anchor, luv_fan, loop_b, visited, cd_loop_uv_offset); + return result; +} + UvElementMap *BM_uv_element_map_create(BMesh *bm, const Scene *scene, const bool uv_selected, const bool use_winding, + const bool use_seams, const bool do_islands) { /* In uv sync selection, all UVs are visible. */ @@ -956,6 +1045,8 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, } BLI_buffer_free(&tf_uv_buf); + GSet *seam_visited_gset = use_seams ? BLI_gset_ptr_new(__func__) : NULL; + /* For each BMVert, sort associated linked list into unique uvs. */ int ev_index; BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, ev_index) { @@ -1001,6 +1092,10 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, winding[BM_elem_index_get(v->l->f)]; } + if (connected && use_seams) { + connected = seam_connected(iterv->l, v->l, seam_visited_gset, cd_loop_uv_offset); + } + if (connected) { if (lastv) { lastv->next = next; @@ -1026,6 +1121,10 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, element_map->vertex[ev_index] = newvlist; } + if (seam_visited_gset) { + BLI_gset_free(seam_visited_gset, NULL); + seam_visited_gset = NULL; + } MEM_SAFE_FREE(winding); /* at this point, every UvElement in vert points to a UvElement sharing the same vertex. diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index 8b9776cf94d..4739fa52674 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -686,9 +686,10 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm /* Winding was added to island detection in 5197aa04c6bd * However the sculpt tools can flip faces, potentially creating orphaned islands. * See T100132 */ - bool use_winding = false; + const bool use_winding = false; + const bool use_seams = true; data->elementMap = BM_uv_element_map_create( - bm, scene, false, use_winding, do_island_optimization); + bm, scene, false, use_winding, use_seams, do_island_optimization); if (!data->elementMap) { uv_sculpt_stroke_exit(C, op); diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c index f3bef2c283b..27f12137e3a 100644 --- a/source/blender/editors/transform/transform_convert_mesh_uv.c +++ b/source/blender/editors/transform/transform_convert_mesh_uv.c @@ -265,7 +265,7 @@ static void createTransUVs(bContext *C, TransInfo *t) /* count */ if (is_island_center) { /* create element map with island information */ - elementmap = BM_uv_element_map_create(em->bm, scene, true, false, true); + elementmap = BM_uv_element_map_create(em->bm, scene, true, false, true, true); if (elementmap == NULL) { continue; } diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index c0dd7623ade..4cc2c6450df 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -535,7 +535,7 @@ static bool uvedit_uv_straighten(Scene *scene, BMesh *bm, eUVWeldAlign tool) return false; } - UvElementMap *element_map = BM_uv_element_map_create(bm, scene, true, false, true); + UvElementMap *element_map = BM_uv_element_map_create(bm, scene, true, false, true, true); if (element_map == NULL) { return false; } diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index cecf0ff7914..43c8620df1d 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -5384,7 +5384,7 @@ static void uv_isolate_selected_islands(const Scene *scene, BLI_assert((scene->toolsettings->uv_flag & UV_SYNC_SELECTION) == 0); BMFace *efa; BMIter iter, liter; - UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true); + UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true, true); if (elementmap == NULL) { return; } diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index e89f99fc412..e19cc67bd16 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -1855,7 +1855,7 @@ static StitchState *stitch_init(bContext *C, * for stitch this isn't useful behavior, see T86924. */ const int selectmode_orig = scene->toolsettings->selectmode; scene->toolsettings->selectmode = SCE_SELECT_VERTEX; - state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, true, true); + state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, true, true, true); scene->toolsettings->selectmode = selectmode_orig; if (!state->element_map) { |