diff options
Diffstat (limited to 'source/blender/editors/uvedit/uvedit_select.c')
-rw-r--r-- | source/blender/editors/uvedit/uvedit_select.c | 1151 |
1 files changed, 803 insertions, 348 deletions
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index cc9be9d48c1..4c354ab5940 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -88,12 +88,128 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph, Object *obedit); /* -------------------------------------------------------------------- */ +/** \name Active Selection Tracking + * + * Currently we don't store loops in the selection history, + * store face/edge/vert combinations (needed for UV path selection). + * \{ */ + +void ED_uvedit_active_vert_loop_set(BMesh *bm, BMLoop *l) +{ + BM_select_history_clear(bm); + BM_select_history_remove(bm, (BMElem *)l->f); + BM_select_history_remove(bm, (BMElem *)l->v); + BM_select_history_store_notest(bm, (BMElem *)l->f); + BM_select_history_store_notest(bm, (BMElem *)l->v); +} + +BMLoop *ED_uvedit_active_vert_loop_get(BMesh *bm) +{ + BMEditSelection *ese = bm->selected.last; + if (ese && ese->prev) { + BMEditSelection *ese_prev = ese->prev; + if ((ese->htype == BM_VERT) && (ese_prev->htype == BM_FACE)) { + /* May be NULL. */ + return BM_face_vert_share_loop((BMFace *)ese_prev->ele, (BMVert *)ese->ele); + } + } + return NULL; +} + +void ED_uvedit_active_edge_loop_set(BMesh *bm, BMLoop *l) +{ + BM_select_history_clear(bm); + BM_select_history_remove(bm, (BMElem *)l->f); + BM_select_history_remove(bm, (BMElem *)l->e); + BM_select_history_store_notest(bm, (BMElem *)l->f); + BM_select_history_store_notest(bm, (BMElem *)l->e); +} + +BMLoop *ED_uvedit_active_edge_loop_get(BMesh *bm) +{ + BMEditSelection *ese = bm->selected.last; + if (ese && ese->prev) { + BMEditSelection *ese_prev = ese->prev; + if ((ese->htype == BM_EDGE) && (ese_prev->htype == BM_FACE)) { + /* May be NULL. */ + return BM_face_edge_share_loop((BMFace *)ese_prev->ele, (BMEdge *)ese->ele); + } + } + return NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Visibility and Selection Utilities * \{ */ -static void uv_select_island_limit_default(SpaceImage *sima, float r_limit[2]) +/** + * Intentionally don't return #UV_SELECT_ISLAND as it's not an element type. + * In this case return #UV_SELECT_VERTEX as a fallback. + */ +char ED_uvedit_select_mode_get(const Scene *scene) { - uvedit_pixel_to_float(sima, 0.05f, r_limit); + const ToolSettings *ts = scene->toolsettings; + char uv_selectmode = UV_SELECT_VERTEX; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_VERTEX) { + uv_selectmode = UV_SELECT_VERTEX; + } + else if (ts->selectmode & SCE_SELECT_EDGE) { + uv_selectmode = UV_SELECT_EDGE; + } + else if (ts->selectmode & SCE_SELECT_FACE) { + uv_selectmode = UV_SELECT_FACE; + } + } + else { + if (ts->uv_selectmode & UV_SELECT_VERTEX) { + uv_selectmode = UV_SELECT_VERTEX; + } + else if (ts->uv_selectmode & UV_SELECT_EDGE) { + uv_selectmode = UV_SELECT_EDGE; + } + else if (ts->uv_selectmode & UV_SELECT_FACE) { + uv_selectmode = UV_SELECT_FACE; + } + } + return uv_selectmode; +} + +void ED_uvedit_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const bool select) +{ + /* bmesh API handles flushing but not on de-select */ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode != SCE_SELECT_FACE) { + if (select == false) { + EDBM_deselect_flush(em); + } + else { + EDBM_select_flush(em); + } + } + + if (select == false) { + BM_select_history_validate(em->bm); + } + } +} + +/** + * Apply a penalty to elements that are already selected + * so elements that aren't already selected are prioritized. + * + * \note This is calculated in screen-space otherwise zooming in on a uv-vert and + * shift-selecting can consider an adjacent point close enough to add to + * the selection rather than de-selecting the closest. + */ +static float uv_select_penalty_default(SpaceImage *sima) +{ + float penalty[2]; + uvedit_pixel_to_float(sima, 5.0f / (sima ? sima->zoom : 1.0f), penalty); + return len_v2(penalty); } static void uvedit_vertex_select_tagged(BMEditMesh *em, @@ -108,7 +224,7 @@ static void uvedit_vertex_select_tagged(BMEditMesh *em, BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); } } } @@ -119,9 +235,7 @@ bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa) if (ts->uv_flag & UV_SYNC_SELECTION) { return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0); } - else { - return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); - } + return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); } bool uvedit_face_visible_test(const Scene *scene, BMFace *efa) { @@ -133,27 +247,47 @@ bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int c if (ts->uv_flag & UV_SYNC_SELECTION) { return (BM_elem_flag_test(efa, BM_ELEM_SELECT)); } - else { - BMLoop *l; - MLoopUV *luv; - BMIter liter; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (!(luv->flag & MLOOPUV_VERTSEL)) { - return false; - } - } + BMLoop *l; + MLoopUV *luv; + BMIter liter; - return true; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (!(luv->flag & MLOOPUV_VERTSEL)) { + return false; + } } + return true; } bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset) { return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset); } -bool uvedit_face_select_set(const struct Scene *scene, +void uvedit_face_select_set_with_sticky(const SpaceImage *sima, + const Scene *scene, + BMEditMesh *em, + BMFace *efa, + const bool select, + const bool do_history, + const int cd_loop_uv_offset) +{ + const ToolSettings *ts = scene->toolsettings; + if (ts->uv_flag & UV_SYNC_SELECTION) { + uvedit_face_select_set(scene, em, efa, select, do_history, cd_loop_uv_offset); + return; + } + + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + uvedit_uv_select_set_with_sticky( + sima, scene, em, l_iter, select, do_history, cd_loop_uv_offset); + } while ((l_iter = l_iter->next) != l_first); +} + +void uvedit_face_select_set(const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select, @@ -161,14 +295,14 @@ bool uvedit_face_select_set(const struct Scene *scene, const int cd_loop_uv_offset) { if (select) { - return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); + uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); } else { - return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); } } -bool uvedit_face_select_enable(const Scene *scene, +void uvedit_face_select_enable(const Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history, @@ -191,14 +325,10 @@ bool uvedit_face_select_enable(const Scene *scene, luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); luv->flag |= MLOOPUV_VERTSEL; } - - return true; } - - return false; } -bool uvedit_face_select_disable(const Scene *scene, +void uvedit_face_select_disable(const Scene *scene, BMEditMesh *em, BMFace *efa, const int cd_loop_uv_offset) @@ -217,11 +347,7 @@ bool uvedit_face_select_disable(const Scene *scene, luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); luv->flag &= ~MLOOPUV_VERTSEL; } - - return true; } - - return false; } bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) @@ -230,30 +356,46 @@ bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_ if (ts->selectmode & SCE_SELECT_FACE) { return BM_elem_flag_test(l->f, BM_ELEM_SELECT); } - else if (ts->selectmode == SCE_SELECT_EDGE) { + if (ts->selectmode == SCE_SELECT_EDGE) { return BM_elem_flag_test(l->e, BM_ELEM_SELECT); } - else { - return BM_elem_flag_test(l->v, BM_ELEM_SELECT) && - BM_elem_flag_test(l->next->v, BM_ELEM_SELECT); - } + return BM_elem_flag_test(l->v, BM_ELEM_SELECT) && + BM_elem_flag_test(l->next->v, BM_ELEM_SELECT); } - else { - MLoopUV *luv1, *luv2; - luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + MLoopUV *luv1, *luv2; - return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL); - } + luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL); } bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) { return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); } -void uvedit_edge_select_set(BMEditMesh *em, - const Scene *scene, +void uvedit_edge_select_set_with_sticky(const struct SpaceImage *sima, + const Scene *scene, + BMEditMesh *em, + BMLoop *l, + const bool select, + const bool do_history, + const uint cd_loop_uv_offset) +{ + const ToolSettings *ts = scene->toolsettings; + if (ts->uv_flag & UV_SYNC_SELECTION) { + uvedit_edge_select_set(scene, em, l, select, do_history, cd_loop_uv_offset); + return; + } + + uvedit_uv_select_set_with_sticky(sima, scene, em, l, select, do_history, cd_loop_uv_offset); + uvedit_uv_select_set_with_sticky( + sima, scene, em, l->next, select, do_history, cd_loop_uv_offset); +} + +void uvedit_edge_select_set(const Scene *scene, + BMEditMesh *em, BMLoop *l, const bool select, const bool do_history, @@ -261,15 +403,15 @@ void uvedit_edge_select_set(BMEditMesh *em, { if (select) { - uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset); + uvedit_edge_select_enable(scene, em, l, do_history, cd_loop_uv_offset); } else { - uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset); + uvedit_edge_select_disable(scene, em, l, cd_loop_uv_offset); } } -void uvedit_edge_select_enable(BMEditMesh *em, - const Scene *scene, +void uvedit_edge_select_enable(const Scene *scene, + BMEditMesh *em, BMLoop *l, const bool do_history, const int cd_loop_uv_offset) @@ -304,8 +446,8 @@ void uvedit_edge_select_enable(BMEditMesh *em, } } -void uvedit_edge_select_disable(BMEditMesh *em, - const Scene *scene, +void uvedit_edge_select_disable(const Scene *scene, + BMEditMesh *em, BMLoop *l, const int cd_loop_uv_offset) @@ -341,37 +483,90 @@ bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_lo if (ts->selectmode & SCE_SELECT_FACE) { return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT); } - else { - return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT); - } - } - else { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - return (luv->flag & MLOOPUV_VERTSEL) != 0; + return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT); } + + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + return (luv->flag & MLOOPUV_VERTSEL) != 0; } bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) { return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); } -void uvedit_uv_select_set(BMEditMesh *em, - const Scene *scene, +void uvedit_uv_select_set_with_sticky(const struct SpaceImage *sima, + const Scene *scene, + BMEditMesh *em, + BMLoop *l, + const bool select, + const bool do_history, + const uint cd_loop_uv_offset) +{ + const ToolSettings *ts = scene->toolsettings; + if (ts->uv_flag & UV_SYNC_SELECTION) { + uvedit_uv_select_set(scene, em, l, select, do_history, cd_loop_uv_offset); + return; + } + + const int sticky = sima->sticky; + switch (sticky) { + case SI_STICKY_DISABLE: { + uvedit_uv_select_set(scene, em, l, select, do_history, cd_loop_uv_offset); + break; + } + default: { + /* #SI_STICKY_VERTEX or #SI_STICKY_LOC. */ + const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + BMEdge *e_first, *e_iter; + e_first = e_iter = l->e; + do { + if (e_iter->l) { + BMLoop *l_radial_iter = e_iter->l; + do { + if (l_radial_iter->v == l->v) { + if (uvedit_face_visible_test(scene, l_radial_iter->f)) { + bool do_select = false; + if (sticky == SI_STICKY_VERTEX) { + do_select = true; + } + else { + const MLoopUV *luv_other = BM_ELEM_CD_GET_VOID_P(l_radial_iter, + cd_loop_uv_offset); + if (equals_v2v2(luv_other->uv, luv->uv)) { + do_select = true; + } + } + + if (do_select) { + uvedit_uv_select_set( + scene, em, l_radial_iter, select, do_history, cd_loop_uv_offset); + } + } + } + } while ((l_radial_iter = l_radial_iter->radial_next) != e_iter->l); + } + } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, l->v)) != e_first); + } + } +} + +void uvedit_uv_select_set(const Scene *scene, + BMEditMesh *em, BMLoop *l, const bool select, const bool do_history, const int cd_loop_uv_offset) { if (select) { - uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset); + uvedit_uv_select_enable(scene, em, l, do_history, cd_loop_uv_offset); } else { - uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset); + uvedit_uv_select_disable(scene, em, l, cd_loop_uv_offset); } } -void uvedit_uv_select_enable(BMEditMesh *em, - const Scene *scene, +void uvedit_uv_select_enable(const Scene *scene, + BMEditMesh *em, BMLoop *l, const bool do_history, const int cd_loop_uv_offset) @@ -387,7 +582,7 @@ void uvedit_uv_select_enable(BMEditMesh *em, } if (do_history) { - BM_select_history_remove(em->bm, (BMElem *)l->v); + BM_select_history_store(em->bm, (BMElem *)l->v); } } else { @@ -396,8 +591,8 @@ void uvedit_uv_select_enable(BMEditMesh *em, } } -void uvedit_uv_select_disable(BMEditMesh *em, - const Scene *scene, +void uvedit_uv_select_disable(const Scene *scene, + BMEditMesh *em, BMLoop *l, const int cd_loop_uv_offset) { @@ -417,6 +612,31 @@ void uvedit_uv_select_disable(BMEditMesh *em, } } +static BMLoop *uvedit_loop_find_other_radial_loop_with_visible_face(Scene *scene, + BMLoop *l_src, + const int cd_loop_uv_offset) +{ + BMLoop *l_other = NULL; + BMLoop *l_iter = l_src->radial_next; + if (l_iter != l_src) { + do { + if (uvedit_face_visible_test(scene, l_iter->f) && + BM_loop_uv_share_edge_check(l_src, l_iter, cd_loop_uv_offset)) { + /* Check UV's are contiguous. */ + if (l_other == NULL) { + l_other = l_iter; + } + else { + /* Only use when there is a single alternative. */ + l_other = NULL; + break; + } + } + } while ((l_iter = l_iter->radial_next) != l_src); + } + return l_other; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -667,9 +887,7 @@ bool ED_uvedit_nearest_uv( *dist_sq = dist_best; return true; } - else { - return false; - } + return false; } bool ED_uvedit_nearest_uv_multi(const Scene *scene, @@ -692,7 +910,73 @@ bool ED_uvedit_nearest_uv_multi(const Scene *scene, /** \} */ /* -------------------------------------------------------------------- */ -/** \name Loop Select +/** \name Find Nearest to Element + * + * These functions are quite specialized, useful when sync select is enabled + * and we want to pick an active UV vertex/edge from the active element which may + * have multiple UV's split out. + * \{ */ + +BMLoop *uv_find_nearest_loop_from_vert(struct Scene *scene, + struct Object *obedit, + struct BMVert *v, + const float co[2]) +{ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BMIter liter; + BMLoop *l; + BMLoop *l_found = NULL; + float dist_best_sq = FLT_MAX; + + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + if (!uvedit_face_visible_test(scene, l->f)) { + continue; + } + + const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + const float dist_test_sq = len_squared_v2v2(co, luv->uv); + if (dist_test_sq < dist_best_sq) { + dist_best_sq = dist_test_sq; + l_found = l; + } + } + return l_found; +} + +BMLoop *uv_find_nearest_loop_from_edge(struct Scene *scene, + struct Object *obedit, + struct BMEdge *e, + const float co[2]) +{ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BMIter eiter; + BMLoop *l; + BMLoop *l_found = NULL; + float dist_best_sq = FLT_MAX; + + BM_ITER_ELEM (l, &eiter, e, BM_LOOPS_OF_EDGE) { + if (!uvedit_face_visible_test(scene, l->f)) { + continue; + } + const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv); + if (dist_test_sq < dist_best_sq) { + dist_best_sq = dist_test_sq; + l_found = l; + } + } + return l_found; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Edge Loop Select * \{ */ static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first) @@ -792,8 +1076,7 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, return true; } -static int uv_select_edgeloop( - Scene *scene, Object *obedit, UvNearestHit *hit, const float limit[2], const bool extend) +static int uv_select_edgeloop(Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMFace *efa; @@ -809,7 +1092,7 @@ static int uv_select_edgeloop( /* setup */ BM_mesh_elem_table_ensure(em->bm, BM_FACE); - vmap = BM_uv_vert_map_create(em->bm, limit, false, false); + vmap = BM_uv_vert_map_create(em->bm, false, false); BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); @@ -882,7 +1165,7 @@ static int uv_select_edgeloop( iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l); if (iterv_curr->flag) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); } } } @@ -896,13 +1179,89 @@ static int uv_select_edgeloop( /** \} */ /* -------------------------------------------------------------------- */ +/** \name Edge Ring Select + * \{ */ + +static int uv_select_edgering( + const SpaceImage *sima, Scene *scene, Object *obedit, UvNearestHit *hit, const bool extend) +{ + const ToolSettings *ts = scene->toolsettings; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const bool use_face_select = (ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode & SCE_SELECT_FACE) : + (ts->uv_selectmode & UV_SELECT_FACE); + bool select; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (!extend) { + uv_select_all_perform(scene, obedit, SEL_DESELECT); + } + + BM_mesh_elem_hflag_disable_all(em->bm, BM_EDGE, BM_ELEM_TAG, false); + + if (extend) { + select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset)); + } + else { + select = true; + } + + BMLoop *l_pair[2] = { + hit->l, + uvedit_loop_find_other_radial_loop_with_visible_face(scene, hit->l, cd_loop_uv_offset), + }; + + for (int side = 0; side < 2; side++) { + BMLoop *l_step = l_pair[side]; + /* Disable since we start from the same edge. */ + BM_elem_flag_disable(hit->l->e, BM_ELEM_TAG); + while (l_step) { + if (!uvedit_face_visible_test(scene, l_step->f)) { + break; + } + + if (use_face_select) { + uvedit_face_select_set_with_sticky( + sima, scene, em, l_step->f, select, false, cd_loop_uv_offset); + } + else { + uvedit_edge_select_set_with_sticky( + sima, scene, em, l_step, select, false, cd_loop_uv_offset); + } + + BM_elem_flag_enable(l_step->e, BM_ELEM_TAG); + if (l_step->f->len == 4) { + BMLoop *l_step_opposite = l_step->next->next; + l_step = uvedit_loop_find_other_radial_loop_with_visible_face( + scene, l_step_opposite, cd_loop_uv_offset); + if (l_step == NULL) { + /* Ensure we touch the opposite edge if we cant walk over it. */ + l_step = l_step_opposite; + } + } + else { + l_step = NULL; + } + + if (l_step && BM_elem_flag_test(l_step->e, BM_ELEM_TAG)) { + break; + } + } + } + + return (select) ? 1 : -1; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Select Linked * \{ */ static void uv_select_linked_multi(Scene *scene, Object **objects, const uint objects_len, - const float limit[2], UvNearestHit *hit_final, bool extend, bool deselect, @@ -937,7 +1296,7 @@ static void uv_select_linked_multi(Scene *scene, * * Better solve this by having a delimit option for select-linked operator, * keeping island-select working as is. */ - vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false); + vmap = BM_uv_vert_map_create(em->bm, !select_faces, false); if (vmap == NULL) { continue; @@ -1011,7 +1370,7 @@ static void uv_select_linked_multi(Scene *scene, if ((startv != iterv) && (iterv->separate)) { break; } - else if (!flag[iterv->poly_index]) { + if (!flag[iterv->poly_index]) { flag[iterv->poly_index] = 1; stack[stacksize] = iterv->poly_index; stacksize++; @@ -1289,17 +1648,16 @@ bool uvedit_select_is_any_selected(Scene *scene, Object *obedit) if (ts->uv_flag & UV_SYNC_SELECTION) { return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel); } - else { - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (luv->flag & MLOOPUV_VERTSEL) { - return true; - } + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (luv->flag & MLOOPUV_VERTSEL) { + return true; } } } @@ -1438,76 +1796,27 @@ void UV_OT_select_all(wmOperatorType *ot) /** \name Mouse Select Operator * \{ */ -static bool uv_sticky_select( - float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen) -{ - int i; - - /* this function test if some vertex needs to selected - * in addition to the existing ones due to sticky select */ - if (sticky == SI_STICKY_DISABLE) { - return false; - } - - for (i = 0; i < hitlen; i++) { - if (hitv[i] == v) { - if (sticky == SI_STICKY_LOC) { - if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) { - return true; - } - } - else if (sticky == SI_STICKY_VERTEX) { - return true; - } - } - } - - return false; -} - static int uv_mouse_select_multi(bContext *C, Object **objects, uint objects_len, const float co[2], const bool extend, - const bool deselect_all, - const bool loop) + const bool deselect_all) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; UvNearestHit hit = UV_NEAREST_HIT_INIT; - int i, selectmode, sticky, sync, *hitv = NULL; - bool select = true; + int selectmode, sticky; bool found_item = false; /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ int flush = 0; - int hitlen = 0; - float limit[2], **hituv = NULL; - /* notice 'limit' is the same no matter the zoom level, since this is like - * remove doubles and could annoying if it joined points when zoomed out. - * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and - * shift-selecting can consider an adjacent point close enough to add to - * the selection rather than de-selecting the closest. */ - - float penalty_dist; - { - float penalty[2]; - uvedit_pixel_to_float(sima, 0.05f, limit); - uvedit_pixel_to_float(sima, 5.0f / (sima ? sima->zoom : 1.0f), penalty); - penalty_dist = len_v2(penalty); - } + const float penalty_dist = uv_select_penalty_default(sima); /* retrieve operation mode */ if (ts->uv_flag & UV_SYNC_SELECTION) { - sync = 1; - if (ts->selectmode & SCE_SELECT_FACE) { selectmode = UV_SELECT_FACE; } @@ -1521,31 +1830,21 @@ static int uv_mouse_select_multi(bContext *C, sticky = SI_STICKY_DISABLE; } else { - sync = 0; selectmode = ts->uv_selectmode; - sticky = (sima) ? sima->sticky : 1; + sticky = (sima) ? sima->sticky : SI_STICKY_DISABLE; } /* find nearest element */ - if (loop) { - /* find edge */ - found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); - } - else if (selectmode == UV_SELECT_VERTEX) { + if (selectmode == UV_SELECT_VERTEX) { /* find vertex */ found_item = uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit); found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); if (found_item) { - /* mark 1 vertex as being hit */ - hitv = BLI_array_alloca(hitv, hit.efa->len); - hituv = BLI_array_alloca(hituv, hit.efa->len); - copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); - - hitv[hit.lindex] = BM_elem_index_get(hit.l->v); - hituv[hit.lindex] = hit.luv->uv; - - hitlen = hit.efa->len; + if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) { + BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm; + ED_uvedit_active_vert_loop_set(bm, hit.l); + } } } else if (selectmode == UV_SELECT_EDGE) { @@ -1554,17 +1853,10 @@ static int uv_mouse_select_multi(bContext *C, found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); if (found_item) { - /* mark 2 edge vertices as being hit */ - hitv = BLI_array_alloca(hitv, hit.efa->len); - hituv = BLI_array_alloca(hituv, hit.efa->len); - copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); - - hitv[hit.lindex] = BM_elem_index_get(hit.l->v); - hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v); - hituv[hit.lindex] = hit.luv->uv; - hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv; - - hitlen = hit.efa->len; + if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) { + BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm; + ED_uvedit_active_edge_loop_set(bm, hit.l); + } } } else if (selectmode == UV_SELECT_FACE) { @@ -1573,23 +1865,8 @@ static int uv_mouse_select_multi(bContext *C, found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); if (found_item) { - BMEditMesh *em = BKE_editmesh_from_object(hit.ob); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* make active */ - BM_mesh_active_face_set(em->bm, hit.efa); - - /* mark all face vertices as being hit */ - - hitv = BLI_array_alloca(hitv, hit.efa->len); - hituv = BLI_array_alloca(hituv, hit.efa->len); - BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - hituv[i] = luv->uv; - hitv[i] = BM_elem_index_get(l->v); - } - - hitlen = hit.efa->len; + BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm; + BM_mesh_active_face_set(bm, hit.efa); } } else if (selectmode == UV_SELECT_ISLAND) { @@ -1616,44 +1893,39 @@ static int uv_mouse_select_multi(bContext *C, const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); /* do selection */ - if (loop) { - if (!extend) { - /* TODO(MULTI_EDIT): We only need to de-select non-active */ - uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); - } - flush = uv_select_edgeloop(scene, obedit, &hit, limit, extend); - } - else if (selectmode == UV_SELECT_ISLAND) { + if (selectmode == UV_SELECT_ISLAND) { if (!extend) { /* TODO(MULTI_EDIT): We only need to de-select non-active */ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } /* Current behavior of 'extend' * is actually toggling, so pass extend flag as 'toggle' here */ - uv_select_linked_multi(scene, objects, objects_len, limit, &hit, false, false, extend, false); + uv_select_linked_multi(scene, objects, objects_len, &hit, false, false, extend, false); } else if (extend) { + bool select = true; if (selectmode == UV_SELECT_VERTEX) { /* (de)select uv vertex */ select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); - uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); + uvedit_uv_select_set_with_sticky(sima, scene, em, hit.l, select, true, cd_loop_uv_offset); flush = 1; } else if (selectmode == UV_SELECT_EDGE) { /* (de)select edge */ select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset)); - uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); + uvedit_edge_select_set_with_sticky(sima, scene, em, hit.l, select, true, cd_loop_uv_offset); flush = 1; } else if (selectmode == UV_SELECT_FACE) { /* (de)select face */ select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset)); - uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset); + uvedit_face_select_set_with_sticky( + sima, scene, em, hit.efa, select, true, cd_loop_uv_offset); flush = -1; } /* de-selecting an edge may deselect a face too - validate */ - if (sync) { + if (ts->uv_flag & UV_SYNC_SELECTION) { if (select == false) { BM_select_history_validate(em->bm); } @@ -1661,98 +1933,36 @@ static int uv_mouse_select_multi(bContext *C, /* (de)select sticky uv nodes */ if (sticky != SI_STICKY_DISABLE) { - - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (uv_sticky_select( - limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } - flush = select ? 1 : -1; } } else { + const bool select = true; /* deselect all */ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); if (selectmode == UV_SELECT_VERTEX) { /* select vertex */ - uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); + uvedit_uv_select_set_with_sticky(sima, scene, em, hit.l, select, true, cd_loop_uv_offset); flush = 1; } else if (selectmode == UV_SELECT_EDGE) { /* select edge */ - uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); + uvedit_edge_select_set_with_sticky(sima, scene, em, hit.l, select, true, cd_loop_uv_offset); flush = 1; } else if (selectmode == UV_SELECT_FACE) { /* select face */ - uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset); - } - - /* select sticky uvs */ - if (sticky != SI_STICKY_DISABLE) { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (sticky == SI_STICKY_DISABLE) { - continue; - } - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (uv_sticky_select( - limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) { - uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); - } - - flush = 1; - } - } + uvedit_face_select_set_with_sticky( + sima, scene, em, hit.efa, select, true, cd_loop_uv_offset); + flush = 1; } } - if (sync) { - /* flush for mesh selection */ - - /* before bmesh */ -#if 0 - if (ts->selectmode != SCE_SELECT_FACE) { - if (flush == 1) { - EDBM_select_flush(em); - } - else if (flush == -1) { - EDBM_deselect_flush(em); - } - } -#else + if (ts->uv_flag & UV_SYNC_SELECTION) { if (flush != 0) { - if (loop) { - /* push vertex -> edge selection */ - if (select) { - EDBM_select_flush(em); - } - else { - EDBM_deselect_flush(em); - } - } - else { - EDBM_selectmode_flush(em); - } + EDBM_selectmode_flush(em); } -#endif } for (uint ob_index = 0; ob_index < objects_len; ob_index++) { @@ -1762,14 +1972,16 @@ static int uv_mouse_select_multi(bContext *C, return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; } -static int uv_mouse_select( - bContext *C, const float co[2], const bool extend, const bool deselect_all, const bool loop) +static int uv_mouse_select(bContext *C, + const float co[2], + const bool extend, + const bool deselect_all) { ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all, loop); + int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all); MEM_freeN(objects); return ret; } @@ -1781,9 +1993,8 @@ static int uv_select_exec(bContext *C, wmOperator *op) RNA_float_get_array(op->ptr, "location", co); const bool extend = RNA_boolean_get(op->ptr, "extend"); const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); - const bool loop = false; - return uv_mouse_select(C, co, extend, deselect_all, loop); + return uv_mouse_select(C, co, extend, deselect_all); } static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -1840,7 +2051,89 @@ void UV_OT_select(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Loop Select Operator +/** \name Shared Edge Loop/Ring Select Operator Functions + * \{ */ + +enum eUVLoopGenericType { + UV_LOOP_SELECT = 1, + UV_RING_SELECT = 2, +}; + +static int uv_mouse_select_loop_generic_multi(bContext *C, + Object **objects, + uint objects_len, + const float co[2], + const bool extend, + enum eUVLoopGenericType loop_type) +{ + SpaceImage *sima = CTX_wm_space_image(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + UvNearestHit hit = UV_NEAREST_HIT_INIT; + bool found_item = false; + /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ + int flush = 0; + + /* Find edge. */ + found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); + if (!found_item) { + return OPERATOR_CANCELLED; + } + + Object *obedit = hit.ob; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + /* Do selection. */ + if (!extend) { + /* TODO(MULTI_EDIT): We only need to de-select non-active */ + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); + } + + if (loop_type == UV_LOOP_SELECT) { + flush = uv_select_edgeloop(scene, obedit, &hit, extend); + } + else if (loop_type == UV_RING_SELECT) { + flush = uv_select_edgering(sima, scene, obedit, &hit, extend); + } + else { + BLI_assert(0); + } + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (flush == 1) { + EDBM_select_flush(em); + } + else if (flush == -1) { + EDBM_deselect_flush(em); + } + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obiter = objects[ob_index]; + uv_select_tag_update_for_object(depsgraph, ts, obiter); + } + + return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; +} +static int uv_mouse_select_loop_generic(bContext *C, + const float co[2], + const bool extend, + enum eUVLoopGenericType loop_type) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + int ret = uv_mouse_select_loop_generic_multi(C, objects, objects_len, co, extend, loop_type); + MEM_freeN(objects); + return ret; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Edge Loop Select Operator * \{ */ static int uv_select_loop_exec(bContext *C, wmOperator *op) @@ -1849,10 +2142,8 @@ static int uv_select_loop_exec(bContext *C, wmOperator *op) RNA_float_get_array(op->ptr, "location", co); const bool extend = RNA_boolean_get(op->ptr, "extend"); - const bool deselect_all = false; - const bool loop = true; - return uv_mouse_select(C, co, extend, deselect_all, loop); + return uv_mouse_select_loop_generic(C, co, extend, UV_LOOP_SELECT); } static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -1901,16 +2192,71 @@ void UV_OT_select_loop(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Edge Ring Select Operator + * \{ */ + +static int uv_select_edge_ring_exec(bContext *C, wmOperator *op) +{ + float co[2]; + RNA_float_get_array(op->ptr, "location", co); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + return uv_mouse_select_loop_generic(C, co, extend, UV_RING_SELECT); +} + +static int uv_select_edge_ring_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + const ARegion *region = CTX_wm_region(C); + float co[2]; + + UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + RNA_float_set_array(op->ptr, "location", co); + + return uv_select_edge_ring_exec(C, op); +} + +void UV_OT_select_edge_ring(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Edge Ring Select"; + ot->description = "Select an edge ring of connected UV vertices"; + ot->idname = "UV_OT_select_edge_ring"; + ot->flag = OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_edge_ring_exec; + ot->invoke = uv_select_edge_ring_invoke; + ot->poll = ED_operator_uvedit; /* requires space image */ + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); + RNA_def_float_vector( + ot->srna, + "location", + 2, + NULL, + -FLT_MAX, + FLT_MAX, + "Location", + "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", + -100.0f, + 100.0f); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Select Linked Operator * \{ */ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick) { - SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); const ToolSettings *ts = scene->toolsettings; ViewLayer *view_layer = CTX_data_view_layer(C); - float limit[2]; bool extend = true; bool deselect = false; bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); @@ -1928,7 +2274,6 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent extend = RNA_boolean_get(op->ptr, "extend"); deselect = RNA_boolean_get(op->ptr, "deselect"); } - uv_select_island_limit_default(sima, limit); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( @@ -1959,15 +2304,8 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } - uv_select_linked_multi(scene, - objects, - objects_len, - limit, - pick ? &hit : NULL, - extend, - deselect, - false, - select_faces); + uv_select_linked_multi( + scene, objects, objects_len, pick ? &hit : NULL, extend, deselect, false, select_faces); /* weak!, but works */ Object **objects_free = objects; @@ -2076,6 +2414,7 @@ void UV_OT_select_linked_pick(wmOperatorType *ot) */ static int uv_select_split_exec(bContext *C, wmOperator *op) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); const ToolSettings *ts = scene->toolsettings; @@ -2142,6 +2481,7 @@ static int uv_select_split_exec(bContext *C, wmOperator *op) if (changed) { changed_multi = true; WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); + uv_select_tag_update_for_object(depsgraph, ts, obedit); } } MEM_freeN(objects); @@ -2162,25 +2502,6 @@ void UV_OT_select_split(wmOperatorType *ot) ot->poll = ED_operator_uvedit; /* requires space image */ } -static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select) -{ - /* bmesh API handles flushing but not on de-select */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode != SCE_SELECT_FACE) { - if (select == false) { - EDBM_deselect_flush(em); - } - else { - EDBM_select_flush(em); - } - } - - if (select == false) { - BM_select_history_validate(em->bm); - } - } -} - static void uv_select_tag_update_for_object(Depsgraph *depsgraph, const ToolSettings *ts, Object *obedit) @@ -2219,7 +2540,7 @@ static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, UvMapVert *start_vlist = NULL, *vlist_iter; BMFace *efa_vlist; - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); @@ -2250,7 +2571,7 @@ static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, l_other = BM_iter_at_index( em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index); - uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l_other, select, false, cd_loop_uv_offset); } vlist_iter = vlist_iter->next; } @@ -2303,20 +2624,17 @@ static void uv_select_flush_from_tag_face(SpaceImage *sima, BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); } } } } else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { struct UvVertMap *vmap; - float limit[2]; uint efa_index; - uv_select_island_limit_default(sima, limit); - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - vmap = BM_uv_vert_map_create(em->bm, limit, false, false); + vmap = BM_uv_vert_map_create(em->bm, false, false); if (vmap == NULL) { return; } @@ -2390,20 +2708,17 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); } } } } else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { struct UvVertMap *vmap; - float limit[2]; uint efa_index; - uv_select_island_limit_default(sima, limit); - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - vmap = BM_uv_vert_map_create(em->bm, limit, false, false); + vmap = BM_uv_vert_map_create(em->bm, false, false); if (vmap == NULL) { return; } @@ -2424,7 +2739,7 @@ static void uv_select_flush_from_tag_loop(SpaceImage *sima, BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); } } } @@ -2451,7 +2766,6 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) MLoopUV *luv; rctf rectf; bool pinned; - float limit[2]; const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? (ts->selectmode == SCE_SELECT_FACE) : (ts->uv_selectmode == UV_SELECT_FACE)); @@ -2469,8 +2783,6 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) pinned = RNA_boolean_get(op->ptr, "pinned"); - uv_select_island_limit_default(sima, limit); - bool changed_multi = false; uint objects_len = 0; @@ -2532,8 +2844,8 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) if ((select != luv_select) || (select != luv_select_prev)) { if (BLI_rctf_isect_pt_v(&rectf, luv->uv) && BLI_rctf_isect_pt_v(&rectf, luv_prev->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l_prev, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG); } @@ -2564,14 +2876,14 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { /* UV_SYNC_SELECTION - can't do pinned selection */ if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); has_selected = true; } } else if (pinned) { if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); } } @@ -2582,8 +2894,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) .ob = obedit, .efa = efa, }; - uv_select_linked_multi( - scene, objects, objects_len, limit, &hit, true, !select, false, false); + uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false); } } @@ -2595,7 +2906,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op) if (changed || use_pre_deselect) { changed_multi = true; - uv_select_sync_flush(ts, em, select); + ED_uvedit_select_sync_flush(ts, em, select); uv_select_tag_update_for_object(depsgraph, ts, obedit); } } @@ -2678,7 +2989,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) MLoopUV *luv; int x, y, radius, width, height; float zoomx, zoomy; - float limit[2], offset[2], ellipse[2]; + float offset[2], ellipse[2]; const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? (ts->selectmode == SCE_SELECT_FACE) : @@ -2702,8 +3013,6 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) UI_view2d_region_to_view(®ion->v2d, x, y, &offset[0], &offset[1]); - uv_select_island_limit_default(sima, limit); - bool changed_multi = false; uint objects_len = 0; @@ -2765,8 +3074,8 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) if ((select != luv_select) || (select != luv_select_prev)) { if (uv_circle_select_is_edge_inside(luv->uv, luv_prev->uv, offset, ellipse)) { changed = true; - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l_prev, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG); } @@ -2794,7 +3103,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (uv_circle_select_is_point_inside(luv->uv, offset, ellipse)) { changed = true; - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); BM_elem_flag_enable(l->v, BM_ELEM_TAG); has_selected = true; } @@ -2805,8 +3114,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) .ob = obedit, .efa = efa, }; - uv_select_linked_multi( - scene, objects, objects_len, limit, &hit, true, !select, false, false); + uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false); } } @@ -2818,7 +3126,7 @@ static int uv_circle_select_exec(bContext *C, wmOperator *op) if (changed || use_pre_deselect) { changed_multi = true; - uv_select_sync_flush(ts, em, select); + ED_uvedit_select_sync_flush(ts, em, select); uv_select_tag_update_for_object(depsgraph, ts, obedit); } } @@ -2897,12 +3205,9 @@ static bool do_lasso_select_mesh_uv(bContext *C, BMFace *efa; BMLoop *l; - float limit[2]; bool changed_multi = false; rcti rect; - uv_select_island_limit_default(sima, limit); - BLI_lasso_boundbox(&rect, mcoords, mcoords_len); uint objects_len = 0; @@ -2962,8 +3267,8 @@ static bool do_lasso_select_mesh_uv(bContext *C, region, &rect, mcoords, mcoords_len, luv->uv) && do_lasso_select_mesh_uv_is_point_inside( region, &rect, mcoords, mcoords_len, luv_prev->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l_prev, select, false, cd_loop_uv_offset); changed = true; BM_elem_flag_enable(l->v, BM_ELEM_TAG); BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG); @@ -2992,7 +3297,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (do_lasso_select_mesh_uv_is_point_inside( region, &rect, mcoords, mcoords_len, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset); changed = true; BM_elem_flag_enable(l->v, BM_ELEM_TAG); has_selected = true; @@ -3004,8 +3309,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, .ob = obedit, .efa = efa, }; - uv_select_linked_multi( - scene, objects, objects_len, limit, &hit, true, !select, false, false); + uv_select_linked_multi(scene, objects, objects_len, &hit, true, !select, false, false); } } @@ -3017,7 +3321,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, if (changed || use_pre_deselect) { changed_multi = true; - uv_select_sync_flush(ts, em, select); + ED_uvedit_select_sync_flush(ts, em, select); uv_select_tag_update_for_object(depsgraph, ts, obedit); } } @@ -3099,7 +3403,7 @@ static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); if (luv->flag & MLOOPUV_PINNED) { - uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); + uvedit_uv_select_enable(scene, em, l, false, cd_loop_uv_offset); changed = true; } } @@ -3369,3 +3673,154 @@ void UV_OT_select_overlap(wmOperatorType *ot) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Selected Elements as Arrays (Vertex, Edge & Faces) + * + * These functions return single elements per connected vertex/edge. + * So an edge that has two connected edge loops only assigns one loop in the array. + * \{ */ + +BMFace **ED_uvedit_selected_faces(Scene *scene, BMesh *bm, int len_max, int *r_faces_len) +{ + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + CLAMP_MAX(len_max, bm->totface); + int faces_len = 0; + BMFace **faces = MEM_mallocN(sizeof(*faces) * len_max, __func__); + + BMIter iter; + BMFace *f; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (uvedit_face_visible_test(scene, f)) { + if (uvedit_face_select_test(scene, f, cd_loop_uv_offset)) { + faces[faces_len++] = f; + if (faces_len == len_max) { + goto finally; + } + } + } + } + +finally: + *r_faces_len = faces_len; + if (faces_len != len_max) { + faces = MEM_reallocN(faces, sizeof(*faces) * faces_len); + } + return faces; +} + +BMLoop **ED_uvedit_selected_edges(Scene *scene, BMesh *bm, int len_max, int *r_edges_len) +{ + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + CLAMP_MAX(len_max, bm->totloop); + int edges_len = 0; + BMLoop **edges = MEM_mallocN(sizeof(*edges) * len_max, __func__); + + BMIter iter; + BMFace *f; + + /* Clear tag. */ + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + BMIter liter; + BMLoop *l_iter; + BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { + BM_elem_flag_disable(l_iter, BM_ELEM_TAG); + } + } + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (uvedit_face_visible_test(scene, f)) { + BMIter liter; + BMLoop *l_iter; + BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { + if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) { + const MLoopUV *luv_curr = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); + const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l_iter->next, cd_loop_uv_offset); + if ((luv_curr->flag & MLOOPUV_VERTSEL) && (luv_next->flag & MLOOPUV_VERTSEL)) { + BM_elem_flag_enable(l_iter, BM_ELEM_TAG); + + edges[edges_len++] = l_iter; + if (edges_len == len_max) { + goto finally; + } + + /* Tag other connected loops so we don't consider them separate edges. */ + if (l_iter != l_iter->radial_next) { + BMLoop *l_radial_iter = l_iter->radial_next; + do { + if (BM_loop_uv_share_edge_check(l_iter, l_radial_iter, cd_loop_uv_offset)) { + BM_elem_flag_enable(l_radial_iter, BM_ELEM_TAG); + } + } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter); + } + } + } + } + } + } + +finally: + *r_edges_len = edges_len; + if (edges_len != len_max) { + edges = MEM_reallocN(edges, sizeof(*edges) * edges_len); + } + return edges; +} + +BMLoop **ED_uvedit_selected_verts(Scene *scene, BMesh *bm, int len_max, int *r_verts_len) +{ + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + CLAMP_MAX(len_max, bm->totloop); + int verts_len = 0; + BMLoop **verts = MEM_mallocN(sizeof(*verts) * len_max, __func__); + + BMIter iter; + BMFace *f; + + /* Clear tag. */ + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + BMIter liter; + BMLoop *l_iter; + BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { + BM_elem_flag_disable(l_iter, BM_ELEM_TAG); + } + } + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (uvedit_face_visible_test(scene, f)) { + BMIter liter; + BMLoop *l_iter; + BM_ITER_ELEM (l_iter, &liter, f, BM_LOOPS_OF_FACE) { + if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) { + const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); + if ((luv->flag & MLOOPUV_VERTSEL)) { + BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG); + + verts[verts_len++] = l_iter; + if (verts_len == len_max) { + goto finally; + } + + /* Tag other connected loops so we don't consider them separate vertices. */ + BMIter liter_disk; + BMLoop *l_disk_iter; + BM_ITER_ELEM (l_disk_iter, &liter_disk, l_iter->v, BM_LOOPS_OF_VERT) { + if (BM_loop_uv_share_vert_check(l_iter, l_disk_iter, cd_loop_uv_offset)) { + BM_elem_flag_enable(l_disk_iter, BM_ELEM_TAG); + } + } + } + } + } + } + } + +finally: + *r_verts_len = verts_len; + if (verts_len != len_max) { + verts = MEM_reallocN(verts, sizeof(*verts) * verts_len); + } + return verts; +} + +/** \} */ |